spring aop创建工程基于注解开发(@Aspect、@Before、@After、@AfterReturning、 @AfterThrowing)

概述

本文通过案例讲解:@Aspect、@Before、@After、@AfterReturning、 @AfterThrowing 注解的作用

尤其是:@Before、@After、@AfterReturning、 @AfterThrowing 注解的执行顺序

案例

使用注解的方式实现aop,实现 不修改 UserSrvImpl 源代码的情况下,增加打印日志的功能

工程目录

创建maven工程

略

修改pom.xml

添加依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

注解需要依赖 aspectjweaver

定义service接口

spring默认使用JDK动态代理实现 aop,所以需要接口

public interface IUserService {
    public void save(String username, String password);
    public int update();
    public int delete(String id);
}

service实现类

@Service
public class UserSrvImpl implements IUserService {

    public UserSrvImpl(){
        System.out.println("UserSrvImpl构造方法");
    }
    public void save(String username,String password){
//        System.out.println("UserSrvImpl保存 报错");
//        int i=1/0;
        System.out.println("UserSrvImpl保存 "+username+"-"+password);
    }
    public int update(){
        System.out.println("UserSrvImpl修改 ");
        return 1;
    }
    public int delete(String id){
        System.out.println("UserSrvImpl删除 "+id);
        return 2;
    }
}

实现Logger日志类

//由spring容器管理,该类不属于Controller、Service、Repository,所以用@Component注解
@Component
//表明该类为切面类
@Aspect
public class Logger {
    /*
    在 com.yingqi.service 包下的类 的 方法,都能注入代码
     */
    @Pointcut("execution(* top.malaoshi.service.*.*(..))")
    public void pt(){

    }
    /*
    在 com.yingqi.service 包下的类 的 方法,执行之前 会先执行下面方法
     */
    @Before("pt()")
    public void beforePrint(JoinPoint jp){
        Signature s=jp.getSignature();
        System.out.println("=======before:::"+"调用 " + s.getDeclaringTypeName()+"."+s.getName() + ",参数:"
                + Arrays.toString(jp.getArgs()));
    }
    /*
    在 com.yingqi.service 包下的类 的 方法,执行之后(不论是否抛异常) 会执行下面方法
     */
    @After("pt()")
    public void afterPrint(){
        System.out.println("======after");
    }
    /*
    在 com.yingqi.service 包下的类 的 方法,执行之后(没抛异常) 会执行下面方法
     */
    @AfterReturning(pointcut="pt()",returning="result")
    public void afterReturningPrint(JoinPoint jp, Object result){
        Signature s=jp.getSignature();
        System.out.println("======afterReturning:::"+"调用 " + s.getDeclaringTypeName()+"."+s.getName() + " ,返回值:" + result);
    }
    /*
    在 com.yingqi.service 包下的类 的 方法,执行之后(抛异常了) 会执行下面方法
     */
    @AfterThrowing(pointcut="pt()",throwing="e")
    public void afterThrowingPrint(JoinPoint jp, Exception e){
        Signature s=jp.getSignature();
        System.out.println("======afterThrowingPrint:::"+s.getDeclaringTypeName()+"."+s.getName() + ",抛出异常:" + e);
    }
}

配置类

@Configuration
@ComponentScan("top.malaoshi")
//启用aop注解
@EnableAspectJAutoProxy
public class ApplicationConfig {

}

注意

必须 加上 @EnableAspectJAutoProxy 注解,才能开启aop,解释参见:
https://www.malaoshi.top/show_1IXUetDK7Ji.html

测试-执行成功

主启动类

public class Main {
    public static void main(String[] args) {
        ApplicationContext ac=new AnnotationConfigApplicationContext(ApplicationConfig.class);

        IUserService srv=(IUserService)ac.getBean("userSrvImpl");
        srv.save("李雷","123456");
    }
}

执行成功的通知顺序:

  1. before
  2. 目标方法
  3. after
  4. afterReturning

测试-执行报错

修改 UserSrvImpl

让 save() 方法抛出异常

@Service
public class UserSrvImpl implements IUserService {

    public UserSrvImpl(){
        System.out.println("UserSrvImpl构造方法");
    }
    public void save(String username,String password){
        System.out.println("UserSrvImpl保存 报错");
        int i=1/0;
//        System.out.println("UserSrvImpl保存 "+username+"-"+password);
    }
    public int update(){
        System.out.println("UserSrvImpl修改 ");
        return 1;
    }
    public int delete(String id){
        System.out.println("UserSrvImpl删除 "+id);
        return 2;
    }
}

执行报错的通知顺序:

  1. before
  2. 目标方法
  3. after
  4. afterThrowingPrint

原文出处:/show_1IX2zv3HVwY.html