SSM学习之路——spring第三天_使用注解AOP

一、pom.xml

<packaging>jar</packaging>
    <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>

二、bean.xml

这个为使用注解实现aop的xml配置
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    <context:component-scan base-package="com.itheima"></context:component-scan>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

三、使用注解编写Logger类

1、使用分开的四个通知类型分别实现前、后、最终、异常通知
@Aspect为表示这个类为一个切面
这里使用两种方式写表达式
一种是像@After后面一样直接填写表达式
另一种就是先写一个pt1()方法,在上面注上@Pointcut,里面填写表达式
在引用Pointcut注解的时候,比如@Before,要注意是pt1(括号),括号不能省略,否则会报切入点表达式错误

@Component("logger")
@Aspect
public class Logger {
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    public void pt1(){}
    @Before("pt1()")
    public void beginLog(){
        System.out.println("开始执行方法");
    }
    @After("execution(* com.itheima.service.impl.*.*(..))")
    public void endLog(){
        System.out.println("方法执行结束(最终)");
    }
    @AfterReturning("pt1()")
    public void successLog(){
        System.out.println("方法执行成功(执行完方法后就调用)");
    }
    @AfterThrowing("pt1()")
    public void exceptionLog(){
        System.out.println("方法执行异常");
    }
}

四、Client类

只调用saveAccount方法来测试

public class Client {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        as.saveAccount();
    }
}

运行结果:

开始执行方法
新建账户
方法执行结束(最终)
方法执行成功(执行完方法后就调用)

notice:

这里有一个发现,就是我们使用spring的几个通知使用注解分开编写(即不使用环绕通知)的时候,先执行最终通知,再执行执行成功,(相当于先执行了finally,再执行方法执行完的操作,我们平常是先执行方法执行完的操作,最后再执行finally)是存在一个顺序上的问题的,比如我们在最终方法需要关闭一个流,而执行成功的方法又需要这个流来操作,按照这个顺序,那么就会出现问题,因为正常执行完所有操作后,再执行最终操作的。

而使用环绕通知则没有这个问题:
使用环绕通知注解:

@Around("execution(* com.itheima.service.impl.*.*(..))")
    public Object arroundLogger(ProceedingJoinPoint pdj){
        Object rtValue = null;
        try {
            Object args[] = pdj.getArgs();
            System.out.println("前置方法执行");
            rtValue=pdj.proceed(args);
            System.out.println("方法执行成功(执行完方法就调用)");
            return rtValue;
        } catch (Throwable throwable) {
            System.out.println("异常方法执行");
            throwable.printStackTrace();
        }finally {
            System.out.println("最终方法执行");
        }
        return rtValue;
    }

执行顺序没有问题

前置方法执行
新建账户
方法执行成功(执行完方法就调用)
最终方法执行

因此更推荐使用环绕通知

发布了23 篇原创文章 · 获赞 0 · 访问量 593

猜你喜欢

转载自blog.csdn.net/SixthMagnitude/article/details/104155892
今日推荐