You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何无接口且在配置类中定义的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动态代理(通过继承目标类生成代理子类实现切面),但原场景存在两个关键限制:

  1. @EnableAspectJAutoProxy默认参数proxyTargetClass = false,即优先使用JDK代理,仅在目标类无接口时尝试CGLIB代理,但这个逻辑对@Configuration类中@Bean注册的Bean不生效——Spring不会自动为这类无接口Bean生成CGLIB代理。
  2. 当通过@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:01:28