为何无接口且在配置类中定义的Bean无法触发AspectJ切面?
Spring AOP切面在特定场景下不生效的原因分析
问题重现
我创建了Demo应用重现切面不生效的问题,代码如下:
DemoService
open class DemoService { fun test() { println("test function is executed.") } }
DemoAspect
@Aspect class DemoAspect { @Around("execution(* com.example.demo.service.DemoService.test(..))") fun testAspect(joinPoint: ProceedingJoinPoint) { println("before test function.") joinPoint.proceed() println("after test function.") } }
AppConfig
@Configuration @EnableAspectJAutoProxy class AppConfig { @Bean fun demoService() = DemoService() @Bean fun demoAspect() = DemoAspect() }
SpringDemoApplication
@SpringBootApplication @Import(AppConfig::class) class SpringDemoApplication fun main(args: Array<String>) { val context = runApplication<SpringDemoApplication>(*args) val demoService = context.beanFactory.getBean(DemoService::class.java) demoService.test() }
执行结果
test function is executed.
切面未生效,不符合预期。
两种可正常生效的变体
变体1:通过注解注册Bean,移除配置类中的DemoService定义
DemoService
@Service open class DemoService { ... // 保留原有test方法逻辑 }
AppConfig
@Configuration @EnableAspectJAutoProxy class AppConfig { @Bean fun demoAspect() = DemoAspect() }
变体2:让DemoService实现接口
DemoService(接口+实现类)
interface DemoService { fun test() } open class DemoServiceImpl: DemoService { override fun test() { println("test function is executed.") } }
AppConfig
@Configuration @EnableAspectJAutoProxy class AppConfig { @Bean fun demoService() = DemoServiceImpl() @Bean fun demoAspect() = DemoAspect() }
原因解析
Spring AOP默认采用JDK动态代理,这种代理方式要求目标类必须实现至少一个接口,代理类通过实现相同接口包裹原对象。当目标类无接口时,Spring本应自动切换为CGLIB动态代理(通过继承目标类生成代理子类实现切面),但原场景存在两个关键限制:
@EnableAspectJAutoProxy默认参数proxyTargetClass = false,即优先使用JDK代理,仅在目标类无接口时尝试CGLIB代理,但这个逻辑对@Configuration类中@Bean注册的Bean不生效——Spring不会自动为这类无接口Bean生成CGLIB代理。- 当通过
@Service等注解注册Bean时,Spring的组件扫描机制会配合后置处理器,正常为无接口Bean生成CGLIB代理;当目标类实现接口时,JDK代理可以正常工作,因此这两种变体的切面均能生效。
要解决原场景的问题,只需修改@EnableAspectJAutoProxy,显式强制使用CGLIB代理:
@Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) class AppConfig { @Bean fun demoService() = DemoService() @Bean fun demoAspect() = DemoAspect() }
内容的提问来源于stack exchange,提问作者zqiw7
相关产品推荐
相关产品推荐

