Spring框架學習09——基於AspectJ的AOP開發

一、基於註解開發AspectJ

(1)AspectJ註解

基於註解開發AspectJ要比基於XML配置開發AspectJ便捷許多,因此在實際開發中推薦使用註解方式。關於註解的相關內容以下:spring

  • @Aspect:用於定義一個切面,註解在切面類上;
  • @Pointcut:用於定義切入點表達式。在使用時須要定義一個切入點方法,該方法是一個返回值void且方法體爲空的普通方法;
  • @Before:用於定義前置通知。在使用時一般爲其指定value屬性值,該值能夠是已有的切入點,也能夠直接定義切入點表達式;
  • @AfterReturning:用於定義後置返回通知。在使用時一般爲其指定value屬性值,該值能夠是已有的切入點,也能夠直接定義切入點表達式;
  • @Around:用於定義環繞通知。在使用時一般爲其指定value屬性值,該值能夠是已有的切入點,也能夠直接定義切入點表達式;
  • @AfterThrowing:用於定義異常通知。在使用時一般爲其指定value屬性值,該值能夠是已有的切入點,也能夠直接定義切入點表達式。另外,還有一個throwing屬性用於訪問目標方法拋出的異常,該屬性值於異常通知方法中同名的形參一致;
  • @After:用於定義後置(最終)通知。在使用時一般爲其指定value屬性值,該值能夠是已有的切入點,也能夠直接定義切入點表達式;

(2)切入點表達式的定義

在通知中使用value屬性定義切入點,經過execution函數,能夠定義切入點的方法切入。
語法:execution(<訪問修飾符>?<返回類型><方法名>(<參數>)<異常>)
例如:express

  • 匹配全部類public方法 execution(public **(..))
  • 匹配指定包下全部類方法 execution(* com.imooc.dao.*(..)) 不包含子包
  • 匹配子包 execution(* com.imooc.dao..*(..)) ..*表示包、子孫包下全部類
  • 匹配指定類全部方法 execution(* com.imooc.service.UserService.*(..))
  • 匹配實現特定接口全部類方法 execution(* com.imooc.dao.GenericDAO+.*(..))
  • 匹配全部save開頭的方法 execution(* save*(..))

(3)代碼實現

添加依賴app

<!-- AOP聯盟依賴 -->
<dependency>
  <groupId>aopalliance</groupId>
  <artifactId>aopalliance</artifactId>
  <version>1.0</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.0.2.RELEASE</version>
</dependency>
<!--aspectJ相關依賴-->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.2</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.0.2.RELEASE</version>
</dependency>

建立StuDao類ide

public class StuDao {
    public void save(){
        System.out.println("保存");
    }
    public String modify(){
        System.out.println("修改");
        return "modify...";
    }
    public void delete(){
        System.out.println("刪除");
    }
    public void findOne(){
        System.out.println("查詢單條信息");
        int i = 1/0;
    }
    public void findAll(){
        System.out.println("查詢全部信息");
    }
}

建立切面類函數

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class MyAspectAnno {

    /**
     * 前置通知
     * @param joinPoint 用於獲取切點信息
     */
    @Before(value = "execution(* com.aspectj.demo.StuDao.save(..))")
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知============="+joinPoint);
    }

    /**
     * 後置返回通知,經過returning屬性能夠定義方法返回值,做爲參數
     * @param result 和returning屬性的值保持一致
     */
    @AfterReturning(value = "execution(* com.aspectj.demo.StuDao.modify(..))",returning = "result")
    public void afterReturing(Object result){
        System.out.println("後置返回通知=========="+result);
    }

    /**
     * 環繞通知
     * 若是不調用ProceedingJoinPoint的proceed方法,那麼目標方法就被攔截了
     * @param joinPoint 能夠調用攔截目標方法執行
     * @return 目標代理方法執行返回值
     * @throws Throwable
     */
    @Around(value = "execution(* com.aspectj.demo.StuDao.delete(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("環繞前置通知*************");
        Object obj = joinPoint.proceed();
        System.out.println("環繞後置通知*************");
        return obj;
    }

    //異常通知
    @AfterThrowing(value = "execution(* com.aspectj.demo.StuDao.findOne(..))",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("異常通知================"+e);
    }

    //最終通知,不管是否出現異常,最終通知老是會被執行的
    @After(value = "execution(* com.aspectj.demo.StuDao.findAll(..))")
    public void after(){
        System.out.println("最終通知==================");
    }

}

配置applicationContext.xml文件測試

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--開啓AspectJ的註解開發,自動代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <bean id="stuDao" class="com.aspectj.demo.StuDao"></bean>
    <bean class="com.aspectj.demo.MyAspectAnno"></bean>

</beans>

建立測試類spa

@Test
public void demo(){

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuDao stuDao = (StuDao) app.getBean("stuDao");
    stuDao.save();
    stuDao.modify();
    stuDao.delete();
    stuDao.findAll();
    stuDao.findOne();
}

運行結果代理

(4)切點命名

在每一個通知內定義切點,會形成工做量大,不易維護,對於重複的切點,可使用@Pointcut進行定義。
切點方法:private void 無參數方法,方法名爲切點名,當通知多個切點時,可使用||進行鏈接。
把切面類代碼修改成:code

