详解java中动态代理实现机制
代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
java各种动态代理实现的比较
接口
interface addinterface{ int add(int a, int b); } interface subinterface{ int sub(int a, int b); }
实现类
class arithmetic implements addinterface, subinterface{ @override public int sub(int a, int b) { return a-b; } @override public int add(int a, int b) { return a+b; } }
方式1: jdk自带的动态代理
1、实现方式
java在jdk1.3后引入的动态代理机制,使我们可以在运行期动态的创建代理类。使用动态代理实现aop需要有四个角色:被代理的类,被代理类的接口,织入器,和invocationhandler,而织入器使用接口反射机制生成一个代理类,然后在这个代理类中织入代码。被代理的类是aop里所说的目标,invocationhandler是切面,它包含了advice和pointcut。
2、vinvocationhandler接口的实现
class jdkdpqueryhandler implements invocationhandler{ private arithmetic real; public jdkdpqueryhandler(arithmetic real){ this.real = real; } @override public object invoke(object proxy, method method, object[] args) throws throwable { string methodname = method.getname(); system.out.println(method); system.out.println("the method: " + methodname + "开始, 参数: "+arrays.aslist(args)); object result = method.invoke(real, args); system.out.println("the method: "+methodname+"结束, 结果: " + result); return result; } }
3、创建代理类并且调用代理类
public class main{ private static int a = 4, b = 2; public static object createjdkproxy(arithmetic real){ object proxyarithmetic = proxy.newproxyinstance(real.getclass().getclassloader(), real.getclass().getinterfaces(), new jdkdpqueryhandler(real)); return proxyarithmetic; } public static void main(string[] args){ arithmetic real = new arithmetic(); object proxyarithmetic = createjdkproxy(real); ((addinterface)proxyarithmetic).add(a, b); ((subinterface)proxyarithmetic).sub(a, b); } }
方式2:动态字节码生成(cglib)
1、实现方式
enhancer和methodinterceptor。enhancer可以用来动态的生成一个类,这个类可以继承指定的一个类,实现指定的一些接口。同时,enhancer在生成一个类之前需要指定一个callback,当类方法调用时,方法的执行被分配给这个callback,methodinterceptor是一个使用比较多的继承自callback的接口,它只有一个方法声明。
2、接口invocationhandler(jdk中)和接口methodinterceptor(cglib中)对比
public interface methodinterceptor extends callback { public object intercept(object obj, java.lang.reflect.method method, object[] args,methodproxy proxy) throws throwable; } public interface invocationhandler { public object invoke(object proxy, method method, object[] args) throws throwable; }
从参数构成上,methodinterceptor的输入参数比invocationhandler多1个,其实前3个参数对象的含义与invocationhandler的含义是相同的。
第一个参数表示调用方法来自哪个对象;
第二个参数表示调用方法的method对象;
第三个参数表示此次调用的输入参数列表;
多出来的参数是methodproxy 类型的,它应该是cglib生成用来代替method对象的一个对象,使用methodproxy比调用jdk自身的method直接执行方法效率会有提升。
3、实现1
methodinterceptor接口的实现
class cglibdpqueryinterceptor implements methodinterceptor{ private arithmetic real; public cglibdpqueryinterceptor(arithmetic real){ this.real = real; } @override public object intercept(object target, method method, object[] args, methodproxy proxy) throws throwable { string methodname = method.getname(); system.out.println(method); system.out.println("the method: " + methodname + "开始, 参数: "+arrays.aslist(args)); //object result = method.invoke(real, args);//两种方式都是可以得 object result = proxy.invoke(real, args); system.out.println("the method: "+methodname+"结束, 结果: " + result); return result; } }
创建代理类并调用代理类
public class main{ private static int a = 4, b = 2; public static object createcglibproxy(arithmetic real){ enhancer enhancer = new enhancer(); enhancer.setcallback(new cglibdpqueryinterceptor(real)); enhancer.setinterfaces(real.getclass().getinterfaces()); return enhancer.create(); } public static void main(string[] args){ arithmetic real = new arithmetic(); object proxyarithmetic = createcglibproxy(real); ((addinterface)proxyarithmetic).add(a, b); ((subinterface)proxyarithmetic).sub(a, b); } }
注意了,methodproxy在对执行函数的时候,提供了2个方法
public object invoke (object obj, object[] args) throws throwable public object invokesuper(object obj, object[] args) throws throwable
其中,javadoc上说这个invoke()方法可以用于相同类中的其他对象的方法执行,也就是说这个方法中的obj需要传入相同一个类的另一个对象(上述方法中就是传入了arithmetic类的不同对象),否则会进入无限递归循环(测试之后还真是出现了*error)。仔细的想一想就会发现,public object intercept(object target, method method, object[] args, methodproxy proxy)中的target是实现的代理类对象,通过target调用add()方法时会触发intercept()方法被调用,如果在intercept()方法中再调用method.invoke(target, args),就相当于add()方法中又调用add()方法,导致无限的递归循环。但是如果执行method.invoke(real, args)则不会,因为real和target是同一个类不同对象,real是真实逻辑主题,target是真实主题real的代理。
下面一个例子来模拟一下:
interface solveinterface{ void solve(); } class real implements solveinterface{ public void solve(){ system.out.println("real solve!"); } } class target extends real{ private object obj; public void setobject(object obj){ this.obj = obj; } private void invoke(){ try { method method = solveinterface.class.getmethod("solve", new class[]{}); method.invoke(obj, new class[]{}); } catch (exception e) { e.printstacktrace(); } } public void solve(){ system.out.println("target solve!"); invoke(); } }
public class main{public static void main(string[] args) throws exception{ target target = new target(); target.setobject(new real());//正确 //target.setobject(target);//发生循环调用 target.solve(); } }
其实method的invoke()方法会根据obj的类型去调用对应的solve()方法,也就是多态性。
4、实现2
methodinterceptor接口的实现
class cglibdpqueryinterceptor implements methodinterceptor{ @override public object intercept(object target, method method, object[] args, methodproxy proxy) throws throwable { string methodname = method.getname(); system.out.println(method); system.out.println("the method: " + methodname + "开始, 参数: "+arrays.aslist(args)); // 打印类信息 :target.getclass();省略 object result = proxy.invokesuper(target, args); system.out.println("the method: "+methodname+"结束, 结果: " + result); return result; } }
创建代理类并调用代理类
public class main{ private static int a = 4, b = 2; public static object createcglibproxy(){ enhancer enhancer = new enhancer(); enhancer.setcallback(new cglibdpqueryinterceptor()); enhancer.setsuperclass(arithmetic.class); return enhancer.create(); } public static void main(string[] args){ arithmetic real = new arithmetic(); object proxyarithmetic = createcglibproxy(); ((addinterface)proxyarithmetic).add(a, b); ((subinterface)proxyarithmetic).sub(a, b); } }
注意了,实现2中enhancer 没有设置接口,因为设置了superclass了(也就是代理类的父类是arithmetic),我们的代理类会继承它,而arithmetic已经实现了我们的接口。为了证明这一点,可以在methodinterceptor的 intercept方法中打印 target.getclass()的类信息,你会发现cglib的两种方式代理类的父类是不同的。如下:
实现1:
public class com.test.arithmetic$$enhancerbycglib$$4fa786eb extends java.lang.object
实现2:
public class com.test.arithmetic$$enhancerbycglib$$4fa786eb extends com.test.arithmetic
方式3:javassist生成动态代理(代理工厂创建 或者 动态代码创建)
javassist是一个编辑字节码的框架,可以让你很简单地操作字节码。它可以在运行期定义或修改class。使用javassist实现aop的原理是在字节码加载前直接修改需要切入的方法。这比使用cglib实现aop更加高效,并且没太多限制,实现原理如下图:
实现1:
接口的实现
class javassistdpqueryhandler implements methodhandler{ @override public object invoke(object target, method method, method proxy, object[] args) throws throwable { string methodname = method.getname(); system.out.println(method); system.out.println("the method: " + methodname + "开始, 参数: "+arrays.aslist(args)); object result = proxy.invoke(target, args); system.out.println("the method: "+methodname+"结束, 结果: " + result); return result; } }
创建代理类并调用代理类
public class main{ private static int a = 4, b = 2; public static object createjavassistproxy() throws exception{ proxyfactory factory = new proxyfactory(); factory.setsuperclass(arithmetic.class); factory.sethandler(new javassistdpqueryhandler()); return factory.createclass().newinstance(); } public static void main(string[] args) throws exception{ arithmetic real = new arithmetic(); object proxyarithmetic = createjavassistproxy(); ((addinterface)proxyarithmetic).add(a, b); ((subinterface)proxyarithmetic).sub(a, b); } }
注意:methodhandler接口中invoke方法的定义,如下:
public object invoke(object target, method method, method proxy, object[] args)
method代表调用方法的method对象,proxy是代理类产生并代替method的对象,否则用method.invoke(target, args)会产生无限循环调用。
实现2:
javassist使用动态java代码常见代理过程和前文的方法略有不同。javassist内部可以通过动态java代码,生成字节码。这种方式创建的动态代理可以非常灵活,甚至可以在运行时产生业务逻辑。
//自定义拦截器接口 interface interceptorhandler { /** * 调用动态代理对象的方法将反射本方法,可在本方法实现中添加类似aop的事前事后操作,只有在本方法体中加入如下代码 * 被代理的方法才会被执行,返回值将返回给代理最后返回给程序 * @param obj object 被代理的对象 * @param method method 被代理对象的方法 * @param args object[] 被代理对象的方法的参数 * @return object 被代理对象的方法执行后的返回值 * @throws throwable */ public object invoke(object obj, method method, object[] args) throws throwable; } //拦截器的实现 class interceptorhandlerimpl implements interceptorhandler{ @override public object invoke(object obj, method method, object[] args) throws throwable { string methodname = method.getname(); system.out.println(method); system.out.println("the method: " + methodname + "开始, 参数: "+arrays.aslist(args)); object result = method.invoke(obj, args); system.out.println("the method: "+methodname+"结束, 结果: " + result); return result; } } class myproxyimpl { /** 动态代理类的类名后缀 */ private final static string proxy_class_name_suffix = "$myproxy_"; /** 拦截器接口 */ private final static string interceptor_handler_interface = "com.test.interceptorhandler"; /** 动态代理类的类名索引,防止类名重复 */ private static int proxyclassindex = 1; /** * 暴露给用户的动态代理接口,返回某个接口的动态代理对象,注意本代理实现需和com.cuishen.myaop.interceptorhandler拦截器配合 * 使用,即用户要使用本动态代理,需先实现com.cuishen.myaop.interceptorhandler拦截器接口 * @param interfaceclassname string 要动态代理的接口类名, e.g test.studentinfoservice * @param classtoproxy string 要动态代理的接口的实现类的类名, e.g test.studentinfoserviceimpl * @param interceptorhandlerimplclassname string 用户提供的拦截器接口的实现类的类名 * @return object 返回某个接口的动态代理对象 * @throws instantiationexception * @throws illegalaccessexception * @throws notfoundexception * @throws cannotcompileexception * @throws classnotfoundexception * @see com.cuishen.myaop.interceptorhandler */ public static object newproxyinstance(string interfaceclassname, string classtoproxy, string interceptorhandlerimplclassname) throws instantiationexception, illegalaccessexception, notfoundexception, cannotcompileexception, classnotfoundexception { class interfaceclass = class.forname(interfaceclassname); class interceptorhandlerimplclass = class.forname(interceptorhandlerimplclassname); return dynamicimplementsinterface(classtoproxy, interfaceclass, interceptorhandlerimplclass); } /** * 动态实现要代理的接口 * @param classtoproxy string 要动态代理的接口的实现类的类名, e.g test.studentinfoserviceimpl * @param interfaceclass class 要动态代理的接口类, e.g test.studentinfoservice * @param interceptorhandlerimplclass class 用户提供的拦截器接口的实现类 * @return object 返回某个接口的动态代理对象 * @throws notfoundexception * @throws cannotcompileexception * @throws instantiationexception * @throws illegalaccessexception */ private static object dynamicimplementsinterface(string classtoproxy, class interfaceclass, class interceptorhandlerimplclass) throws notfoundexception, cannotcompileexception, instantiationexception, illegalaccessexception { classpool cp = classpool.getdefault(); string interfacename = interfaceclass.getname(); //动态指定代理类的类名 string proxyclassname = interfacename + proxy_class_name_suffix + proxyclassindex++; //要实现的接口的包名+接口名 string interfacenamepath = interfacename; ctclass ctinterface = cp.getctclass(interfacenamepath); ctclass cc = cp.makeclass(proxyclassname); cc.addinterface(ctinterface); method [] methods = interfaceclass.getmethods(); for(int i = 0; i < methods.length; i++) { method method = methods[i]; dynamicimplementsmethodsfrominterface(classtoproxy, cc, method, interceptorhandlerimplclass, i); } return (object)cc.toclass().newinstance(); } /** * 动态实现接口里的方法 * @param classtoproxy string 要动态代理的接口的实现类的类名, e.g test.studentinfoserviceimpl * @param implementer ctclass 动态代理类的包装 * @param methodtoimpl method 动态代理类里面要实现的接口方法的包装 * @param interceptorclass class 用户提供的拦截器实现类 * @param methodindex int 要实现的方法的索引 * @throws cannotcompileexception */ private static void dynamicimplementsmethodsfrominterface(string classtoproxy, ctclass implementer, method methodtoimpl, class interceptorclass, int methodindex) throws cannotcompileexception { string methodcode = generatemethodcode(classtoproxy, methodtoimpl, interceptorclass, methodindex); ctmethod cm = ctnewmethod.make(methodcode, implementer); implementer.addmethod(cm); } /** * 动态组装方法体,当然代理里面的方法实现并不是简单的方法拷贝,而是反射调用了拦截器里的invoke方法,并将接收到的参数进行传递 * @param classtoproxy string 要动态代理的接口的实现类的类名, e.g test.studentinfoserviceimpl * @param methodtoimpl method 动态代理类里面要实现的接口方法的包装 * @param interceptorclass class 用户提供的拦截器实现类 * @param methodindex int 要实现的方法的索引 * @return string 动态组装的方法的字符串 */ private static string generatemethodcode(string classtoproxy, method methodtoimpl, class interceptorclass, int methodindex) { string methodname = methodtoimpl.getname(); string methodreturntype = methodtoimpl.getreturntype().getname(); class[] parameters = methodtoimpl.getparametertypes(); class[] exceptiontypes = methodtoimpl.getexceptiontypes(); stringbuffer exceptionbuffer = new stringbuffer(); //组装方法的exception声明 if(exceptiontypes.length > 0) exceptionbuffer.append(" throws "); for(int i = 0; i < exceptiontypes.length; i++) { if(i != exceptiontypes.length - 1) exceptionbuffer.append(exceptiontypes[i].getname()).append(","); else exceptionbuffer.append(exceptiontypes[i].getname()); } stringbuffer parameterbuffer = new stringbuffer(); //组装方法的参数列表 for(int i = 0; i < parameters.length; i++) { class parameter = parameters[i]; string parametertype = parameter.getname(); //动态指定方法参数的变量名 string refname = "a" + i; if(i != parameters.length - 1) parameterbuffer.append(parametertype).append(" " + refname).append(","); else parameterbuffer.append(parametertype).append(" " + refname); } stringbuffer methoddeclare = new stringbuffer(); //方法声明,由于是实现接口的方法,所以是public methoddeclare.append("public ").append(methodreturntype).append(" ").append(methodname).append("(").append(parameterbuffer).append(")").append(exceptionbuffer).append(" {\n"); string interceptorimplname = interceptorclass.getname(); //方法体 methoddeclare.append(interceptor_handler_interface).append(" interceptor = new ").append(interceptorimplname).append("();\n"); //反射调用用户的拦截器接口 methoddeclare.append("object returnobj = interceptor.invoke(class.forname(\"" + classtoproxy + "\").newinstance(), class.forname(\"" + classtoproxy + "\").getmethods()[" + methodindex + "], "); //传递方法里的参数 if(parameters.length > 0) methoddeclare.append("new object[]{"); for(int i = 0; i < parameters.length; i++) { //($w) converts from a primitive type to the corresponding wrapper type: e.g. //integer i = ($w)5; if(i != parameters.length - 1) methoddeclare.append("($w)a" + i + ","); else methoddeclare.append("($w)a" + i); } if(parameters.length > 0) methoddeclare.append("});\n"); else methoddeclare.append("null);\n"); //对调用拦截器的返回值进行包装 if(methodtoimpl.getreturntype().isprimitive()) { if(methodtoimpl.getreturntype().equals(boolean.type)) methoddeclare.append("return ((boolean)returnobj).booleanvalue();\n"); else if(methodtoimpl.getreturntype().equals(integer.type)) methoddeclare.append("return ((integer)returnobj).intvalue();\n"); else if(methodtoimpl.getreturntype().equals(long.type)) methoddeclare.append("return ((long)returnobj).longvalue();\n"); else if(methodtoimpl.getreturntype().equals(float.type)) methoddeclare.append("return ((float)returnobj).floatvalue();\n"); else if(methodtoimpl.getreturntype().equals(double.type)) methoddeclare.append("return ((double)returnobj).doublevalue();\n"); else if(methodtoimpl.getreturntype().equals(character.type)) methoddeclare.append("return ((character)returnobj).charvalue();\n"); else if(methodtoimpl.getreturntype().equals(byte.type)) methoddeclare.append("return ((byte)returnobj).bytevalue();\n"); else if(methodtoimpl.getreturntype().equals(short.type)) methoddeclare.append("return ((short)returnobj).shortvalue();\n"); } else { methoddeclare.append("return (" + methodreturntype + ")returnobj;\n"); } methoddeclare.append("}"); system.out.println(methoddeclare.tostring()); return methoddeclare.tostring(); } } public class main{ public static void main(string[] args) throws exception{ //分别对应 代理类要实现的接口类名, 需要代理类的类名, 用户自定义拦截器实现类的类名 object proxyarithmetic = myproxyimpl.newproxyinstance("com.test.arithmeticinterface", "com.test.arithmetic", "com.test.interceptorhandlerimpl"); ((arithmeticinterface)proxyarithmetic).add(a, b); ((arithmeticinterface)proxyarithmetic).sub(a, b); } }
打印一下动态实现接口的代码如下:
public int add(int a0,int a1) { com.test.interceptorhandler interceptor = new com.test.interceptorhandlerimpl(); object returnobj = interceptor.invoke(class.forname("com.test.arithmetic").newinstance(), class.forname("com.test.arithmetic").getmethods()[0], new object[]{($w)a0,($w)a1}); return ((integer)returnobj).intvalue(); } public int sub(int a0,int a1) { com.test.interceptorhandler interceptor = new com.test.interceptorhandlerimpl(); object returnobj = interceptor.invoke(class.forname("com.test.arithmetic").newinstance(), class.forname("com.test.arithmetic").getmethods()[1], new object[]{($w)a0,($w)a1}); return ((integer)returnobj).intvalue(); }
以上就是关于java中动态代理实现机制的详细介绍,希望对大家的学习有所帮助。
上一篇: WebService教程详解(一)
下一篇: Java 顺序表-两个有序表的合并