Is it possible to register AOP advices programmatically, after the application has booted and the context has been initialized?
When I tried, the advices didn't work, supposedly because they need to wrap the bean BEFORE it gets available in the context.
Something like this (it doesn't work):
@Bean
private AspectJExpressionPointcutAdvisor createPointcutAdvisor(AWSXRayRecorder awsxRayRecorder, String name, String pointcut) {
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression("execution ...()");
advisor.setAdvice(new CustomAdvice("custom bean"));
return advisor;
}
Clarification: I need to read a list of advice from a config file, and register the pointcuts accordingly. I need the label for bookeeping purposes. The file contents are unknown at compile time.
label: execution(* com.my.ns.OtherClass(..))
label2: execution(* com.my.ns.Class(..))
Maybe programmatic creation of @AspectJ Proxies according to the Spring AOP manual does what you want. Quoting from there because answers with external links only are frowned upon on SO:
Update:
So actually I played around a bit, not being a Spring user but rather an AspectJ expert. But anyway I found a way to dynamically register an advisor with a custom pointcut. The thing is, though, you need to know which beans you want to apply it to, and be careful to differentiate between beans which are already proxied and ones which are not.
Question: When in your application lifecycle and to which beans do you want to add the advisors? Have your other beans already been instantiated and wired (injected) into others? I am asking because it is quite easy to register advisors to beans you have direct references to, wrapping them into proxies or adding the advisors to existing proxies. But there is no obvious way to wrap a bean which has already been injected into other beans and not proxied yet. So how easy or difficult the solution is depends on your requirements.
P.S.: I am still wondering why your pointcuts are in a properties file instead of just in a Spring XML config file, which would be the standard way. That XML file is also loaded during application start-up. Where does the requirement to use another file come from? Both are basically editable (text) resource files.
Update 2:
Okay, I have created a GitHub repo for you. Just build with Maven and run the class with the
main(..)
method. It looks like this:The console log looks like this:
You can nicely see how log output from the advisor gets printed. After detaching the advisor again, the log output goes away and only the log output from the advisor defined in class
AopConfiguration
remains. I.e. you can mix Spring configuration with your own dynamically attached advisors.BTW, if you comment out the
@Bean
annotation inAopConfiguration
like thisthen class
PersonService
will not be proxied already by the time you attach your dynamic advisor and the console output changes to:Please note that not only the log lines produces by the Spring-configured advisor go away as expected but that also the line
changes to
The previous solution is too invasive as it not only creates advice on the fly but also handles advising beans. This replicates functionality of Spring's AbstractAdvisorAutoProxyCreator, specifically the getAdvicesAndAdvisorsForBean method, where Spring will locate and apply eligible Advisors to each bean. A better approach is to simply programmatically create Advisors and let Spring handle the rest of the plumbing of advising beans, creating proxies, and so forth.
A simple way of creating a Advisor is to create a Advisor bean using the @Bean annotation:
Where the class MyMethodInterceptor implements the MethodInterceptor interface:
What this does is to create a around advice Advisor bean named "advisorBean" for all methods calls to a Spring bean MyAspectedService declared as
This approach focuses on only creating the necessary Advisors and interception implementation and delegates the weaving of the aspect to the Spring framework.