面向切面編程-AOP的介紹

AOP簡介java

  1. AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論, 是對傳統 OOP(Object-Oriented Programming, 面向對象編程) 的補充.。
  2. AOP 的主要編程對象是 切面(aspect), 而切面模塊化橫切關注點.。
  3. 在應用 AOP 編程時, 仍然須要定義通用的系統功能, 但能夠明確的定義這個功能在哪裏, 以什麼方式應用, 而且沒必要修改受影響的類. 這樣一來橫切關注點就被模塊化到特殊的對象(切面)裏。

 

  AOP的優勢:web

    •  日誌記錄的代碼和真正的業務邏輯代碼進行代碼分離 
    •  通用的系統功能(日誌記錄、權限校驗)進行了高度的模塊化 
    •  業務邏輯的功能變的更簡潔,僅僅包含業務邏輯的代碼
    •  AOP能夠將系統功能(日誌記錄)與業務邏輯功能攪和到一塊兒執行

 

 


 

 

 

AOP 中的專業術語spring

 

  • 切面(aspect):橫切邏輯被模塊化的特殊對象。即它是一個類 :如LogAspect
  • 通知(advice):切面中必須完成的工做。即它是類中的一個方法:如writeLog()
  • 目標類(target):被通知加強的對象
  • 代理類(proxy):向目標類應用通知加強以後產生的對象
  • 切入點(pointcut):切面中通知執行的「地點」的定義
  • 鏈接點(JoinPoint): 與切入點匹配的執行點:如目標類中的全部方法getUserId()

 

 


 

 

 

AOP的兩種底層實現方式express

  代理:apache

代理設計模式的原理: 使用一個代理對象將原始對象包裝起來, 而後用該代理對象取代原始對象. 任何對原始對象的調用都要經過代理對象. 代理對象決定是否以及什麼時候將方法調用轉到原始對象上。編程

 

 

 

      •     靜態代理:

爲每個目標對象建立一個代理實現類的方式能夠認爲就是靜態代理。設計模式

靜態代理的實現很簡單,可是會形成代理類的快速膨脹,每個目標類,都須要建立一個代理類api

 1 //靜態代理
 2 public class StaticProxyUserService implements UserService {  3     //原始對象
 4     private UserService userService;  5     
 6     public StaticProxyUserService(UserService userService) {  7         this.userService = userService;  8  }  9  @Override 10     public User getById(String userId) { 11         System.out.println("執行權限校驗,日誌記錄......."); 12         return userService.getById(userId); 13  } 14  @Override 15     public boolean add(User user) { 16         System.out.println("執行權限校驗,日誌記錄......."); 17         return userService.add(user); 18  } 19 
20  @Override 21     public boolean delete(String userId) { 22         System.out.println("執行權限校驗,日誌記錄......."); 23         return userService.delete(userId); 24  } 25  @Override 26     public boolean update(User user) { 27         System.out.println("執行權限校驗,日誌記錄......."); 28         return userService.update(user); 29  } 30 }

 

 

      •    動態代理:

 

爲了解決靜態代理的缺點,就產生了動態代理:在系統運行時,動態生成一個持有原始對象,並實現代理接口的Proxy,同時 「植入」通用邏輯(日誌、權限等)。maven

動態代理能夠實現靜態代理相同的功能,惟一的區別這些Proxy的建立都是自動的而且在系統運行時生成的。這樣就不須要對每個原始對象來建立一個代理了。ide

 

 JDK動態代理

 

JDK內置的Proxy動態代理能夠在運行時動態生成字節碼,而不必針對每一個類編寫代理類。中間主要使用到了一個接口InvocationHandler與Proxy.newProxyInstance靜態方法。

 使用內置的Proxy(JDK動態代理)實現動態代理有一個問題:被代理的類必須實現接口,未實現接口則沒辦法完成動態代理。

若是項目中有些類沒有實現接口,則不該該爲了實現動態代理而刻意去抽出一些沒有實例意義的接口,經過cglib能夠解決該問題。

 

 

    1.  建立maven工程並解決jdk版本及web.xml問題

    2.  導入jar包

<properties>
      <spring-version>4.2.4.RELEASE</spring-version>
  </properties>
  
   <dependencies>
       <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>${spring-version}</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-core</artifactId>
           <version>${spring-version}</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-beans</artifactId>
           <version>${spring-version}</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-expression</artifactId>
           <version>${spring-version}</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-web</artifactId>
           <version>${spring-version}</version>
       </dependency>
       <dependency>
           <groupId>javax.servlet</groupId>
           <artifactId>javax.servlet-api</artifactId>
           <version>3.1.0</version>
           <scope>provided</scope>
       </dependency>    
       <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring-version}</version>
        <scope>test</scope>
    </dependency>    
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring-version}</version>
    </dependency>    
   </dependencies>
   <build>
          <plugins>
          <!-- 設置jdk的編譯版本 -->
            <plugin>  
                        <groupId>org.apache.maven.plugins</groupId>  
                        <artifactId>maven-compiler-plugin</artifactId>  
                        <version>3.1</version>  
                        <configuration>  
                            <source>1.8</source>  
                            <target>1.8</target> 
                            <encoding>utf-8</encoding> 
                        </configuration>  
                    </plugin>  
        </plugins>
    </build>

 

    3.  編寫切面類(封裝加強邏輯)

