首页 > 其他分享 >Spring Aop 常见注解和执行顺序

Spring Aop 常见注解和执行顺序

时间:2023-03-28 17:13:56浏览次数:45  
标签:spring Aop boot System Spring println 注解 public out

Spring Aop 常见注解和执行顺序

IOC、AOP、Bean注入、Bean的生命周期、Bean的循环依赖

首先我们一起来回顾一下 Spring Aop 中常用的几个注解:

  • @Before 前置通知:目标方法之前执行
  • @After 后置通知:目标方法之后执行(始终执行)
  • @AfterReturning 返回之后通知:执行方法结束之前执行(异常不执行)
  • @AfterThrowing 异常通知:出香异常后执行
  • @Around 环绕通知:环绕目标方法执行

常见问题

1、你肯定知道 Spring  , 那说说 Aop 的去全部通知顺序, Spring Boot 或者 Spring Boot 2 对 aop 的执行顺序影响?

2、说说你在 AOP 中遇到的那些坑?

示例代码

下面我们先快速构建一个 spring aop 的 demo 程序来一起讨论 spring aop 中的一些细节。

配置文件

为了方便我直接使用 spring-boot 进行快速的项目搭建,大家可以使用 idea 的spring-boot 项目快速创建功能,或者去 start.spring.io 上面去快速创建spring-boot 应用。

因为本人经常手动去网上贴一些依赖导致,依赖冲突服务启动失败等一些问题。

plugins {
    id 'org.springframework.boot' version '2.6.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group 'io.zhengsh'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
    maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {
    # 其实这里也可以不增加 web 配置,为了试验简单,大家请忽略 
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-aop'
    
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

接口类

首先我们需要定义一个接口。我们这里可以再来回顾一下 JDK 的默认代理实现的选择:

  • 如果目标对象实现了接口,则默认采用JDK动态代理
  • 如果目标对象没有实现接口,则采用进行动态代理
  • 如果目标对象实现了接口,且强制Cglib,则使用cglib代理

这块的逻辑在 DefaultAopProxyFactory 大家有兴趣可以去看看。

public interface CalcService {

    public int div(int x, int y);
}

实现类

这里我门就简单一点做一个除法操作,可以模拟正常也可以很容易的模拟错误。

@Service
public class CalcServiceImpl implements CalcService {

    @Override
    public int div(int x, int y) {
        int result = x / y;
        System.out.println("====> CalcServiceImpl 被调用了,我们的计算结果是:" + result);
        return result;
    }
}

aop 拦截器

申明一个拦截器我们要为当前对象增加 @Aspect 和 @Component ,笔者之前也是才踩过这样的坑,只加了一个。

其实这块我刚开始也不是很理解,但是我看了 Aspect 注解的定义我就清楚了

 

 

这里面根本就没有 Bean 的定义。所以我们还是乖乖的加上两个注解。

还有就是如果当测试的时候需要开启Aop 的支持为配置类上增加@EnableAspectJAutoProxy 注解。

其实 Aop 使用就三个步骤:

  • 定义 Aspect 定义切面
  • 定义 Pointcut 就是定义我们切入点
  • 定义具体的通知,比如: @After, @Before 等。
@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* io.zhengsh.spring.service.impl..*.*(..))")
    public void divPointCut() {

    }

    @Before("divPointCut()")
    public void beforeNotify() {
        System.out.println("----===>> @Before 我是前置通知");
    }

    @After("divPointCut")
    public void afterNotify() {
        System.out.println("----===>> @After  我是后置通知");
    }

    @AfterReturning("divPointCut")
    public void afterReturningNotify() {
        System.out.println("----===>> @AfterReturning 我是前置通知");
    }

    @AfterThrowing("divPointCut")
    public void afterThrowingNotify() {
        System.out.println("----===>> @AfterThrowing 我是异常通知");
    }

    @Around("divPointCut")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object retVal;
        System.out.println("----===>> @Around 环绕通知之前 AAA");
        retVal = proceedingJoinPoint.proceed();
        System.out.println("----===>> @Around 环绕通知之后 BBB");
        return retVal;
    }
}

