Spring-AOP-2:CGLIB的动态代理

这篇文章紧接着上一篇静态代理和动态代理来说

前言:

到现在呢,老是讲动态代理,有的人都晕了,会说你这代理中用到的类怎么没有一个是与spring相关的呢,所以,我要说明的事,虽然现在讲的都是最普通的动态代理,但实质上就是将AOP的内部实现原理,Spring AOP之所以这么强大是因为它底层都是用动态代理来实现的,为了说明这一点,得贴出点源码来

1.如果是有接口声明的类进行AOP,spring调用的是java.lang.reflection.Proxy类来做处理 
在spring的资源包中,找到org.springframework.aop.framework.JdkDynamicAopProxy这个类,在资源包的位置为spring-framework-2.5.6\src\org\springframework\aop\framework\JdkDynamicAopProxy.java,看看其中重要的代码片段

 

Java代码   收藏代码
  1. <span style="font-size: medium;"public Object getProxy(ClassLoader classLoader) {     
  2.         if (logger.isDebugEnabled()) {     
  3.             Class targetClass = this.advised.getTargetSource().getTargetClass();     
  4.             logger.debug("Creating JDK dynamic proxy" +     
  5.                     (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));     
  6.         }     
  7.         Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);     
  8.         return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);     
  9.     }  </span>  

 

再看org.springframework.aop.framework.ReflectiveMethodInvocation中的代码片段

 

Java代码   收藏代码
  1. <span style="font-size: medium;">public Object proceed() throws Throwable {     
  2.         //  We start with an index of -1 and increment early.     
  3.         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {     
  4.             return invokeJoinpoint();     
  5.         }     
  6.     
  7.         Object interceptorOrInterceptionAdvice =     
  8.             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);     
  9.         if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {     
  10.             // Evaluate dynamic method matcher here: static part will already have     
  11.             // been evaluated and found to match.     
  12.             InterceptorAndDynamicMethodMatcher dm =     
  13.                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;     
  14.             if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {     
  15.                 return dm.interceptor.invoke(this);     
  16.             }     
  17.             else {     
  18.                 // Dynamic matching failed.     
  19.                 // Skip this interceptor and invoke the next in the chain.     
  20.                 return proceed();     
  21.             }     
  22.         }     
  23.         else {     
  24.             // It's an interceptor, so we just invoke it: The pointcut will have     
  25.             // been evaluated statically before this object was constructed.     
  26.             return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);     
  27.         }     
  28.     }    
  29. </span>  

 

 

2.如果是没有接口声明的类呢?SPRING通过CGLIB包和内部类来实现 

Java代码   收藏代码
  1. <span style="font-size: medium;">private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable {  
  2.   
  3.         private final Object target;  
  4.   
  5.         public StaticUnadvisedInterceptor(Object target) {  
  6.             this.target = target;  
  7.         }  
  8.   
  9.         public Object intercept(Object proxy, Method method, Object[] args,  
  10.                 MethodProxy methodProxy) throws Throwable {  
  11.   
  12.             Object retVal = methodProxy.invoke(target, args);  
  13.             return massageReturnTypeIfNecessary(proxy, target, retVal);  
  14.         }  
  15.     }  
  16.   
  17.   
  18.     /** 
  19.      * Method interceptor used for static targets with no advice chain, when the 
  20.      * proxy is to be exposed. 
  21.      */  
  22.     private static class StaticUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {  
  23.   
  24.         private final Object target;  
  25.   
  26.         public StaticUnadvisedExposedInterceptor(Object target) {  
  27.             this.target = target;  
  28.         }  
  29.   
  30.         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  31.             Object oldProxy = null;  
  32.             try {  
  33.                 oldProxy = AopContext.setCurrentProxy(proxy);  
  34.                 Object retVal = methodProxy.invoke(target, args);  
  35.                 return massageReturnTypeIfNecessary(proxy, target, retVal);  
  36.             }  
  37.             finally {  
  38.                 AopContext.setCurrentProxy(oldProxy);  
  39.             }  
  40.         }  
  41.     }  
  42.   
  43.   
  44.     /** 
  45.      * Interceptor used to invoke a dynamic target without creating a method 
  46.      * invocation or evaluating an advice chain. (We know there was no advice 
  47.      * for this method.) 
  48.      */  
  49.     private class DynamicUnadvisedInterceptor implements MethodInterceptor, Serializable {  
  50.   
  51.         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  52.             Object target = advised.getTargetSource().getTarget();  
  53.             try {  
  54.                 Object retVal = methodProxy.invoke(target, args);  
  55.                 return massageReturnTypeIfNecessary(proxy, target, retVal);  
  56.             }  
  57.             finally {  
  58.                 advised.getTargetSource().releaseTarget(target);  
  59.             }  
  60.         }  
  61.     }  
  62.   
  63.   
  64.     /** 
  65.      * Interceptor for unadvised dynamic targets when the proxy needs exposing. 
  66.      */  
  67.     private class DynamicUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {  
  68.   
  69.         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  70.             Object oldProxy = null;  
  71.             Object target = advised.getTargetSource().getTarget();  
  72.             try {  
  73.                 oldProxy = AopContext.setCurrentProxy(proxy);  
  74.                 Object retVal = methodProxy.invoke(target, args);  
  75.                 return massageReturnTypeIfNecessary(proxy, target, retVal);  
  76.             }  
  77.             finally {  
  78.                 AopContext.setCurrentProxy(oldProxy);  
  79.                 advised.getTargetSource().releaseTarget(target);  
  80.             }  
  81.         }  
  82.     }</span>  

 

