隨筆-126  評論-247  文章-5  trackbacks-0

          AOP(Aspect Orient Programming),也就是常說的面向方面編程,它是作為面向對象編程的一種補充,專門用于處理系統中分布于各個模塊(不同方法)

          中的交叉關注點的問題,在 Java EE 應用中,常常通過 AOP 來處理一些具有橫切性質的系統級服務,如事務管理、安全檢查、緩存、對象池管理等。

          簡單點來說,它就是一個攔截器可以攔截一些進程,例如,當某個方法執行時,Spring AOP 可以攔截該執行的方法,并允許在方法執行之前或之后添加額外的功能,

          以上如若解釋的不好,勿噴 -_- ||

          AspectJ 是一個基于 Java 語言的 AOP 框架,提供了強大的 AOP 功能,Spring 從 2.0 起,對 AspectJ 功能都提供了支持 .

          幾個常用的 AspectJ 注解 : 

              @Before   在方法執行前被執行

              @After     在方法執行后被執行

              @AfterReturning     在方法執行后被執行,并同時攔截方法返回的結果

              @AfterThrowing      在方法拋出異常時候被執行,若方法不拋出異常,則不會被執行

              @Around   這個,不知道要怎么解釋了,比較不好解釋,就像你攔截了一個方法,并在適當的時候給予放行,放行前后可以做額外的處理,下面看示例就很容易明白了

          環境 :

           
          eclipse  3.6
          maven  3.0.4
          spring   3.0.5
          aspectj 1.6.11
           


          pom.xml 清單 :

           
          <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation
          ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
            
          <modelVersion>4.0.0</modelVersion>
            
          <groupId>com.fancy</groupId>
            
          <artifactId>spring-aop</artifactId>
            
          <packaging>war</packaging>
            
          <version>1.0</version>
            
          <name>spring-aop Maven Webapp</name>
            
          <url>http://maven.apache.org</url>
            
            
          <properties>
              
          <spring.version>3.0.5.RELEASE</spring.version>
              
          <aspectj.version>1.6.11</aspectj.version>
            
          </properties>
            
            
          <dependencies>
              
              
          <dependency>
                
          <groupId>org.springframework</groupId>
                
          <artifactId>spring-core</artifactId>
                
          <version>${spring.version}</version>
              
          </dependency>
           
              
          <dependency>
                
          <groupId>org.springframework</groupId>
                
          <artifactId>spring-context</artifactId>
                
          <version>${spring.version}</version>
              
          </dependency>
           
              
          <!-- Spring AOP + AspectJ -->
              
          <dependency>
                
          <groupId>org.springframework</groupId>
                
          <artifactId>spring-aop</artifactId>
                
          <version>${spring.version}</version>
              
          </dependency>
           
              
          <dependency>
                
          <groupId>org.aspectj</groupId>
                
          <artifactId>aspectjrt</artifactId>
                
          <version>${aspectj.version}</version>
              
          </dependency>
           
              
          <dependency>
                
          <groupId>org.aspectj</groupId>
                
          <artifactId>aspectjweaver</artifactId>
                
          <version>${aspectj.version}</version>
              
          </dependency>
              
              
          <dependency>
                
          <groupId>junit</groupId>
                
          <artifactId>junit</artifactId>
                
          <version>4.7</version>
                
          <scope>test</scope>
              
          </dependency>
              
            
          </dependencies>
            
            
          <build>
              
          <finalName>spring-aop</finalName>
            
          </build>
            
          </project>
           


          applicationContext.xml 清單 :

           
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:p
          ="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
            xmlns:aop
          ="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
            xsi:schemaLocation
          ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
          >
              
            
          <!-- 開啟注解 -->
            
          <context:annotation-config/>
            
          <!-- 自動掃描 -->
            
          <context:component-scan base-package="com.fancy"/>
            
          <!-- 啟動 AspectJ 支持 -->
            
          <aop:aspectj-autoproxy />
              
          </beans>
           


          還是來編寫 HelloWorld :

          1 . 編寫 HelloWorld 接口

           
          package com.fancy.service;

          public interface HelloWorld {

              
          public void sayHi();
              
              
          public void sayHiAround(String username);
              
              
          public void sayHiThrowException() throws Exception;
              
              
          public String  sayHiReturnValue();
              
          }
           


          2 . 編寫 HelloWorld 接口的實現,并將其注解成 spring 的一個組件

           
          package com.fancy.service.impl;

          import com.fancy.service.HelloWorld;
          import org.springframework.stereotype.Component;

          @Component
          public class HelloWorldImpl implements HelloWorld {

              
          public void sayHi() {
                  
                  System.out.println(
          "sayHi ---->> Hi fancy !");
              }

              
          public void sayHiAround(String username) {
                  
                  System.out.println(
          "sayHiAround ---->> Hi " + username + " !");
              }

              
          public void sayHiThrowException() throws Exception {
                  
                  System.out.println(
          "sayHiThrowException ---->> Hi fancy !");
                  
          throw new Exception("Throw an exception here !!!!");
              }

              
          public String sayHiReturnValue() {
                  
                  System.out.println(
          "sayHiReturnValue ---->> Hi fancy !");
                  
          return "fancy";
              }
              
          }
           


          3 . 編寫方面代碼 :

          AspectJ @Before 示例

           
          package com.fancy.aspect;

          import org.aspectj.lang.JoinPoint;
          import org.aspectj.lang.annotation.Aspect;
          import org.aspectj.lang.annotation.Before;
          import org.springframework.stereotype.Component;

          @Aspect
          @Component
          public class MyAspect {

              @Before(
          "execution (* com.fancy.service.HelloWorld.sayHi(..))")
              
          public void logBefore(JoinPoint   joinPoint){
                  
                  System.out.println(
          "logBefore() Method Invoke!");
                  System.out.println(
          "Hijack Method Name : " + joinPoint.getSignature().getName());
              }
              
          }
           

          其中,@Before("execution (* com.fancy.service.HelloWorld.sayHi(..))") 中的 execution (* com.fancy.service.HelloWorld.sayHi(..)) 是切入點表達式,

          更多的幫助信息可以查看 spring 的幫助文檔,spring 3.0.5 的幫助文檔中是在 第 7  章的 7.2.3.4 小節,因為文檔上說的也不是太清楚,在這里我也不好說話,

          其中的 execution 是用于匹配方法執行的連接點,那個 * 號所占的位不知道是不是代表方法的訪問權限,文檔上沒說,網上也沒找到相關解釋,哪位知道的望告知啊~~

          接下來的 com.fancy.service.HelloWorld.sayHi 就很明顯了,就是切入點方法名,再接下來的是 (..),(..) 代表匹配任意數量的參數,可以是 0 個也可以是多個 ;

          如果你確定這個方法不需要參數,可以直接使用 (),還可以使用 (*) 來匹配一個任意類型的參數,還可以使用 (* , String),這樣代表匹配兩個參數,第二個參數必須是

          String 類型的參數,這些在 spring 幫助文檔的 7.2.3.4 小節都有說到,在這里就不多說了,可以自己去看,英文的看起來更帶勁 *_*

          再接下來的是 JoinPoint 接口,org.aspectj.lang.JoinPoint 接口表示的是目標類連接點對象,這個我也找不到相關的 API,只能手工整理一下了 :

          JoinPoint     API 

               java.lang.Object                getThis() :獲取代理對象本身;

               java.lang.Object           getTarget() :獲取連接點所在的目標對象; 

              Signature                   getSignature() :獲取連接點的方法簽名對象; 

              java.lang.Object[]             getArgs():獲取連接點方法運行時的入參列表; 
                       

          Junit 測試

           
          package junit.test;

          import org.junit.Test;
          import org.junit.BeforeClass;
          import com.fancy.service.HelloWorld;
          import org.springframework.context.ApplicationContext;
          import org.springframework.context.support.ClassPathXmlApplicationContext;

          public class TestApp {
              
              
          private static ApplicationContext context = null;
              
              @BeforeClass
              
          public static void setUpBeforeClass() throws Exception {

                  context 
          = new ClassPathXmlApplicationContext("applicationContext.xml");
              }
              
              @Test
              
          public void testMethod() throws Exception{
                  
                  HelloWorld helloworld 
          = (HelloWorld)context.getBean("helloWorldImpl");
                  helloworld.sayHi();
              }

          }
           

          后臺輸出 :

           
          logBefore() Method Invoke
          !
          Hijack Method Name : sayHi
          sayHi 
          ---->> Hi fancy !
           


          AspectJ @After 示例

           
          package com.fancy.aspect;

          import org.aspectj.lang.JoinPoint;
          import org.aspectj.lang.annotation.After;
          import org.aspectj.lang.annotation.Aspect;
          import org.springframework.stereotype.Component;

          @Aspect
          @Component
          public class MyAspect {


              @After(
          "execution (* com.fancy.service.HelloWorld.sayHi(..))")
              
          public void logAfter(JoinPoint   joinPoint){
                  
                  System.out.println(
          "logAfter() Method Invoke!");
                  System.out.println(
          "Hijack Method Name : " + joinPoint.getSignature().getName());
              }
              
          }
           

          Junit 測試

           
          @Test
              
          public void testMethod() throws Exception{
                  
                  HelloWorld helloworld 
          = (HelloWorld)context.getBean("helloWorldImpl");
                  helloworld.sayHi();
              }
           

          后臺輸出 :

           
          sayHi 
          ---->> Hi fancy !
          logAfter() Method Invoke
          !
          Hijack Method Name : sayHi
           


          AspectJ @AfterReturning 示例

           
          package com.fancy.aspect;

          import org.aspectj.lang.JoinPoint;
          import org.aspectj.lang.annotation.AfterReturning;
          import org.aspectj.lang.annotation.Aspect;
          import org.springframework.stereotype.Component;

          @Aspect
          @Component
          public class MyAspect {


              @AfterReturning(pointcut 
          = "execution (* com.fancy.service.HelloWorld.sayHiReturnValue(..))", returning = "returnValue")
              
          public void logAfterReturning(JoinPoint   joinPoint, Object/*String*/ returnValue){
                  
                  System.out.println(
          "logAfterReturning() Method Invoke!");
                  System.out.println(
          "Hijack Method Name : " + joinPoint.getSignature().getName());
                  System.out.println(
          "The Return Value Is : " + returnValue);
              }
              
          }
           

          Junit 測試

           
          @Test
              
          public void testMethod() throws Exception{
                  
                  HelloWorld helloworld 
          = (HelloWorld)context.getBean("helloWorldImpl");
                  helloworld.sayHiReturnValue();
              }
           

          后臺輸出 :

           
          sayHiReturnValue 
          ---->> Hi fancy !
          logAfterReturning() Method Invoke
          !
          Hijack Method Name : sayHiReturnValue
          The Return Value Is : fancy
           


          AspectJ @AfterThrowing 示例

           
          package com.fancy.aspect;

          import org.aspectj.lang.JoinPoint;
          import org.aspectj.lang.annotation.AfterThrowing;
          import org.aspectj.lang.annotation.Aspect;
          import org.springframework.stereotype.Component;

          @Aspect
          @Component
          public class MyAspect {


              @AfterThrowing(pointcut 
          = "execution (* com.fancy.service.HelloWorld.sayHiThrowException(..))", throwing = "error")
              
          public void logAfterThrowing(JoinPoint joinPoint, Throwable error){
                  
                  System.out.println(
          "logAfterThrowing() Method Invoke!");
                  System.out.println(
          "Hijack Method Name : " + joinPoint.getSignature().getName());
                  System.out.println(
          "Exception Message  :" + error);
              }
              
          }
           

          Junit 測試

           
          @Test
              
          public void testMethod() throws Exception{
                  
                  HelloWorld helloworld 
          = (HelloWorld)context.getBean("helloWorldImpl");
                  helloworld.sayHiThrowException();
              }
           

          后臺輸出 :

           
          sayHiThrowException 
          ---->> Hi fancy !
          logAfterThrowing() Method Invoke
          !
          Hijack Method Name : sayHiThrowException
          Exception Message  :java.lang.Exception: Throw an exception here 
          !!!!
           

          若將 HelloWorldImpl 類中 sayHiThrowException 方法的異常拋出注釋掉,

           
          public void sayHiThrowException() throws Exception {
                  
                  System.out.println(
          "sayHiThrowException ---->> Hi fancy !");
                  
          //throw new Exception("Throw an exception here !!!!");
              }
           

          其余不變,再次執行 Junit 測試,后臺輸出 :

           
          sayHiThrowException 
          ---->> Hi fancy !
           

          這就說明,當該方法能夠運行正常的時候,沒有拋出異常,則,logAfterThrowing 不會被執行 .


          AspectJ @Around 示例

           
          package com.fancy.aspect;

          import java.util.Arrays;

          import org.aspectj.lang.ProceedingJoinPoint;
          import org.aspectj.lang.annotation.Around;
          import org.aspectj.lang.annotation.Aspect;
          import org.springframework.stereotype.Component;

          @Aspect
          @Component
          public class MyAspect {


              @Around(
          "execution (* com.fancy.service.HelloWorld.sayHiAround(..))")
              
          public void logAround(ProceedingJoinPoint   joinPoint) throws Throwable {
                  
                  System.out.println(
          "logAround() Method Invoke!");
                  System.out.println(
          "Hijack Method Name  : " + joinPoint.getSignature().getName());
                  System.out.println(
          "Hijack Arguments Is : " + Arrays.toString(joinPoint.getArgs()));
                  System.out.println(
          "Around before : can do something here !");
                  joinPoint.proceed(); 
          //放行
                  System.out.println("Around after  : can do something here !");
              }
              
          }
           

          Junit 測試

           
          @Test
              
          public void testMethod() throws Exception{
                  
                  HelloWorld helloworld 
          = (HelloWorld)context.getBean("helloWorldImpl");
                  helloworld.sayHiAround(
          "fancy");
              }
           

          后臺輸出 :

           
          logAround() Method Invoke
          !
          Hijack Method Name  : sayHiAround
          Hijack Arguments Is : [fancy]
          Around before : can 
          do something here !
          sayHiAround 
          ---->> Hi fancy !
          Around after  : can 
          do something here !
           

          其中,需要提一下 ProceedingJoinPoint 接口 :

          ProceedingJoinPoint 繼承于 JoinPoint,是其子接口,它新增了兩個用于執行連接點方法的方法: 

               java.lang.Object proceed() throws java.lang.Throwable:通過反射執行目標對象的連接點處的方法; 

               java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通過反射執行目標對象連接點處的方法,不過使用新的入參替換原來的入參。


          最后附上 spring 3.0.5 幫助文檔中的一些信息 :

          Some examples of common pointcut expressions are given below.

          • the execution of any public method:

            execution(public * *(..))
          • the execution of any method with a name beginning with "set":

            execution(* set*(..))
          • the execution of any method defined by the AccountService interface:

            execution(* com.xyz.service.AccountService.*(..))
          • the execution of any method defined in the service package:

            execution(* com.xyz.service.*.*(..))
          • the execution of any method defined in the service package or a sub-package:

            execution(* com.xyz.service..*.*(..))
          • any join point (method execution only in Spring AOP) within the service package:

            within(com.xyz.service.*)
          • any join point (method execution only in Spring AOP) within the service package or a sub-package:

            within(com.xyz.service..*)
          • any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:

            this(com.xyz.service.AccountService)

            'this' is more commonly used in a binding form :- see the following section on advice for how to make the proxy object available in the advice body.

          • any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:

            target(com.xyz.service.AccountService)

            'target' is more commonly used in a binding form :- see the following section on advice for how to make the target object available in the advice body.

          • any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable:

            args(java.io.Serializable)

            'args' is more commonly used in a binding form :- see the following section on advice for how to make the method arguments available in the advice body.

            Note that the pointcut given in this example is different to execution(* *(java.io.Serializable)): the args version matches if the argument passed at runtime is Serializable, the execution version matches if the method signature declares a single parameter of type Serializable.

          • any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation:

            @target(org.springframework.transaction.annotation.Transactional)

            '@target' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

          • any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:

            @within(org.springframework.transaction.annotation.Transactional)

            '@within' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

          • any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:

            @annotation(org.springframework.transaction.annotation.Transactional)

            '@annotation' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

          • any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the@Classified annotation:

            @args(com.xyz.security.Classified)

            '@args' can also be used in a binding form :- see the following section on advice for how to make the annotation object(s) available in the advice body.

          • any join point (method execution only in Spring AOP) on a Spring bean named 'tradeService':

            bean(tradeService)
          • any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service':

            bean(*Service)






















           



            
          posted on 2012-10-05 00:31 fancydeepin 閱讀(4850) 評論(1)  編輯  收藏

          評論:
          # re: Spring AOP + AspectJ framework[未登錄] 2013-08-12 20:57 | tiger
          前面的那個*號是表示訪求的返回類型  回復  更多評論
            

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 昌邑市| 延寿县| 房山区| 中江县| 剑河县| 上虞市| 若尔盖县| 巴彦淖尔市| 房山区| 翁源县| 瓮安县| 彝良县| 佛教| 安塞县| 嘉峪关市| 镇沅| 改则县| 宾阳县| 奉化市| 塔河县| 定西市| 怀化市| 桐乡市| 时尚| 邵阳县| 延寿县| 沙坪坝区| 依兰县| 始兴县| 阿瓦提县| 平凉市| 文成县| 新蔡县| 阿图什市| 桑植县| 大悟县| 涟源市| 渝北区| 临沧市| 宁南县| 从化市|