基于注解的AOP配置之四种通知日志记录案例(不建议)

1、 创建maven的jar工程,导入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
    </dependencies>

2、 编写业务层的接口

public interface IAccountService {

    /**
     * 模拟保存账户
     */
   void saveAccount();
}

3、编写业务层接口的实现类:

@Service("accountService")
public class AccountServiceImpl implements IAccountService{
    @Override
    public void saveAccount() {
        System.out.println("执行了保存");
       // int i=1/0;
    }
}

4、 创建一个具有公共代码的类

@Component("logger")  // 要将通知bean交个spring来管理,否则通知bean不生效
@Aspect//表示当前类是一个切面类
public class Logger { @Pointcut("execution(* com.itheima.service.impl.*.*(..))") private void pt1(){} //前置通知 @Before("pt1()") public void beforePrintLog(){ System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。"); } //后置通知 @AfterReturning("pt1()") public void afterReturningPrintLog(){ System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。"); } // 异常通知 @AfterThrowing("pt1()") public void afterThrowingPrintLog(){ System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。"); } //最终通知 @After("pt1()") public void afterPrintLog(){ System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。"); } }

Logger类上面写@Aspect注解,表示当前类是一个切面类

前置通知用@Before("pt1()")注解,

后置通知用@AfterReturning("pt1()")注解,

异常通知用@AfterThrowing("pt1()")注解,

最终通知用@After("pt1()")注解,

环绕通知用@Around("pt1()")注解

Logger类中定义一个方法pt1,使用@Pointcut注解指定切入点表达式

注意引用切入点表达式时,@Before、@AfterReturning、@AfterThrowing、@After注解中的pt1后面的()一定要加上,否则会报错。

5、编写配置文件bean.xml,配置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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="com.itheima"></context:component-scan>
    <!-- 配置spring开启注解AOP的支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

6、测试

public class AOPTest {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// ApplicationContext ac = new AnnotationConfigApplicationContext(Logger.class);
//2.获取对象
IAccountService as = (IAccountService)ac.getBean("accountService");
//3.执行方法
as.saveAccount();
}
}

结果:

发现最终通知在后置通知之前先执行,

发现最终通知在异常通知之前先执行,

Spring基于注解的AOP中,这四个通知类型确实有顺序调用的问题,所以在实际开发中一般选择用环绕通知。因为环绕通知不存在这个问题,因为代码是我们自己写的,我们想让他们什么时候执行就什么时候执行,故如果是基于注解的AOP,建议用环绕通知,因为前面四个通知在执行调用顺序上有问题

不使用XML而是使用纯注解实现AOP

1、注释掉bean.xml中的

 2、给Logger类添加注解

@Component("logger")
@Aspect//表示当前类是一个切面类
@ComponentScan(basePackages = "com.itheima")
@EnableAspectJAutoProxy
public class Logger {
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    private void pt1(){}
    //前置通知
    @Before("pt1()")
    public  void beforePrintLog(){
        System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
    }
    //后置通知
    @AfterReturning("pt1()")
    public  void afterReturningPrintLog(){
        System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
    }
    // 异常通知
    @AfterThrowing("pt1()")
    public  void afterThrowingPrintLog(){
        System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
    }
    //最终通知
    @After("pt1()")
    public  void afterPrintLog(){
        System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
    }

}

使用注解@ComponentScan(basePackage=“com.itheima”)替换<context:component-scan>标签

使用@EnableAspectJAutoProxy替换<aop:aspectj-autoproxy>标签。

3、测试:

public class AOPTest {
    public static void main(String[] args) {
        //1.获取容器
//        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        ApplicationContext ac = new AnnotationConfigApplicationContext(Logger.class);
        //2.获取对象
        IAccountService as = (IAccountService)ac.getBean("accountService");
        //3.执行方法
        as.saveAccount();
    }
}

结果:

 

原文地址:https://www.cnblogs.com/zwh0910/p/14628864.html