Issue
Using Spring AOP
, when attempting to create a Pointcut
using the designator args
while not providing any types results in a series of exceptions starting with BeanCurrentlyInCreationException
The Example
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)
}
}
The Run Method
@Test
fun test_run() {
_001_Spring_AOP_Pointcut_Args_NoArgs.runJava()
}
The Exception Summary
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?
Solution
args()
vs. execution(* *())
This is an unusual way of intercepting all methods without parameters. I would rather make it more explicit and use execution(* *())
instead. If you ever migrate from Spring AOP to AspectJ, you will notice that args()
matches all kinds of pointcuts there, e.g. call
, initialization
, preinitialization
, staticinitialization
, get
and constructor calls/executions without parameters.
Pointcut scoping
Here in Spring AOP your problem might be another one, though: Your pointcut is too broad. It matches many joinpoints in Spring beans, also in Spring or third-party classes themselves. So you want to limit the scope of your pointcut, e.g. something like
execution(* *()) && within(my.own.package.**)
When to (not) use fully qualified class names in pointcuts
BTW, if your pointcut is defined in the very same class as the advice using it, it should not be necessary to use a fully qualified class name, i.e. instead of
@After("sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs.AspectA.pc_noArgs()")
you could use
@After("pc_noArgs()")
Inline pointcuts
If you have no plans to re-use the same pointcut in other advices, just get rid of @Pointcut
and define an inline pointcut such as
@After("execution(* *()) && within(my.own.package.**)")
Advices should be public
While it is OK to define the @Pointcut
method as private if you do not refer to it from other classes, the @After
advice should be public. It might work in Spring AOP, but is against conventions. Again, if you ever migrate to AspectJ, you will even get a compile error because an AspectJ advice must be public.
Answered By - kriegaex