转载

java中动态代理实现机制

第一个参数表示调用方法来自哪个对象;

第二个参数表示调用方法的Method对象;

第三个参数表示此次调用的输入参数列表;

多出来的参数是MethodProxy 类型的,它应该是cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升。

实现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类的不同对象 ,否则会进入无限递归循环(测试之后还真是出现了 StackOverflowError )。仔细的想一想就会发现,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()方法,也就是多态性。

实现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的两种方式代理类的父类是不同的。如下:

(如果需要打印类信息代码,请参考: http://www.cnblogs.com/hujunzheng/p/5132943.html )

实现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更加高效,并且没太多限制,实现原理如下图:

java中动态代理实现机制

java中动态代理实现机制

实现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:

(来自:http://cuishen.iteye.com/blog/421464),代码注释很详细,仔细研究一下就会懂了!

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(); } 
原文  http://www.cnblogs.com/hujunzheng/p/5134478.html
正文到此结束
Loading...