Spring 温习笔记(四)spring AOP

怼烎@ 2023-01-11 08:44 207阅读 0赞

AOP 相关概念

Spring 的AOP (Aspect Oriented Programming)实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。

  • Target(目标对象):代理的目标对象
  • Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
  • Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
  • Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
  • Aspect(切面):是切入点和通知(引介)的结合
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

基于XML的AOP开发

切面表达式和及其抽取

切点表达式的写法

  1. execution([修饰符] 返回值类型 包名.类名.方法名(参数))
  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号* 代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
    例如:

    execution(public void com.feitian.aop.Target.method())
    execution(void com.feitian.aop.Target.(..))
    execution(
    com.feitian.aop..(..))
    execution( com.feitian.aop...(..))
    execution(
    ...*(..))

通知的类型

通知织入的写法:

  1. <aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>

切点表达式的抽取

当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。

  1. <aop:config>
  2. <!--引用myAspect的Bean为切面对象-->
  3. <aop:aspect ref="myAspect">
  4. <aop:pointcut id="myPointcut" expression="execution(* com.feitian.aop.*.*(..))"/>
  5. <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
  6. </aop:aspect>
  7. </aop:config>

图解spring aop

在这里插入图片描述

小案例

在导开始小案例之前,需要映入若干jar包;

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-jdbc</artifactId>
  5. <version>5.1.9.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-context</artifactId>
  10. <version>5.1.10.RELEASE</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>junit</groupId>
  14. <artifactId>junit</artifactId>
  15. <version>4.12</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.aspectj</groupId>
  19. <artifactId>aspectjweaver</artifactId>
  20. <version>1.9.0</version>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.springframework</groupId>
  24. <artifactId>spring-test</artifactId>
  25. <version>5.1.10.RELEASE</version>
  26. </dependency>
  27. </dependencies>

采用目标类和切面类实现切面编程,增强目标方法

方法一 采用xml配置方式(bean 通过在xml配置文件中注入)

目标类

  1. public class AopTarget implements AopTargetInterface {
  2. public void save() {
  3. System.out.println("AOP target saving .......");
  4. //int i = 1/0;
  5. }
  6. }

目标接口

  1. public interface AopTargetInterface {
  2. public void save();
  3. }

切面类

  1. public class AopAspect {
  2. public void before(){
  3. System.out.println("前值增强......");
  4. }
  5. public void after(){
  6. System.out.println("后置增强......");
  7. }
  8. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  9. System.out.println("this is before around method....");
  10. Object proceed = pjp.proceed();
  11. System.out.println("this is after around method....");
  12. return proceed;
  13. }
  14. public void afterThrowing(){
  15. System.out.println("exception is throwing");
  16. }
  17. }

配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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">
  3. <!--配置目标对象-->
  4. <bean id="aopTarget" class="com.feitian.spring.aop.AopTarget"/>
  5. <!--配置切面对象-->
  6. <bean id="aopAspect" class="com.feitian.spring.aop.AopAspect"/>
  7. <!--配置织入: 告诉spring框架 那些方法(切点)需要进行那些增强(前置、后置)-->
  8. <aop:config>
  9. <!--申明切面-->
  10. <aop:aspect ref="aopAspect">
  11. <!--抽取切点-->
  12. <aop:pointcut id="myExecution" expression="execution(* com.feitian.spring.aop.*.*(..))"/>
  13. <aop:before method="before" pointcut-ref="myExecution"/>
  14. <aop:after method="after" pointcut-ref="myExecution"/>
  15. <aop:around method="around" pointcut="execution(public void com.feitian.spring.aop.AopTarget.save())"/>
  16. <aop:after-throwing method="afterThrowing" pointcut-ref="myExecution"/>
  17. </aop:aspect>
  18. </aop:config>
  19. </beans>

测试类

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext.xml")
  3. public class SpringAop01Demo {
  4. @Autowired
  5. private AopTargetInterface aopTarget;
  6. @Test
  7. public void test1(){
  8. aopTarget.save();
  9. }
  10. }

在这里插入图片描述

方法二 采用注解配置方式(bean 直接通过扫描注入)

接口类:

  1. public interface AnnAopTargetInterface {
  2. public void save();
  3. }

目标类 :

  1. @Component("annAopTarget")
  2. public class AnnAopTarget implements AnnAopTargetInterface {
  3. public void save() {
  4. System.out.println("AOP target saving .......");
  5. //int i = 1/0;
  6. }
  7. }

切面类

  1. @Component("myAnnAspect")
  2. @Aspect //标注当前MyAspect是一个切面类
  3. public class AnnAopAspect {
  4. @Before("execution(* com.feitian.spring.anno.*.*(..))")
  5. public void before(){
  6. System.out.println("前值增强......");
  7. }
  8. @After("execution(* com .feitian.spring.anno.*.*(..))")
  9. public void after(){
  10. System.out.println("后置增强......");
  11. }
  12. @Around("execution(* com .feitian.spring.anno.*.*(..)))")
  13. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  14. System.out.println("this is before around method....");
  15. Object proceed = pjp.proceed();
  16. System.out.println("this is after around method....");
  17. return proceed;
  18. }
  19. @AfterThrowing("execution(* com .feitian.spring.anno.*.*(..)))")
  20. public void afterThrowing(){
  21. System.out.println("exception is throwing");
  22. }
  23. }

xml配置文件(在xml配置文件中需要配置扫描注解和开启自动代理)

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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/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">
  3. <!--组件扫描-->
  4. <context:component-scan base-package="com.feitian.spring.anno"/>
  5. <!--开启自动代理-->
  6. <aop:aspectj-autoproxy/>
  7. </beans>

测试类

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration("classpath:applicationContext_ann.xml")
  3. public class SpringAop02Demo {
  4. @Autowired
  5. private AnnAopTargetInterface annAopTarget;
  6. @Test
  7. public void test1(){
  8. annAopTarget.save();
  9. }
  10. }

在这里插入图片描述
测试结果达到基本预期。

在这里小猿抛出一个问题,为什么开启自动注解后各个通知的执行顺序会发生变化呢?若有童鞋知道答案请及时告知小猿,谢谢各位了。

发表评论

表情:
评论列表 (有 0 条评论,207人围观)

还没有评论,来说两句吧...

相关阅读

    相关 spring学习笔记: Spring AOP

    AOP的概念不好解释, 有一大堆的术语都很拗口,还是先看一个代码例子,在src根目录下面新建一个package叫做aop,把这个单元所有的代码都放在这个包里面,有一个接口Boo