使用没有类型的 args 指示符创建切入点会导致 BeanCurrentlyInCreationException

Creating A pointcut using args designator with no types results in BeanCurrentlyInCreationException

使用 Spring AOP,当尝试使用指示符 args 创建 Pointcut 而未提供任何类型时,会导致一系列以 BeanCurrentlyInCreationException[= 开头的异常17=]

例子

object _001_Spring_AOP_Pointcut_Args_NoArgs {

    open class BeanA {
        open fun m() {
            println("BeanA#m()")
        }
    }

    @Aspect
    class AspectA {
        @Pointcut("args()")
        private fun pc_noArgs() = Unit

        @After("sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs.AspectA.pc_noArgs()")
        private fun ac_noArgs() = println("ac_noArgs")
    }

    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    open class Config {
        @Bean
        open fun beanA(): BeanA = BeanA()

        @Bean
        open fun aspectA(): AspectA = AspectA()
    }

    fun runJava() {
        AnnotationConfigApplicationContext(Config::class.java)
    }

}

运行 方法

    @Test
    fun test_run() {
        _001_Spring_AOP_Pointcut_Args_NoArgs.runJava()
    }

异常总结

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'beanA' defined in sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$Config: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$BeanA]: Factory method 'beanA' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'aspectA' defined in sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$Config: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$AspectA]: Factory method 'aspectA' threw exception; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'aspectA': Requested bean is currently in creation: Is there an unresolvable circular reference?

args() 对比 execution(* *())

这是拦截所有无参数方法的不寻常方式。我宁愿让它更明确,而是使用 execution(* *()) 。如果您曾经从 Spring AOP 迁移到 AspectJ,您会注意到 args() 匹配那里的所有类型的切入点,例如callinitializationpreinitializationstaticinitializationget 和不带参数的构造函数 calls/executions。

切入点作用域

在 Spring AOP 中,您的问题可能是另一个问题:您的切入点太宽泛了。它匹配 Spring beans 中的许多连接点,也在 Spring 或第三方 classes 本身中。所以你想限制切入点的范围,例如像

execution(* *()) && within(my.own.package.**)

何时(不)在切入点中使用完全限定的 class 名称

顺便说一句,如果你的切入点定义在与使用它的建议完全相同的 class 中,则没有必要使用完全限定的 class 名称,即而不是

@After("sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs.AspectA.pc_noArgs()")

你可以使用

@After("pc_noArgs()")

内联切入点

如果您不打算在其他建议中重复使用相同的切入点,只需删除 @Pointcut 并定义一个内联切入点,例如

@After("execution(* *()) && within(my.own.package.**)")

建议应该是public

虽然可以将 @Pointcut 方法定义为私有方法,但如果您不从其他 classes 引用它,@After 建议应该是 public .它可能适用于 Spring AOP,但违反约定。同样,如果您曾经迁移到 AspectJ,您甚至会遇到编译错误,因为 AspectJ 通知必须是 public.

代码共享失败,出现以下异常 -

org.springframework.beans.factory.BeanCurrentlyInCreationException

,当 pointcut 表达式在包内有范围时,方面 class 所在。

示例:

bean 的完全限定名称:

rg.spring.boot.AspectA

rg.spring.boot.bean.BeanA

像下面这样的切入点表达式将失败:

@Pointcut("args() && within(rg.spring.boot..*)")

然而,以下切入点表达式成功:

@Pointcut("args() && within(rg.spring.boot.bean..*)")

这个例外,per 我,是因为 pointcut 在初始化期间以方面的框架方法为目标。要解决异常,您可以将 bean 移动到特定包并微调该包的 pointcut 表达式的范围。