1 //切面:定義了加強的業務邏輯(權限驗證)
2 public class SecurityAspect { 3     //權限校驗的系統邏輯
4     public void checkPrivilege(){ 5         System.out.println("我是權限校驗的方法,我須要在方法執行前進行執行"); 6  } 7 }

 

    4.  建立代理對象

 1 public class ProxyFactory implements InvocationHandler{  2     //目標類
 3     private Object target;  4         
 5     //傳遞目標對象
 6     public ProxyFactory(Object target) {  7         super();  8         this.target = target;  9  } 10 
11     public Object getProxy(){ 12         /**
13  * loader:類加載器 14  * interfaces:目標實現類接口(jdk動態代理必須有接口) 15  * h:實現了InvocationHandle接口的類 16          */
17         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 18                 target.getClass().getInterfaces(), this); 19  } 20 
21  @Override 22     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 23         //添加校驗權限的邏輯
24         SecurityAspect securityAspect = new SecurityAspect(); 25         //添加檢驗權限
26  securityAspect.checkPrivilege(); 27         //反射調用業務邏輯方法(目標類,參數)
28         Object result = method.invoke(target, args); 29         return result; 30  } 31 }

 

    5.  測試

1 public static void main(String[] args) { 2         //測試動態代理的執行
3         UserService target = new UserServiceImpl(); 4         //產生代理對象
5         UserService proxy = (UserService) new ProxyFactory(target).getProxy(); 6         //調用代理對象的業務方法
7  proxy.add(); 8     }

 

 

 CGLIB動態代理

 

   CGLIB(Code Generation Library)是一個開源項目,是一個強大的,高性能,高質量的Code生成類庫,它能夠在運行期擴展Java類與實現Java接口,通俗說cglib能夠在運行時動態生成字節碼。

   使用cglib完成動態代理,大概的原理是:cglib繼承被代理的類(UserServiceImpl),重寫方法,織入通知,動態生成字節碼並運行,由於是繼承因此final類是沒有辦法動態代理的。

 

 

      1.  定義目標類(不須要實現接口)

 1 /**
 2  * cglib的目標類  3  * 沒有實現接口,只是一個業務類  4  */
 5 public class UserServiceCglib {  6     //切入點  7     //業務邏輯方法
 8     public void add(){  9         System.out.println("cglib的add方法被調用..."); 10  } 11 }

    

      2.  定義切面類(加強邏輯類)

 

 1 /**
 2  * 加強邏輯類:日誌記錄切面  3  */
 4 public class LogAspect {  5     //通知  6     //加強的業務邏輯
 7     public void log(){  8         System.out.println("日誌記錄... ...");  9  } 10 }

 

 

      3.  定義cglib動態代理生成器

 

 1 /**
 2  * cglib動態代理類生成器  3  */
 4 public class CglibProxyFactory implements MethodInterceptor{  5     //目標對象
 6     private Object target;  7 
 8     //有參構造器
 9     public CglibProxyFactory(Object target) { 10         super(); 11         this.target = target; 12  } 13         
14     //獲取代理類的方法
15     public Object getProxy(){ 16         //調用cglib產生代理對象
17         Enhancer enhancer = new Enhancer(); 18         //設置父類的類型
19  enhancer.setSuperclass(target.getClass()); 20         //設置回調方法
21         enhancer.setCallback(this); 22         
23         //產生代理對象
24         Object proxy = enhancer.create(); 25         return proxy; 26  } 27 
28     //攔截業務方法的執行
29  @Override 30     public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 31         //添加加強邏輯 32         //添加日誌
33         LogAspect logAspect = new LogAspect(); 34  logAspect.log(); 35         
36         //執行業務邏輯方法
37         Object result = methodProxy.invokeSuper(o, args); 38         return result; 39  } 40 }

 

      4.  測試

1 public static void main(String[] args) { 2         //建立目標對象
3         UserServiceCglib target = new UserServiceCglib(); 4         //獲取目標對象的代理對象
5         UserServiceCglib proxy = (UserServiceCglib) new CglibProxyFactory(target).getProxy(); 6  proxy.add(); 7     }
相關文章
相關標籤/搜索