@Aspect
public class MyAspectAnno {

    //前置通知
    @Before(value = "myPointcut1()")
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知============="+joinPoint);
    }

    //後置通知
    @AfterReturning(value = "myPointcut2()",returning = "result")
    public void afterReturing(Object result){
        System.out.println("後置返回通知=========="+result);
    }

    //環繞通知
    @Around(value = "myPointcut3()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("環繞前置通知*************");
        Object obj = joinPoint.proceed();
        System.out.println("環繞後置通知*************");
        return obj;
    }

    //異常通知
    @AfterThrowing(value = "myPointcut4()",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("異常通知================"+e);
    }

    //最終通知
    @After(value = "myPointcut5()")
    public void after(){
        System.out.println("最終通知==================");
    }

    @Pointcut(value = "execution(* com.aspectj.demo.StuDao.save(..))")
    private void myPointcut1(){}

    @Pointcut(value = "execution(* com.aspectj.demo.StuDao.modify(..))")
    private void myPointcut2(){}

    @Pointcut(value = "execution(* com.aspectj.demo.StuDao.delete(..))")
    private void myPointcut3(){}

    @Pointcut(value = "execution(* com.aspectj.demo.StuDao.findOne(..))")
    private void myPointcut4(){}

    @Pointcut(value = "execution(* com.aspectj.demo.StuDao.findAll(..))")
    private void myPointcut5(){}

}

二、基於XML配置開發AspectJ

添加依賴xml

<!-- AOP聯盟依賴 -->
<dependency>
  <groupId>aopalliance</groupId>
  <artifactId>aopalliance</artifactId>
  <version>1.0</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.0.2.RELEASE</version>
</dependency>
<!--aspectJ相關依賴-->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.2</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.0.2.RELEASE</version>
</dependency>

建立StuDao接口和實現類StuDaoImpl
StuDao接口

public interface StuDao {
    public void save();
    public void delete();
    public String modify();
    public void findOne();
    public void findAll();
}

StuDaoImpl實現類

public class StuDaoImpl implements StuDao {
    @Override
    public void save() {
        System.out.println("保存");
    }

    @Override
    public String modify() {
        System.out.println("修改");
        return "modify...";
    }

    @Override
    public void delete() {
        System.out.println("刪除");
    }

    @Override
    public void findOne() {
        System.out.println("查詢單條記錄");
        int i = 1/0;
    }

    @Override
    public void findAll() {
        System.out.println("查詢全部記錄");
    }
}

建立切面類

public class MyAspectjXml {

    //前置通知
    public void before(){
        System.out.println("前置通知===============");
    }

    //後置返回通知
    public void afterReturing(Object result){
        System.out.println("後置返回通知============="+result);
    }

    //環繞通知
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("環繞前置通知**************");
        Object obj = joinPoint.proceed();
        System.out.println("環繞後置通知**************");
        return obj;
    }

    //異常通知
    public void afterThrowing(Throwable e){
        System.out.println("異常通知=================="+e);
    }

    //最終通知
    public void after(){
        System.out.println("最終通知===================");
    }
}

配置applicationContext.xml文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <!--配置目標類-->
    <bean id="stuDao" class="com.aspectj.demo2.StuDaoImpl"></bean>
    <!--配置切面類-->
    <bean id="myAspectjXml" class="com.aspectj.demo2.MyAspectjXml"></bean>
    <!--AOP相關配置-->
    <aop:config>
        <!--配置切入點-->
        <aop:pointcut id="pointcut1" expression="execution(* com.aspectj.demo2.StuDao.save(..))"></aop:pointcut>
        <aop:pointcut id="pointcut2" expression="execution(* com.aspectj.demo2.StuDao.modify(..))"></aop:pointcut>
        <aop:pointcut id="pointcut3" expression="execution(* com.aspectj.demo2.StuDao.delete(..))"></aop:pointcut>
        <aop:pointcut id="pointcut4" expression="execution(* com.aspectj.demo2.StuDao.findOne(..))"></aop:pointcut>
        <aop:pointcut id="pointcut5" expression="execution(* com.aspectj.demo2.StuDao.findAll(..))"></aop:pointcut>

        <!--配置AOP的切面-->
        <aop:aspect ref="myAspectjXml">
            <!--配置前置通知-->
            <aop:before method="before" pointcut-ref="pointcut1"></aop:before>
            <!--配置後置返回通知-->
            <aop:after-returning method="afterReturing" pointcut-ref="pointcut2" returning="result"></aop:after-returning>
            <!--配置環繞通知-->
            <aop:around method="around" pointcut-ref="pointcut3"></aop:around>
            <!--配置異常通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e"></aop:after-throwing>
            <!--配置最終通知-->
            <aop:after method="after" pointcut-ref="pointcut5"></aop:after>
        </aop:aspect>
    </aop:config>

</beans>

建立測試類

@Test
public void demo(){
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuDao stuDao = (StuDao) app.getBean("stuDao");
    stuDao.save();
    stuDao.delete();
    stuDao.modify();
    stuDao.findAll();
    stuDao.findOne();
}

運行結果

相關文章
相關標籤/搜索