测试类

其实我这个测试类,虽然用了 @Test 注解,但是我这个类更加像一个 main 方法把:如下所示:

 

 

执行结论

结果记录:spring 4.x, spring-boot 1.5.9

无法现在依赖,所以无法试验

我直接说一下结论:Spring 4 中环绕通知是在最里面执行的

结果记录:spring 版本5.3.15 springboot 版本2.6.3

多切面的情况

多个切面的情况下,可以通过@Order指定先后顺序,数字越小,优先级越高。如下图所示:

 

 


代理失效场景

下面一种场景会导致 aop 代理失效,因为我们在执行 a 方法的时候其实本质是执行 AServer#a 的方法拦截器(MethodInterceptor)链, 当我们在 a 方法内直接执行b(), 其实本质就相当于 this.b() , 这个时候由执行 a方法是调用到 a 的原始对象相当于是 this 调用,那么会导致 b() 方法的代理失效。这个问题也是我们开发者在开发过程中最常遇到的一个问题。

@Service
public class AService {
    
    public void a() {
        System.out.println("...... a");
        b();
    }
    
    public void b() {
        System.out.println("...... b");
    }

}

 

     

标签:spring,Aop,boot,System,Spring,println,注解,public,out
From: https://www.cnblogs.com/fenqing5277/p/17265922.html

相关文章

  • SpringBoot+RocketMq+Mybatis项目整合demo
    转载自:https://blog.csdn.net/mikewuhao/article/details/106666109 ============= Demo实现的功能项目启动生产者和消费者2个服务后,生产者端执行用户查询,从数据......
  • Spring boot 、Vue学习体会
    近期集中学习了Springboot、Vue等技术,学习过程也是不断碰壁,总的来说自认为有些涨进,抓住核心、深入关键、逐步剖析。两个技术分别负责后台和前端,学习后一个感受,两个技术......
  • SpringBoot的EnableCaching简述
    SpringBoot中的EnableCaching简述springboot中自带有数据缓存机制,主要通过其org.springframework.cache包下的各种类来实现。EnableCaching@EnableCaching是启用缓存......
  • SpringBoot运行端口被占用
    运行Springboot项目端口被占用如图:   解决方式-命令行进入cmd界面执行查询端口占用情况netstat-ano|findstr8210结果执行中止端口命令 task......
  • Spring4+Hibernate4事务小记
    学习Spring+Hibernate,非常强大的框架,为了追新,就直接从最高版本开始学习了,这要冒很大的风险,因为网上可查到的资料大多是针对旧版本的,比如Spring3,Hibernate3。根据我的测试,记......
  • Spring
    在pom.xml文件中添加依赖<dependencies><!--dependency><groupId>org.example</groupId><artifactId>[theartifactidoftheblocktobemounte......
  • Spring Mvc返回html页面404错误解决记录
        以前使用SpringMvc时候都是返回jsp页面或者ftl页面,昨天想返回html页面,spring-mvc.xml配置如下 :<beanid="viewResolver"class="org.springframework.web.servlet......
  • Spring4 MVC Hibernate4集成
    一、   本文所用环境Spring4.0.3.RELEASEHibernate4.3.5.FinalMysql二、   工程目录 三、   Maven添加依赖用Maven创建项目,pom.xml如下:ViewCode四、  ......
  • 【Spring】创建第一个Spring项目
    添加依赖:1<!--spring基础包spring-core-->2<dependency>3<groupId>org.springframework</groupId>4<artifactId>spring-core</artifa......
  • Spring、SpringBoot基于内存的异步调用ApplicationContext.publishEvent (生产、消费)
     ApplicationContext.publishEvent是Spring提供的解耦的一种方式(基于内存)。同样可以使用MQ组件/线程池代替。 参数类NotifyEvent.javaimportlombok.AllA......