好了,已经知道spring内部实现就是动态代理机制了,所以现在我们手动写的关于CGLIB的动态代理还是要写个小示例的。

上一篇文章中如果ServiceImpl没有实现任何接口的话,那么创建代理对象就不能使用javax.lang.Proxy这个类了,这时需要使用CGLIB了,在spring资源包中找到CGLIB的jar:spring-framework-2.5.6\lib\cglib\cglib-nodep-2.1_3.jar

然后写一个新的代理实现类CGlibProxyFactory.java

 

Java代码   收藏代码
  1. <span style="font-size: medium;">package com.javacrazyer.dao;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.Enhancer;  
  6. import net.sf.cglib.proxy.MethodInterceptor;  
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. public class CGlibProxyFactory implements MethodInterceptor {  
  10.     private Object targetObject;  
  11.   
  12.     public Object newProxy(Object targetObject) {  
  13.         this.targetObject = targetObject;  
  14.         Enhancer enhancer = new Enhancer();  
  15.         enhancer.setSuperclass(this.targetObject.getClass());  
  16.         enhancer.setCallback(this);  
  17.         // 返回代理对象  
  18.         return enhancer.create();  
  19.     }  
  20.   
  21.     /** 
  22.      * proxy 带来对象本身 method 被拦截到的方法 args 方法的参数 methodProxy 方法的代理对象 
  23.      */  
  24.     public Object intercept(Object proxy, Method method, Object[] args,  
  25.             MethodProxy methodProxy) throws Throwable {  
  26.         checkSecurity();  
  27.         Object ret = null;  
  28.         try {  
  29.             // 调用目标对象的真实方法  
  30.             ret = method.invoke(this.targetObject, args);  
  31.             // ret接受存在的返回值,不存在返回值则为Null  
  32.         } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.         return ret;  
  36.     }  
  37.   
  38.     public void checkSecurity() {  
  39.         System.out.println("--------ServiceImpl.checkSecurity()----------");  
  40.     }  
  41.   
  42. }  
  43. </span>  

 

 

这时测试类有所变化

Java代码   收藏代码
  1. <span style="font-size: medium;">package com.javacrazyer.dao;  
  2.   
  3. public class TestProxy {  
  4.     public static void main(String[] args) {  
  5.         CGlibProxyFactory hander = new CGlibProxyFactory();  
  6.         //创建代理对象,这是这个代理对象是UserManagerImpl的子类  
  7.           ServiceImpl  service = (ServiceImpl)hander.newProxy(new ServiceImpl());  
  8.           service.outPut();  
  9.           service.putOut();  
  10.     }  
  11. }  
  12. </span>  

 

 输出结果

--------ServiceImpl.checkSecurity()----------
I am method outPut
--------ServiceImpl.checkSecurity()----------
I am method putOut

 

到目前位置,无论是前面的静态代理,javax.lang.Proxy的动态代理,还是这里的CGLIB的动态代理都是没有借助任何框架的情况下实现AOP的方法

猜你喜欢

转载自jsycjacky.iteye.com/blog/2224592
今日推荐