I'm trying to log which aspect instance is responsible for which proxied object. However, when I'm collecting proxy object context through this() PCD and using perthis() instantiation model I'm getting an error related to the variable name of proxy object that I use in the pointcut expression:
warning no match for this type name: bean [Xlint:invalidAbsoluteTypeName]
Maven dependencies that I use:
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
</dependency>
</dependencies>
This is an aspect that I use to implement that I needed:
@Aspect("perthis(com.sj.aspects.AssociationsAspect.exampleBeans())")
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AssociationsAspect {
public AssociationsAspect(){
System.out.println("Creating aspect instance!");
}
@Pointcut("execution(* com.sj.utilities.Example.*(..))")
public void exampleBeans(){};
@Pointcut("execution(* com.sj.utilities.Example.*(..)) && this(bean)")
public void exampleOperations(Object bean){};
@Before(value = "exampleOperations(bean)", argNames = "jp,bean")
public void beforeExampleMethodsExecution(JoinPoint jp, Object bean){
System.out.println(
"JoinPoint: " + jp.getStaticPart() +
"\n\taspect: " + this +
"\n\tobject: " + bean
);
}
}
I tried to change bean as variable name to concrete type, but from documentation it will give different from binding result:
Any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:
this(com.xyz.service.AccountService)
As well as it will be changing exiting error to another:
error at ::0 formal unbound in pointcut
Funny enough, if you put away ("perthis(com.sj.aspects.AssociationsAspect.exampleBeans())")
then everything will work fine and Spring container will create a separate aspect instance for every proxy object in it. However that is not desirable and most likely a bug, because through @Scope()
annotation I only say that there can be multiple instances of same aspect and that Spring container will need to create new instance when I told it to do, but not that it need to create them when it wants to.
The final solution to which I came was to use JoinPoint reflection API instead of collecting context through this() PCD. And it works fine, however I have preconceptions related to how @Scope() works without perthis() instantiation model and with it.
In the end I want to know, 'Is there a solution for collecting proxy object context with this() PCD and using perthis() instantiation model at the same time?'. As well as what are mistakes in the aspect that I described earlier, that give such an error.
This answer is incorrect in this particular context, but maybe valuable for other readers, because it describes a frequently made mistake by readers of the Spring manual who do not realise that the code snippets in the manual refer to pointcut methods with fully qualified name rather than to target methods.
I am assuming that you got the syntax example for
perthis()
from this part of the Spring manual. Unfortunately, the example is somewhat misleading, because it uses fully qualified pointcut method names, expecting the user to have read another manual section describing how to use shared pointcut definitions from a separate class, which is a rather exotic use case.Inside
perthis()
, when not referencing a poincut method name but defining an inline pointcut targeting a specific application method, you need to specify a full pointcut, not just a method name without even a return type. Examples for valid clauses would be:perthis(myPointcut())
, ifmyPointcut
is specified as a separate, named pointcutperthis(this(org.acme.MyClass))
perthis(execution(* doCommand(..))
perthis(execution(* doCommand(..)) && this(org.acme.MyClass))
See also the AspectJ documentation here and there. Unfortunately, documentation is sparse.
In your particular case, you might want:
But of course, referring to an external pointcut like
for pointcuts in the same class or super class or
for poinctuts in a shared pointcut class is also OK.
Update: I created Spring pull request # 29998 in order to improve the documentation, because I also misunderstood the brief examples out of context there.