JDKProxy生成对象的步骤如下:
1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2、JDKProxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接
口。
3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体
现)。
4、编译新生成的Java代码.class。
5、再重新加载到JVM中运行。
以上这个过程就叫字节码重组。JDK中有一个规范,在ClassPath下只要是$开头的class
文件一般都是自动生成的。
package com.sp.demo.proxy;/*** @author : lssffy* @Description :* @date : 2024/3/8 10:25*/
public interface OneDay {void eat();void play();void sleep();
}
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;
}
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);}
}
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);}@Overrideprotected 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;}
}
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);}@Overridepublic 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");}}
package com.sp.demo.proxy;/*** @author : lssffy* @Description :* @date : 2024/3/8 10:26*/
public class LaoWang implements OneDay{@Overridepublic void eat() {System.out.println("准备碗筷");System.out.println("开始吃饭");System.out.println("收拾碗筷");}@Overridepublic void play() {System.out.println("打开电脑");System.out.println("登录账号");System.out.println("开始玩");}@Overridepublic void sleep() {System.out.println("开始洗澡");System.out.println("躺倒床上");System.out.println("开始睡觉");}
}
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();}}
}