JDKProxy生成对象的步骤如下:
1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2、JDKProxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接
口。
3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体
现)。
4、编译新生成的Java代码.class。
5、再重新加载到JVM中运行。
以上这个过程就叫字节码重组。JDK中有一个规范,在ClassPath下只要是$开头的class
文件一般都是自动生成的。
java
package com.sp.demo.proxy;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/8 10:25
*/
public interface OneDay {
void eat();
void play();
void sleep();
}
java
package com.sp.base.proxyhandler;
import java.lang.reflect.Method;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/21 14:41
*/
public interface SInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
java
package com.sp.base.proxyhandler;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/21 14:42
*/
public class SProxy {
private static final String ln = "\r\n";
public static Object newProxyInstance(SClassLoader classLoader,Class<?> [] interfaces,SInvocationHandler h){
try {
//动态生成源代码。java文件
String src = generateSrc(interfaces);
//Java文件输出磁盘
String filePath = SProxy.class.getResource("").getPath();
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//把生成的。java文件编译成。class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable);
task.call();
manager.close();
//把编译生成的。class文件加载到jvm中
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(SInvocationHandler.class);
f.delete();
//返回字节码重组以后的新的代理对象
return c.newInstance(h);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?>[] interfaces) {
StringBuffer sb= new StringBuffer();
sb.append("package com.sp.base.proxyhandler;" +ln);
sb.append("import com.sp.demo.proxy.OneDay;" + ln);
sb.append("import java.lang.reflect.*;" +ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName()+ "{"+ln);
sb.append("SInvocationHandler h;"+ ln);
sb.append("public $Proxy0(SInvocationHandler h) { "+ln);
sb.append("this.h = h;");
sb.append("}"+ ln);
for(Method m : interfaces[0].getMethods()){
Class<?>[] params= m.getParameterTypes();
StringBuffer paramNames=new StringBuffer();
StringBuffer paramValues=new StringBuffer();
StringBuffer paramClasses= new StringBuffer();
for(int i= 0;i < params.length; i++){
Class clazz=params[i];
String type=clazz.getName();
String paramName= toLowerFirstCase(clazz.getSimpleName());
paramNames.append(type + "" + paramName);
paramValues.append(paramName);
paramClasses.append(clazz.getName() + ".class");
if(i > 0&& i< params.length-1){
paramNames.append(",");
paramClasses.append(",");
paramValues.append(",");
}
}
sb.append("public " +m.getReturnType().getName() + " " + m.getName() +"(" +
paramNames.toString() + "){"+ ln);
sb.append("try{"+ ln);
sb.append("Method m="+interfaces[0].getName()+".class.getMethod(\""
+m.getName()+ "\",new Class[]{"+paramClasses.toString() + "});" +ln);
sb.append((hasReturnValue(m.getReturnType()) ?"return " : "") +
getCaseCode("this.h.invoke(this,m,new Object[]{"+paramValues+"})",m.getReturnType())+";"+ln);
sb.append("}catch(Error _ex){ }");
sb.append("catch(Throwable e){"+ ln);
sb.append("throw new UndeclaredThrowableException(e);" +ln);
sb.append("}");
sb.append(getReturnEmptyCode(m.getReturnType()));
sb.append("}");
}
sb.append("}"+ ln);
return sb.toString();
}
private static Map<Class,Class> mappings = new HashMap<Class,Class>();
static {
mappings.put(int.class,Integer.class);
}
private static String getReturnEmptyCode(Class<?> returnType) {
if(mappings.containsKey(returnType)){
return "return 0;";
}else if(returnType ==void.class){
return "";
}else{
return"return null;";
}
}
private static String getCaseCode(String s, Class<?> returnType) {
if(mappings.containsKey(returnType)){
return "(("+mappings.get(returnType).getName() + ")"+ s+ ")."+
returnType.getSimpleName() +"Value()";
}
return s;
}
private static boolean hasReturnValue(Class<?> returnType) {
return returnType != void.class;
}
private static String toLowerFirstCase(String simpleName) {
char [] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
java
package com.sp.base.proxyhandler;
import java.io.*;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/21 14:44
*/
public class SClassLoader extends ClassLoader{
private File classPathFile;
public SClassLoader(){
String classPath = SClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = SClassLoader.class.getPackage().getName() + "." + name;
if (classPathFile != null) {
File classFile = new File(classPathFile,name.replace("\\", "/") + ".class");
if(classFile.exists()) {
FileInputStream fis = null;
ByteArrayOutputStream out = null;
try {
fis = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while((len=fis.read(buff))!=-1){
out.write(buff,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null!=fis){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null!=out){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
java
package com.sp.demo.proxy;
import com.sp.base.proxyhandler.SClassLoader;
import com.sp.base.proxyhandler.SInvocationHandler;
import com.sp.base.proxyhandler.SProxy;
import java.lang.reflect.Method;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/21 14:15
*/
public class InvocationHandlerJDK implements SInvocationHandler {
private Object target;
public Object getInstance(Object target) {
this.target = target;
Class<?> targetClass = target.getClass();
return SProxy.newProxyInstance(new SClassLoader(),targetClass.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(this.target, args);
after();
return obj;
}
private void before(){
System.out.println("start runtime invocation");
}
private void after(){
System.out.println("end runtime invocation");
}
}
java
package com.sp.demo.proxy;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/8 10:26
*/
public class LaoWang implements OneDay{
@Override
public void eat() {
System.out.println("准备碗筷");
System.out.println("开始吃饭");
System.out.println("收拾碗筷");
}
@Override
public void play() {
System.out.println("打开电脑");
System.out.println("登录账号");
System.out.println("开始玩");
}
@Override
public void sleep() {
System.out.println("开始洗澡");
System.out.println("躺倒床上");
System.out.println("开始睡觉");
}
}
java
package com.sp.demo.proxy;
/**
* @author : lssffy
* @Description :
* @date : 2024/3/8 10:33
*/
public class Test {
public static void main(String[] args) {
try {
OneDay oneDay1 = (OneDay) new InvocationHandlerJDK().getInstance(new LaoWang());
oneDay1.play();
oneDay1.eat();
oneDay1.sleep();
}catch(Exception e){
e.printStackTrace();
}
}
}