天天看點

11-spring注解方式實作AOP

步驟:

  1. 導入相應的依賴
  2. 開啟注解掃描
  3. 編寫代理接口
  4. 被代理接口實作類
  5. 編寫切面類
  6. 測試

1. pom.xml加載依賴

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-11</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <!--導入AOP包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>org.aopalliance</groupId>
            <artifactId>com.springsource.org.aopalliance</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.cglib</groupId>
            <artifactId>com.springsource.net.sf.cglib</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
           

需要的依賴:

  1. com.springsource.net.sf.cglib-2.1.3.jar
  2. com.springsource.org.aopalliance-1.0.0.jar
  3. com.springsource.org.aspectj.weaver-1.9.6.RELEASE.jar
  4. spring-aspects-5.2.13.RELEASE

2.spring配置檔案

<?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:context="http://www.springframework.org/schema/context"
       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/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">
    <context:component-scan base-package="com.qwy"/>
    <!--開啟注解的AOP實作-->
    <aop:aspectj-autoproxy/>
</beans>
           
  1. content命名空間
  2. aop命名空間

3. POJO

package com.qwy.bean;

/**
 * @author qwy
 * @create 2021-04-24 9:46
 **/
public class Users {
}

           

此類純屬為了模拟開發

4.代理接口

package com.qwy.servce;

import com.qwy.bean.Users;

/**
 * @author qwy
 * @create 2021-04-24 9:46
 **/
public interface UsersService {
    public void save(Users users);
    public void update(Users users);
    public void deleteById(Integer id);
    public Users getUsersById(Integer id);
}

           

5. 代理接口實作類(被代理對象)

package com.qwy.servce.impl;

import com.qwy.bean.Users;
import com.qwy.servce.UsersService;
import org.springframework.stereotype.Service;

/**
 * @author qwy
 * @create 2021-04-24 9:47
 **/
@Service("usersService")
public class UsersServiceImpl implements UsersService {
    public void save(Users users) {
        System.out.println("UsersServiceImpl.save");
    }

    public void update(Users users) {
        System.out.println("UsersServiceImpl.update");
    }

    public void deleteById(Integer id) {
        System.out.println("UsersServiceImpl.deleteById");
    }

    public Users getUsersById(Integer id) {
        System.out.println("UsersServiceImpl.getUsersById");
        return new Users();
    }
}

           

隻是為了示範AOP,跟業務無參,這裡隻做了列印,看效果。

  1. @Service :将被代理對象交給Spring容器管理。

6.切面類

package com.qwy.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author qwy
 * @create 2021-04-24 9:29
 **/
@Component
@Aspect
public class LogAspect {
    @Pointcut("execution(* com.qwy.servce.impl.UsersServiceImpl.update(..))")
    private void anyMethod(){}
    @Before("anyMethod()")
    public void beforeMethod(JoinPoint joinPoint){
        //擷取被代理對象的方法名
        String name = joinPoint.getSignature().getName();
        //擷取被代理對象的參數清單
        Object[] args = joinPoint.getArgs();
        System.out.println("前置通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
    }
    @AfterReturning(value = "anyMethod()",returning = "result")
    public void afterReturnMethod(JoinPoint joinPoint,Object result){
        //擷取被代理對象的方法名
        String name = joinPoint.getSignature().getName();
        //擷取被代理對象的參數清單
        Object[] args = joinPoint.getArgs();
        System.out.println("傳回通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
    }
    @AfterThrowing(value = "anyMethod()",throwing = "e")
    public void afterThrowMethod(JoinPoint joinPoint, Exception e){
        //擷取被代理對象的方法名
        String name = joinPoint.getSignature().getName();
        //擷取被代理對象的參數清單
        Object[] args = joinPoint.getArgs();
        System.out.println("異常通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
    }

    @After("anyMethod()")
    public void after(JoinPoint joinPoint){
        //擷取被代理對象的方法名
        String name = joinPoint.getSignature().getName();
        //擷取被代理對象的參數清單
        Object[] args = joinPoint.getArgs();
        System.out.println("後置通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
    }
    //@Around("anyMethod()")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed=null;
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        try{
            //前置通知

            System.out.println("前置通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
            proceed = joinPoint.proceed();
            //傳回通知
            System.out.println("傳回通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
        }catch (Exception e){
            System.out.println("異常通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
            e.printStackTrace();
        }finally {
            System.out.println("後置通知:  被代理對象的方法:  " + name +" , 參數 :" + args);
        }

        return proceed;
    }

}


           

說明:

  1. @Component :切面必須是 IOC 中的 bean
  2. @Aspect :表名該類為切面類
  3. @Pointcut :定義切面表達式,格式:execution(通路修飾 傳回值 類的全名稱.方法名(參數清單))
  4. @Before(“anyMethod()”) :表示前置通知,接口的每一個實作類的每一個方法開始之前執行一段代碼,anyMethod表示引用@Pointcut定 義的表達式,當然可以單獨定義。
  5. @AfterReturning(value = “anyMethod()”,returning = “result”): 表示傳回通知是可以通路到方法的傳回值的!
  6. @AfterThrowing(value = “anyMethod()”,throwing = “e”):在目标方法出現異常時會執行的代碼.可以通路到異常對象; 且可以指定在出現特定異常時在執行通知代碼。
  7. @After(“anyMethod()”):在方法執行之後執行的代碼. 無論該方法是否出現異常
  8. @Around(“anyMethod()”):環繞通知需要攜帶 ProceedingJoinPoint 類型的參數.環繞通知類似于動态代理的全過程: ProceedingJoinPoint 類型的參數可以決定是否執行目标方法.且環繞通知必須有傳回值, 傳回值即為目标方法的傳回值。

7. 測試類

package com.qwy.test;

import com.qwy.bean.Users;
import com.qwy.servce.UsersService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author qwy
 * @create 2021-04-24 9:49
 **/
public class TestAnnotationAOP {
    private ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
    @Test
    public void test1(){
        UsersService usersService = ac.getBean("usersService", UsersService.class);
        usersService.save(new Users());
        usersService.update(new Users());
        usersService.deleteById(1);
        usersService.getUsersById(1);
    }
}

           

執行結果:

UsersServiceImpl.save

前置通知: 被代理對象的方法: update , 參數 :[Ljava.lang.Object;@3c947bc5

UsersServiceImpl.update

傳回通知: 被代理對象的方法: update , 參數 :[Ljava.lang.Object;@3c947bc5

後置通知: 被代理對象的方法: update , 參數 :[Ljava.lang.Object;@3c947bc5

UsersServiceImpl.deleteById

UsersServiceImpl.getUsersById

需要示範的結果過多。這裡沒有分開示範,大家可以分别示範。

繼續閱讀