记一次SpringBoot Aspect不生效解决过程

本文记录了一次SpringBoot中AOP在Service层无法执行的问题及解决过程。问题源于在Controller层调用的Service对象不是代理对象,导致AOP切面无法生效。原因是Shiro的LifecycleBeanPostProcessor在实例化自定义Realm时,提前初始化了依赖的Service。解决方案是将Realm中对Service的引用改为懒加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自我的个人博客:《记一次SpringBoot Aspect不生效解决过程》

 

问题描述

项目中两个aspect,一个环绕controller,用于记录日志,能够正常在point处进入aspect处理;另一个aspect 的point设于service,死活不能进入。


解决思路

1、首先排查pointcut配置是否正确,检查后发现没有问题;
2、我们都知道spring的aop运用的是动态代理技术,由spring托管的bean大多为代理bean,controller层打印service对象,发现service对象竟然直接是service实现类的“本尊”。如下图所示:
 



再看springboot启动日志,发现roleServiceImpl实例化的时候有如下提示:
Bean 'roleServiceImpl' of type [com.gaoxiaobo.wms.service.impl.RoleServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
 



那么问题就明了了,我们在controller层调用的roleServiceImpl对象非代理对象而是其本身,那么对其的aspect是不会生效的,不仅aspsect不会生效,事务注解@Transactional也不会生效,问题还是相当严重的。

那么,why 没有生成其代理对象呢?一定是哪里先调用了roleServiceImpl导致spring优先实例化了该bean;

通过排查,找到了罪魁祸首:shiro 的LifecycleBeanPostProcessor优先实例化自定义Realm,自定义的Realm依赖于roleService,导致roleService被初始化。


解决方法
自定义realm中roleService设置成懒加载。

### Spring Boot AOP 不生效的原因分析 当遇到Spring Boot应用程序中的面向切面编程(AOP)功能未按预期工作的情况时,可能由多种因素引起。为了确保AOP能够正常运行,在项目配置以及依赖项方面需要注意几个关键点。 #### 1. 添加必要的依赖关系 确认`pom.xml`文件中包含了AspectJ的支持库: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 此依赖会引入所有必需的组件来支持AOP特性[^1]。 #### 2. 启用全局AOP代理机制 如果使用的是基于Java Config的方式,则应在主类或其他配置类上添加@EnableAspectJAutoProxy注解以激活自动代理创建过程: ```java import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy(proxyTargetClass=true) public class AppConfig { } ``` 设置参数`proxyTargetClass=true`可以强制CGLIB子类化模式而不是默认接口代理方式,这有助于处理那些没有实现任何接口的目标对象。 #### 3. 正确编写切入点表达式 确保定义合适的Pointcut匹配规则以便精确捕获目标方法调用。例如: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service..*(..))") public void logMethodCall(JoinPoint joinPoint){ System.out.println("Invoking method:" + joinPoint.getSignature().getName()); } } ``` 上述代码片段展示了如何通过指定包路径前缀(`com.example.service`)及其下的任意层次结构内的所有公共成员函数作为切入点范围。 #### 4. 验证Bean扫描作用域 检查是否存在多个独立的应用上下文实例导致某些beans未能被正确注册至同一容器内;另外还需注意aspect bean本身也需处于相同的scope下才能与其他业务逻辑bean交互成功。 ```java @SpringBootApplication(scanBasePackages={"com.example.controller","com.example.aspect"}) public class Application { public static void main(String[] args) throws Exception{ SpringApplication.run(Application.class,args); } } ``` 在此处指定了两个基础包用于组件扫描操作,从而保证controller层和自定义aspect都能得到有效的加载与管理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值