您好,欢迎访问一九零五行业门户网

面试官:Spring Aop 常见注解和执行顺序

最近,我在给很多人做简历修改和模拟面试的时候,有部分朋友和我反馈spring aop的面试题,今天就和大家来问问。
spring 一开始最强大的就是 ioc / aop 两大核心功能,我们今天一起来学习一下 spring aop 常见注解和执行顺序。
spring 面试 核心点:
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);}
实现类这里我门就简单一点做一个除法操作,可以模拟正常也可以很容易的模拟错误。
@servicepublic 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@componentpublic 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
img多切面的情况多个切面的情况下,可以通过@order指定先后顺序,数字越小,优先级越高。如下图所示:
代理失效场景下面一种场景会导致 aop 代理失效,因为我们在执行 a 方法的时候其实本质是执行 aserver#a 的方法拦截器(methodinterceptor)链, 当我们在 a 方法内直接执行b(), 其实本质就相当于 this.b() , 这个时候由执行 a方法是调用到 a 的原始对象相当于是 this 调用,那么会导致 b() 方法的代理失效。这个问题也是我们开发者在开发过程中最常遇到的一个问题。
@servicepublic class aservice { public void a() { system.out.println("...... a"); b(); } public void b() { system.out.println("...... b"); }}
以上就是面试官:spring aop 常见注解和执行顺序的详细内容。
其它类似信息

推荐信息