Spring框架(6)---AspectJ實現AOP


AspectJ實現AOP

   上一篇文章Spring框架(4)---AOP講解鋪墊,講了一些基礎AOP理解性的東西,那么這篇文章真正開始講解AOP

    通過AspectJ實現AOP要比普通的實現Aop要方便的多,所以第五篇文章有關SpringAOP我暫且不寫,后面整理好了再補充上;

   那我們首先還是講一些有的沒的的東西:

什么是Spring的AspectJ的AOP

      AspectJ是一個面向切面的框架,它擴展了Java語言。AspectJ定義了AOP語法所以它有一個專門的編譯器用來生成遵守Java字節編碼規范的Class文件。
  Spring2.0以后新增了對AspectJ切點表達式支持,@AspectJ 是AspectJ1.5新增功能,通過JDK5注解技術,允許直接在Bean類中定義切面
  新版本Spring框架,建議使用AspectJ方式來開發AOP

那我們先來一個小案例,還是以前面狗的案例舉例:

1.導入相關架包

在原來的基礎上導入下面四個架包:

  • spring-aop-4.2.0.RELEASE.jar
  • com.springsource.org.aopalliance-1.0.0.jar
  • spring-aspects-4.2.0.RELEASE.jar
  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

 2.編寫配置文件applicationContext.xml    導入aop的命名空間

<?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: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.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
         
         <!-- 配置注解bean所在的包 -->
          <context:annotation-config/>
          <context:component-scan base-package="com.study.spring.d_advisor"></context:component-scan>
        <!-- 打開自動代理 -->
        <aop:aspectj-autoproxy/>
</
beans>
 
        

 3.編寫代理對象

 1 public class Dog {
 2 
 3     public void run() {
 4         System.out.println("狗會跑");
 5     }
 6 
 7     public void jump() {
 8 
 9         System.out.println("狗會跳");
10 
11     }
12 
13     public void eat() {
14 
15         System.out.println("狗能吃");
16     }
17 }

4)編寫切面類

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//@Aspect聲明當前類是一個切面
@Aspect     
public class MyAspectJ {
    //@Before代表在執行方法之前執行增強代碼
    @Before("execution(* com.study.dog.Dog.*(..))")
    public void before1() {
        System.out.println("飼養員叫你你猜能動");
    }

}

5編寫配置文件 

<?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: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.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
         
         <!-- 配置注解bean所在的包 -->
          <context:annotation-config/>
          <context:component-scan base-package="com.study.spring.d_advisor"></context:component-scan>
        <!-- 打開自動代理 -->
        <aop:aspectj-autoproxy/>
        
        
          <!-- 被代理對象 -->
           <bean id="Dog" class="com.study.dog.Dog"></bean>
         <!-- 切面 -->
          <bean id="MyAspectJ" class="com.study.dog.MyAspectJ"></bean>
       
        </beans>

6.編寫測試類

 1 import org.junit.Test;
 2 import org.junit.runner.RunWith;
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.test.context.ContextConfiguration;
 6 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 7 
 8 //完成配置文件的加載
 9 @RunWith(SpringJUnit4ClassRunner.class)
10 @ContextConfiguration(locations="classpath:applicationContext.xml")
11 public class AspectJTest {
12     // 得到dog對象
13     @Autowired
14     @Qualifier("Dog")
15     private Dog dog;
16 
17     @Test
18     public void Demo1() {
19         dog.eat();
20         dog.run();
21         dog.jump();
22     }
23     /*
24      * 輸出結果:
25      *    飼養員叫你你猜能動
26      *    狗能吃
27      *    飼養員叫你你猜能動
28      *    狗會跑
29      *    飼養員叫你你猜能動
30      *    狗會跳
31      */
32 }

 總結:上面是一個最簡單的AspectJ的AOP,我們這樣就可以通過輸入一個”飼養員叫你你猜能動",就可以在多個方法中存在,在以后開發非常需要

那么下來來說一些非常重要的干貨!

 AspectJ表達式:
    語法:execution(表達式) 通過execution函數,可以定義切點的方法切入

      execution(<訪問修飾符>?<返回類型><方法名>(<參數>)<異常>)      

         例如

               execution(public * *(..))                             匹配所有類public方法

               execution(* cn.study.dao..*(..))                  匹配指定包下所有類方法,不包含子包

     execution(* cn.study.dao..*(..))                  ..*表示包、子孫包下所有類

     execution(* cn.study.service.UserService.*(..))  匹配指定類所有方法

     execution(* cn.study.dao.GenericDAO+.*(..))   匹配實現特定接口所有類方法

     execution(* save*(..))                                     匹配所有save開頭的方法

    AspectJ增強
    @Before 前置通知,相當於BeforeAdvice
    @AfterReturning 后置通知,相當於AfterReturningAdvice
    @Around 環繞通知,相當於MethodInterceptor
    @AfterThrowing拋出通知,相當於ThrowAdvice
    @After 最終final通知,不管是否異常,該通知都會執行
    @DeclareParents 引介通知,相當於IntroductionInterceptor (不要求掌握)

那現在我們通過上面的列子,來全面貫徹上面的干貨!

對上面MyAspectJ的進行全面增強:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
//@Aspect聲明當前類是一個切面
@Aspect     
public class MyAspectJ {
   
     //@Before代表在執行方法之前執行增強代碼
     @Before("execution(* com.study.dog.Dog.run(..))")
        public void before(JoinPoint joinPoint){
            System.out.println("前置增強...."+joinPoint);
        }  
     //后置通知
      @AfterReturning (value="execution(* com.study.dog.Dog.jump(..))",returning="returnVal")
        public void afterReturin(Object returnVal){
            System.out.println("后置增強....方法的返回值:"+returnVal);
        }  
      //環繞通知
        @Around(value="MyAspectJ.myPointcut()")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
            System.out.println("環繞前增強....");
            Object obj = proceedingJoinPoint.proceed();
            System.out.println("環繞后增強....");
            return obj;
        } 
        //拋出通知
        @AfterThrowing(value="MyAspectJ.myPointcut()",throwing="e")
        public void afterThrowing(Throwable e){
            System.out.println("不好了 出異常了!!!"+e.getMessage());
        } 
        
        //最終final通知,不管是否異常,該通知都會執行
        @After("MyAspectJ.myPointcut()")
        public void after(){
            System.out.println("最終通知...");
        } 
      //切點的定義
        @Pointcut("execution(* com.study.dog.Dog.eat(..))")
        private void myPointcut(){}
}

編寫測試類AspectJTest   和上面一點不變 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//完成配置文件的加載
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AspectJTest {
    // 得到dog對象
    @Autowired
    @Qualifier("Dog")
    private Dog dog;

    @Test
    public void Demo1() {
        dog.eat();
        dog.run();
        dog.jump();
    }

}

運行結果:

通過這個例子,相信大家對於AspectJ的AOP有了一定的了解了。

最后補充一個面試題:

     Advisor和Aspect的區別?
        Advisor:Spring傳統意義上的切面:支持一個切點和一個通知的組合.
        Aspect:可以支持多個切點和多個通知的組合.

這篇文章就講到這里,有不足之處,歡迎大家指出,謝謝!

 


免責聲明!

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



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