动态代理类的实现和解析
静态代理类:
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.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 }
/***
*这个类是用来制定你的代理对象,在调用方法时需要进行哪些前置处理和后置处理
*
*/
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