由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了
动态代理类 :
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
话不多说看代码。。 。
package proxyBase; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class MyProxy { static Class<?>[] parameterTypes = { InvocationHandler.class }; protected InvocationHandler h; protected MyProxy(InvocationHandler h) { this.h = h; } public static Object newInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) { // :产生一个代理类的字节码对象 Class<?> c1 = null; try { // :通过getClass0方法可以得到一个代理类的字节码对象 c1 = getClass0(loader, interfaces); } catch (MalformedURLException e1) { e1.printStackTrace(); } Constructor<?> constructor = null; try { /** * 调用子类$Proxy0(InvocationHandler h)构造函数,由于继承了MyProxy类, * 所以又会继续调用父类的MyProxy(InvocationHandler h)构造函数给 h初始化一个值; */ constructor = c1.getDeclaredConstructor(InvocationHandler.class); /** * 返回一个生成的代理类对象,并将InvocationHandler 的实现类对象传入进去。从而达到给h赋值的目的 * */ return constructor.newInstance(h); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } return null; } // :用来生成一个代理类对象 private static Class<?> getClass0(ClassLoader loader, Class<?>[] interfaces) throws MalformedURLException { Class<?> forName = null; try { GennerateClass.generate(interfaces[0]); // :动态编译 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMgr.getJavaFileObjects(System.getProperty("user.dir") + "/src/" + interfaces[0].getPackage().getName() + "/" + interfaces[0].getSimpleName() + "$proxy0.java"); // :"-d", System.getProperty("user.dir")+"/bin/" 用来指定java文件编译后存放的地方 Iterable<String> options = Arrays.asList("-d", System.getProperty("user.dir") + "/bin/"); CompilationTask t = compiler.getTask(null, fileMgr, null, options, null, units); t.call(); try { fileMgr.close(); } catch (IOException e) { e.printStackTrace(); } // :得到代码自动生成代理类的实例对象 forName = Class.forName(interfaces[0].getName() + "$proxy0"); } catch (ClassNotFoundException e) { e.printStackTrace(); } return forName; } }
这个GennerateClass类是用来生成代理类的Java文件的,是通过字符串拼接而成,仅供参考.
1 package proxyBase; 2 3 import java.io.BufferedWriter; 4 import java.io.File; 5 import java.io.FileWriter; 6 import java.io.IOException; 7 import java.lang.reflect.Method; 8 9 public class GennerateClass { 10 public static void generate(Class<?> clazz) { 11 String methodStr = ""; //:方法字符串的拼接 12 String classStr = ""; //:类名的拼接 13 String packageStr = ""; //:导入包名的拼接 14 String classParamStr = ""; //: 15 String staticCodeStr = "static {/ntry {";//:静态代码块的拼接 16 String member_var = ""; //:成员变量的拼接 17 String package1 = clazz.getPackage().getName(); 18 String simpleName = clazz.getSimpleName(); //:获得简单类名 19 String className = clazz.getName(); //:获得权限定类名 20 //:构造函数的拼接 21 String counstructStr = "public " + simpleName + "$proxy0(InvocationHandler h) {/r/n" + " super(h);/r" 22 + " }/n"; 23 // :导包 24 packageStr = "package " + package1 + ";/n" 25 + "import proxyBase.MyProxy;/r import java.lang.reflect.InvocationHandler;/n" 26 + "import java.lang.reflect.Method;/n"; 27 // :构建类名 28 classStr += "public class " + simpleName + "$proxy0 extends MyProxy implements " + simpleName + "{/n" + ""; 29 // :构建代理类的方法 30 Method[] methods = clazz.getMethods(); 31 int i = 0; 32 for (Method method : methods) { 33 String paramStr = "";//:参数变量拼接 34 int paramCount = 0; //:参数个数计数用来生成参数变量 35 i += 1; 36 member_var += "private static Method m" + i + ";/n";//成员变量的拼接 37 String tempStr = ""; //:参数列表 38 String methodName = method.getName();// 方法名 39 Class<?>[] parameterTypes = method.getParameterTypes();// 参数列表的class类型 40 Class<?> returnType = method.getReturnType();// 返回值类型 41 methodStr += "public final " + returnType.getName() + " " + methodName + "("; 42 // :参数列表名字符串 43 for (Class<?> type : parameterTypes) { 44 paramCount += 1; 45 tempStr += "," + type.getName() + " param" + paramCount; 46 paramStr += ",param" + paramCount; 47 classParamStr += "," + type.getName() + ".class"; 48 } 49 //: 50 if (!paramStr.isEmpty()) { 51 paramStr = paramStr.substring(1); 52 } 53 if (!tempStr.isEmpty()) { 54 tempStr = tempStr.substring(1); 55 } 56 if (classParamStr.isEmpty()) { 57 classParamStr = "null"; 58 } else { 59 classParamStr = classParamStr.substring(1); 60 } 61 //:判断返回值是否时void,是则不需要return 62 //方法的拼接 63 if (returnType.getName().equals("void")) { 64 methodStr = methodStr + tempStr + ")/n{/n" + "/ttry{/n/tthis.h.invoke(this,m" + i + ",new Object[]{" 65 + paramStr + "});" + "} catch (Throwable e) {/r/n" + " e.printStackTrace();/r/n" 66 + " }/n}/n"; 67 } else { 68 methodStr = methodStr + tempStr + ")/n{/nObject result=null;/n/ttry{/n/tresult=this.h.invoke(this,m" + i 69 + ",new Object[]{" + paramStr + "});" + "} catch (Throwable e) {/r/n" 70 + " e.printStackTrace();/r/n" + "}/nreturn (" + returnType.getName() + ")result;}/n"; 71 } 72 // :构建静态代码块 73 if (!classParamStr.equals("null")) { 74 staticCodeStr += "m" + i + " = Class.forName(/"" + className + "/").getMethod(/"" + methodName 75 + "/",new Class<?>[]{" + classParamStr + "});"; 76 } else { 77 staticCodeStr += "m" + i + " = Class.forName(/"" + className + "/").getMethod(/"" + methodName + "/");"; 78 } 79 classParamStr = ""; 80 } 81 //静态代码块的拼接 82 staticCodeStr += "} catch (NoSuchMethodException e) {/r/n" + " e.printStackTrace();/r/n" 83 + " } catch (SecurityException e) {/r/n" + " e.printStackTrace();/r/n" 84 + " } catch (ClassNotFoundException e) {/r/n" + " e.printStackTrace();/r/n" + " }}"; 85 //总和成Java文件的内容 86 packageStr = packageStr + classStr + member_var + counstructStr + methodStr + staticCodeStr + "/n}"; 87 //通过流写入成文件 88 FileWriter fout = null; 89 try { 90 fout = new FileWriter(new File("src/" + package1 + "/" + simpleName + "$proxy0.java")); 91 } catch (IOException e) { 92 93 e.printStackTrace(); 94 } 95 BufferedWriter out = new BufferedWriter(fout); 96 try { 97 out.write(packageStr); 98 } catch (IOException e) { 99 e.printStackTrace(); 100 } 101 try { 102 out.close(); 103 fout.close(); 104 } catch (IOException e) { 105 e.printStackTrace(); 106 } 107 } 108 } View Code
/*** *这个类是用来制定你的代理对象,在调用方法时需要进行哪些前置处理和后置处理 * */ 1 package proxyBase; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class Hadler<T> implements InvocationHandler { 7 private T target; 8 //通过new Hadler将被代理的那个对象传入, 9 public Hadler(T target) { 10 super(); 11 this.target = target; 12 } 13 private void before() { 14 System.out.println("先吃饭"); 15 } 16 private void after() { 17 System.out.println("再睡觉"); 18 } 19 //这里根据自己的逻辑来制定相应的invoke方法,视情况而定,此处的写法只是来简单测试代理对象。 20 @Override 21 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 22 before(); 23 Object invoke = method.invoke(target,args); 24 after(); 25 return invoke; 26 } 27 }
这里时生成后的代理类文件Person$proxy0.java
package proxyBase; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class Hadler<T> implements InvocationHandler { private T target; //通过new Hadler将被代理的那个对象传入, public Hadler(T target) { super(); this.target = target; } private void before() { System.out.println("先吃饭"); } private void after() { System.out.println("再睡觉"); } //这里根据自己的逻辑来制定相应的invoke方法,视情况而定,此处的写法只是来简单测试代理对象。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object invoke = method.invoke(target,args); after(); return invoke; } }
接下来是写一个接口,jdk中的动态代理是针对接口代理的,而cglib是针对类进行代理的,这个接口将会被代理,分别写了四个方法来测试,无参,一参,两参,和一个有返回值
的方法,都是用来测试GennerateClass类生成的是否正确,(目前只测试了这几种,如果大神发现有误,还望联系斧正)
1 package proxy; 2 3 4 public interface Person { 5 void study2(); 6 void study2(int a); 7 void study3(int b ,String a); 8 int returnInt(int a); 9 }
接下来写一个Person的实现类,然后通过代理类来代理这个实现类对象,进行一些前置处理和后置处理。
1 package proxy; 2 3 public class Student implements Person { 4 public void study2() { 5 System.out.println("正在考试中"); 6 } 7 8 @Override 9 public void study2(int a) { 10 System.out.println(a); 11 } 12 13 @Override 14 public void study3(int b, String a) { 15 System.out.println(a+b); 16 } 17 18 @Override 19 public int returnInt(int a) { 20 21 return a; 22 } 23 }
最后就是测试和使用所写的代理类了
第一步,创建一个Person类型的对象student,
第二步,创建一个InvocationHandler的实现类对象,并将student传入进去,这个student会将生成实现类中的成员变量target进行赋值初始化。
第三步,调用MyProxy中的newInstance方法来获得代理类对象(注意:newInstance 中的参数要是实现类的类类型来获得他的实现Interface接口的类类型,即Person,生成代理类的Java文件就是依据该接口生成的)
第四步, 测试生成的代理类对象,结果如下,通过原生student和代理类对象stu调用相同方法进行对比
1 public static void main(String[] args) { 2 Person student = new Student(); 3 4 InvocationHandler h = new Hadler<Person>(student); 5 Person stu = (Person) MyProxy.newInstance(Person.class.getClassLoader(), Student.class.getInterfaces(), h); 6 stu.study2(); 7 System.out.println("-------"); 8 student.study2(); 9 stu.study2(4); 10 stu.study3(4, "A"); 11 int a = stu.returnInt(2015); 12 System.out.println(a); 13 }
运行结果:
先吃饭 正在考试中 再睡觉 ------- 正在考试中 先吃饭 4 再睡觉 先吃饭 A4 再睡觉 先吃饭 再睡觉 2015