Spring AOP的兩種代理方式


Spring AOP主要有兩種代理方式:

1.JDK動態代理  2.cglib代理
1、如果目標對象實現了接口,默認情況下會采用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須采用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
注:JDK動態代理要比cglib代理執行速度快,但性能不如cglib好。所以在選擇用哪種代理還是要看具體情況,一般單例模式用cglib比較好,具體原因請自行百度。

一、JDK動態代理實現(原理是使用反射機制)
1、定義TestService接口
[java] view plain copy
package io.mykit.proxy.jdk.service; 
 
/**
 * JDK動態代理Service
 * @author liuyazhuang
 *
 */ 
public interface TestService { 
     
    int add(); 

2、定義TestServiceImpl實現類
[java] view plain copy
package io.mykit.proxy.jdk.service.impl; 
 
import io.mykit.proxy.jdk.service.TestService; 
 
public class TestServiceImpl implements TestService { 
 
    @Override 
    public int add() { 
        System.out.println("開始執行add..."); 
        return 0; 
    } 
 

3、定義動態代理類JDKDynamicProxy
[java] view plain copy
package io.mykit.proxy.jdk.handler; 
 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
 
/**
 * JDK的動態代理實現
 * @author liuyazhuang
 *
 */ 
public class JDKDynamicProxy implements InvocationHandler { 
 
     //被代理的目標對象 
    private Object proxyObj;   
    
    /**
     * Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
     * loader    :類加載器 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
     * interfaces:一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了
     * h         :一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上
     */ 
      public Object newProxy(Object proxyObj){   
          this.proxyObj = proxyObj; 
          //返回一個代理對象   
          return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(), proxyObj.getClass().getInterfaces(), this);   
      }   
 
     /**
      * 執行目標對象
      * Object  proxy:被代理的對象
      * Method  method:要調用的方法
      * Object  args[]:方法調用時所需要的參數
      */ 
       @Override 
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {       
            before(); 
            Object object = method.invoke(this.proxyObj, args);  // 通過反射機制調用目標對象的方法 
            after();       
            return object;   
        } 
        public void before(){ 
             System.out.println("開始執行目標對象之前..."); 
        } 
        public void after(){ 
            System.out.println("開始執行目標對象之后..."); 
    } 

4、實現測試類ProxyTest
[java] view plain copy
package io.mykit.proxy.jdk; 
 
import io.mykit.proxy.jdk.handler.JDKDynamicProxy; 
import io.mykit.proxy.jdk.service.TestService; 
import io.mykit.proxy.jdk.service.impl.TestServiceImpl; 
 
/**
 * 動態代理測試
 * 
 * @author liuyazhuang
 *
 */ 
public class ProxyTest { 
     
    public static void main(String[] args) { 
        // 我們要代理的真實對象 
        TestService testService = new TestServiceImpl(); 
        testService.add();// 不是用代理 
        System.out.println("==================================="); 
        JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy(); 
        TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService); 
        // 執行代理類的方法 
        testServiceProxy.add(); 
    } 

5、測試結果如下
[plain] view plain copy
開始執行add... 
=================================== 
開始執行目標對象之前... 
開始執行add... 
開始執行目標對象之后... 
二、CGLIB代理
1、創建TestCGLIBServiceImpl類
[java] view plain copy
package io.mykit.proxy.cglib.service.impl; 
/**
 * 未實現接口的類
 * @author liuyazhuang
 *
 */ 
public class TestCGLIBServiceImpl { 
    public int add() { 
        System.out.println("開始執行add..."); 
        return 0; 
    } 
 } 
2、創建代理類CGLIBProxy
[java] view plain copy
package io.mykit.proxy.cglib.handler; 
 
import java.lang.reflect.Method; 
import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 
 
/**
 * 基於CGLIB實現
 * @author liuyazhuang
 *
 */ 
public class CGLIBProxy implements MethodInterceptor { 
 
    private Object targetObject;// 被代理的目標對象 
 
    /**
     * 構造代理對象
     * @param targetObject 傳遞的真實對象
     * @return 代理對象
     */ 
    public Object createProxyInstance(Object targetObject) { 
        this.targetObject = targetObject; 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(targetObject.getClass());// 設置代理目標 
        enhancer.setCallback(this);// 設置回調 
        return enhancer.create(); 
    } 
 
    /**
     * 在代理實例上處理方法調用並返回結果
     * @param object : 代理類
     * @param method  :被代理的方法
     * @param args :該方法的參數數組
     * @param methodProxy : 方法代理
     */ 
    @Override 
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodproxy) throws Throwable { 
        Object result = null; 
        try { 
            System.out.println("前置處理開始 ..."); 
            result = methodproxy.invoke(targetObject, args);// 執行目標對象的方法 
            System.out.println("后置處理開始  ..."); 
        } catch (Exception e) { 
            System.out.println(" 異常處理 ..."); 
        } finally { 
            System.out.println(" 調用結束 ..."); 
        } 
        return result; 
    } 

3、創建測試類ProxyTest
[java] view plain copy
package io.mykit.proxy.cglib; 
 
import io.mykit.proxy.cglib.handler.CGLIBProxy; 
import io.mykit.proxy.cglib.service.impl.TestCGLIBServiceImpl; 
 
/**
 * 測試CGLIB代理
 * @author liuyazhuang
 *
 */ 
public class ProxyTest { 
     
     public static void main(String[] args) { 
         //我們要代理的真實對象 
         TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl(); 
         testCGLIB.add(); 
         System.out.println("======================================"); 
         CGLIBProxy CGLIBproxy = new CGLIBProxy(); 
         TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB); 
         testCGLIBProxy.add(); 
      } 

4、測試結果
[plain] view plain copy
開始執行add... 
====================================== 
前置處理開始 ... 
開始執行add... 
后置處理開始  ... 
 調用結束 ... 
5、pom.xml中添加的Jar包
[html] view plain copy
<properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <skip_maven_deploy>false</skip_maven_deploy> 
    <jdk.version>1.8</jdk.version> 
    <spring.version>4.1.0.RELEASE</spring.version> 
</properties> 
 
<dependencies> 
    
  <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-expression</artifactId> 
        <version>${spring.version}</version> 
    </dependency>  
     
        <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-messaging</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
     
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-jms</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
     
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-aop</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
     
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-jdbc</artifactId> 
         <version>${spring.version}</version> 
    </dependency> 
     
     <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-context</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
 
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-context-support</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
     
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-web</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
     
    <dependency> 
        <groupId>org.springframework</groupId> 
        <artifactId>spring-webmvc</artifactId> 
        <version>${spring.version}</version> 
    </dependency> 
     
    <dependency> 
        <groupId>org.aspectj</groupId> 
        <artifactId>aspectjtools</artifactId> 
        <version>1.9.1</version> 
    </dependency> 
     
    <dependency> 
        <groupId>javax.servlet</groupId> 
        <artifactId>javax.servlet-api</artifactId> 
        <version>3.0.1</version> 
    </dependency> 
 
    <dependency>   
        <groupId>org.slf4j</groupId>   
        <artifactId>slf4j-log4j12</artifactId>   
        <version>1.7.2</version>   
    </dependency>  
     
      <dependency> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
        <version>1.1.1</version> 
    </dependency> 
     <dependency> 
            <groupId>cglib</groupId> 
            <artifactId>cglib-nodep</artifactId> 
            <version>2.1_3</version> 
        </dependency> 
     
</dependencies> 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM