spring AOP的两种代理

 

1.JDK动态代理  2.cglib代理

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

注:JDK动态代理要比cglib代理执行速度快,但性能不如cglib好。所以在选择用哪种代理还是要看具体情况,一般单例模式用cglib比较好,具体原因请自行百度。

一 JDK动态代理实现(原理是使用反射机制)

首先定义接口,并实现     

 
  1. public interface TestService {

  2. public int add();    

  3. }

  4.  
  5. public class TestServiceImpl implements TestService {

  6.  
  7.      @Override

  8.      public int add() {

  9.          System.out.println("开始执行add..."); 

  10.          return 0;

  11.      }

  12. }

定义代理类,这里要注意导入的包是import java.lang.reflect.*

 
  1.    public class JDKDynamicProxy implements InvocationHandler {

  2.  
  3.      //被代理的目标对象

  4.     private Object proxyObj;  

  5.     

  6.     /**

  7.       * Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

  8.       * loader    :类加载器 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

  9.       * interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

  10.        * h         :一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

  11.      */

  12.        public Object newProxy(Object proxyObj){  

  13.              this.proxyObj = proxyObj;

  14.             //返回一个代理对象  

  15.            return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),   

  16.                                       proxyObj.getClass().getInterfaces(),   

  17.                                       this);  

  18.        }  

  19.  
  20.       /**

  21.        * 执行目标对象

  22.        * Object  proxy:被代理的对象

  23.        * Method  method:要调用的方法

  24.        * Object  args[]:方法调用时所需要的参数

  25.        */

  26.         @Override

  27.         public Object invoke(Object proxy, Method method, Object[] args)

  28.                                    throws Throwable {       

  29.              before(); 

  30.              Object object = method.invoke(this.proxyObj,args);  // 通过反射机制调用目标对象的方法

  31.              after();       

  32.              return object;  

  33.          }

  34.     

  35.          public void before(){

  36.               System.out.println("开始执行目标对象之前..."); 

  37.          }

  38.     

  39.          public void after(){

  40.              System.out.println("开始执行目标对象之后..."); 

  41.          }

  42.      }

测试类:     

 
  1. public static void main(String[] args) {

  2.         

  3.           //我们要代理的真实对象

  4.           TestService testService = new TestServiceImpl();        

  5.           //testJDKProxyService.add();//不是用代理    

  6.         

  7.          JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy();

  8.          TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService);

  9.          //执行代理类的方法  

  10.          testServiceProxy.add();

  11.  
  12.      }

控制台显示

    

 

二 CGLIB代理

    需要导入 cglib-nodep-2.1_3.jar

    先说下cglib,CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

先定义一个实现类(注意并没有实现接口)

 
  1. public class TestCGLIBServiceImpl {

  2.  
  3.     public int add() {

  4.         System.out.println("开始执行add..."); 

  5.         return 0;

  6.     }

  7.  }

定义cglib代理类,此时导入的包应该是import net.sf.cglib.proxy.* 
 

 
  1. import java.lang.reflect.Method;

  2.   import net.sf.cglib.proxy.Enhancer;

  3.   import net.sf.cglib.proxy.MethodInterceptor;

  4.   import net.sf.cglib.proxy.MethodProxy;

  5.  
  6.     public class CGLIBProxy implements MethodInterceptor{

  7.  
  8.     private Object targetObject ;//被代理的目标对象

  9.     

  10.     public Object createProxyInstance(Object targetObject) {

  11.  
  12.            this.targetObject = targetObject;

  13.  
  14.            Enhancer enhancer = new Enhancer();

  15.  
  16.            enhancer.setSuperclass(targetObject.getClass());// 设置代理目标

  17.  
  18.            enhancer.setCallback(this);// 设置回调

  19.  
  20.            return enhancer.create();

  21.  
  22.     } 

  23.     

  24.  
  25.     /**

  26.      * 在代理实例上处理方法调用并返回结果 

  27.      * @param object : 代理类

  28.      * @param method :被代理的方法

  29.      * @param args :该方法的参数数组

  30.      * @param methodProxy

  31.      */

  32.     @Override

  33.     public Object intercept(Object object, Method method, Object[] args,

  34.             MethodProxy methodproxy) throws Throwable {        

  35.         Object result = null;    

  36.         try {

  37.               System.out.println("前置处理开始 ...");

  38.               result = methodproxy.invoke( targetObject , args);//执行目标对象的方法

  39.               System.out.println("后置处理开始  ...");

  40.            } catch (Exception e) {

  41.                System.out.println("异常处理 ...");

  42.            } finally {

  43.                System.out.println("调用结束 ...");

  44.            }

  45.            return result; 

  46.        }   

  47.    }

测试类:

  

 
  1. public class TestCGLIBProxy {

  2.  
  3.         public static void main(String[] args) {

  4.         

  5.           //我们要代理的真实对象

  6.           TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl();

  7.            CGLIBProxy CGLIBproxy = new CGLIBProxy();

  8.            TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB);

  9.            testCGLIBProxy.add();

  10.        }

  11.    }

结果图:

   

写在后面:spring AOP的两种代理实现代码就写到这,这里只是实现了,如果你要想真正明白,还得熟悉其中原理机制,比如反射机制,newProxyInstance(...),Enhancer()原理,invoke()原理等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值