Is it possible to create a Java aspect that runs on class initialization using Spring AOP?
We have an annotation that will be used in several places, and in order to make use of the annotation we need some boilerplate code that needs to run every second (using #Scheduled). We're hoping to move that boilerplate code to another class-level annotation to make it easier to reuse.
As far as I understand, it's not possible to implement such a class-level annotation using Spring AOP since it only supports method execution (https://www.baeldung.com/spring-aop-vs-aspectj#4-joinpoints). Is there any workaround to achieve what we're hoping for? I'm aware we could use AspectJ instead of Spring AOP, but I'm reluctant to do that because it's complex to use.
Code snipped:
#Scheduled(fixedDelayString = "${app.pollable-consumer.time-interval}")
public void pollForDeletionRequest() {
log.trace("Polling for new messages");
cleanupInput.poll(cleanupSubmissionService::submitDeletion);
}
Thanks for your help.
Update: The annotation needs to be added to a library to enable it to be shared by different microservices.
We think that writing a new class-level annotation might help. It would run on class initialization, find all methods that are annotated with #PollableStreamListener, and schedule the polling to happen for each of the Kafka topics.
To slightly adjust the terminology and shift the focus, is it acceptable to bind the creation of such a construction to Spring's Application Context initialization? If so, you could create a Bean Factory Post Processor that would have been triggered for each #PollableStreamListener.
In a nutshell, BFPP runs before spring creates the beans during the application context initialization. This mechanism allows to "dynamically" create beans that in a runtime will be indistinguishable from those created by spring in a regular way, a kind of hook to the spring initialization lifecycle that you can use here.
So this BFPP and introspect the methods of your interest. Then based on the information found in the annotations / configuration This BFPP could register a Bean Definition per scheduled job of the bean (a class with all the required parameters that you could prepare as a part of the infrastructure). Then spring will read this bean definition and create the beans out of this bean definition as it usually does.
Here you can find an example of how to use this BFPP and more specifically its registerBeanDefintion method.
Related
I'm writing an aspect for making that possible for dependencies from external libraries to return values that are correctly formatted for my application.
With this in mind, I've created an annotation with name #SafeReturns.
I wire this class from the external library with the help of spring and in addition, I add my annotation.
#SafeReturns
#Autowired
public PermissionsClient client;
Now I try to make an aspect of it, but unfortunately, I can't catch all the calls to all the methods on the field annotated with this annotation. I tried different pointcuts. e.g.
#Pointcut("execution(#myApp.SafeReturns * *(..))")
#Around("safeReturnsPointCut()")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
}
None of them helps me to achieve the behaviour of catching all the methods. Is there a way to catch them?
There are several problems with your approach and your assumptions about aspect syntax and execution logic:
You are using Spring AOP, but that one only works with Spring-managed beans/components due to its proxy-based nature, as is well documented in the Spring AOP manual. It does not work with non-Spring third-party code.
In order to target third-party code you need to use full AspectJ via LTW (load-time weaving). The Spring AOP manual also explains how to configure LTW.
Your pointcut says to target all method executions (of Spring components, if you are using Spring AOP) where the methods are annotated by SafeReturns. Neither with Spring AOP nor with AspectJ can you expect this syntax to apply to objects that happen to be assigned to instance member variables with a certain annotation. So your expectations of how you dream AOP to work and how it really does are quite divergent.
My suggestion is to switch to AspectJ via LTW and then write pointcuts which either target external method execution()s directly or to solve the problem indirectly by routing your external calls through annotated facades and target them with your pointcuts. This would even work with Spring AOP if the facades are Spring components.
There also is a direct way of solving this with advanced AspectJ + some manual bookkeeping. You can use set() pointcuts in order to find out when objects are assigned to your annotated fields (or unassigned later). Then you can have the aspect do manual bookkeeping of assigned objects and make sure that whatever your aspect advices do is only triggered if the object in question happens to be assigned to an annotated member variable. This works, I also have done that in the past. But it means you have to weave all of your application's method calls and then dynamically decide via look-ups in your bookkeeping whether or not the code should be executed or not, because there yould be object instances which are not assigned to any of your annotated fields. This incurs a certain performance penalty because this kind of thing cannot be determined during compile time by any aspect weaver. Please see my answer here for sample code for the manual bookkeeping thing.
I hope that my explanation was not too complicated, but your issue is quite technical and intricate.
As you know when I want to inject a class to my class's property in spring framework I do something like this:
Class sample {
#Autowired
MyService service;
}
or use #Resource or #Named or what else.
but now I wonder that if possible I declare my own annotation like #MyInjection to do this stuff and besides do something more.
for example, instead of searching the application context and find proper bean to inject, create a class and inject this created bean to property of class.
Thanks.
An annotation is just basically data about data. So if you want something to handle your annotation you have to write a custom annotation processor.
I suggest you should look into Spring's AOP features for more details:
Aspect Oriented Programming with Spring
With AOP you basically create an annotation (in your case) then you configure Spring to do something when it bumps into your annotation (Spring uses regexps for this if I remember it right). This is called a Pointcut. Then if Spring finds a match it runs your custom code which can be basically anything.
I think what you want could be achieved by using Spring's factory method, which gets called when Spring is about to resolve some dependency. See example Hope this helps.
I am using #Configurable beans for non-managed spring instances in a section of code that must be highly performant. We are using a lot of non-managed beans with the new operator, and in our profiling we have noticed that the use of the #Configurable annotation is slowing things down quite a bit.
Just for this specific section, we would like a faster way of pulling beans from the context (just a direct applicationContext.getBean()). I know we give up IoC doing this, but this is a special scenario and not a normal pattern.
We are using CTW for the weaving, but I wanted to know what mechanism spring is using behind the scenes to get the application context so we can simply grab it and use getBean? A static application context? Is it stored in threadlocal somewhere?
Aspects are singletons managed by AspectJ. When you put an aspect in your Spring configuration file Spring doesn't actually create the aspect. Instead it obtains a reference to the aspect using aspectOf().
This means that (at compile time when you do your weaving) your #Configurable annotation gets hooked into the singleton AnnotationBeanConfigurerAspect. Then when you load your application context, Spring obtains a reference to that same singleton aspect and calls the setBeanFactory() method on the aspect (since it implements BeanFactoryAware).
This magic can lead to trouble of course. If you had two application contexts then the second would overwrite the configuration of the first which can be terribly confusing.
To answer your question directly this means that all you have to do is create a new aspect that implements BeanFactoryAware (here is the code for AnnotationBeanConfigurerAspect which you can use as an example) and then "instantiate" that same aspect in your spring configuration file and your aspect will now have access to the bean factory.
If you're going for performance then please note that the above is not much cleaner than creating a static reference to the BeanFactory and instantiating that when you start your application so you might as well do the static reference as it is simpler.
I have a bunch of projects which declare some spring bean files. I would like to write a "library" which supplies a utility which takes some bean names and adds some behaviour "around" the objects (example: Call Counting, Monitoring, Logging etc)
One obvious way for doing this would be to add some AspectJ annotations in the spring xml files in the projects but I would like the "utility" to search for some beans and add behaviour to them (This way the projects themselves are not aware of the utility).
The utility will be declared in the spring xml file somewhere so it has access to the ApplicationContext as it could implement ApplicationContextAware interface however I am keen on exploring how one would go about modifying behaviour of another bean in the app context programmatically. ex, something like find a bean of id "OrderService", create an aspected bean with some monitoring/call counting etc around all methods and replace that bean in the application context for "OrderService"
I know there are disadvantages with this approach but what I am after is "IS it possible to do this? And if yes how?"
If you don't want to use AOP, you can achieve this using a BeanPostProcessor. The Spring documentation states:
The BeanPostProcessor interface defines callback methods that you can
implement to provide your own (or override the container's default)
instantiation logic, dependency-resolution logic, and so forth. If you
want to implement some custom logic after the Spring container
finishes instantiating, configuring, and otherwise initializing a
bean, you can plug in one or more BeanPostProcessor implementations.
So you may create and register a BeanPostProcessor and implement the postProcessAfterInitialization(Object bean, String beanName) method to modify the methods you want to customize. Here is an example.
(But I would still recommend that you do this with AOP as this is the classical use case for it and it's much easier and more declarative. With the bean() pointcut, you can even advise beans with names matching a certain pattern.)
You can create your own BeanPostProcessor. You just have two declare it in applicationContext.xml and it will be called for each bean during initialization of beans (in fact, just before or just after). In each call you get a the actual object and its name. There, you can, for example, wrap that object depending on its name or type.
I want to know that whether we can apply 'multiple' AOP behaviors to our service classes or not?
Lets just say, i do this to my BankServiceImpl class:
#Transactional on top of one of the method, accountTransfer(), and
and some custom <aop> pointcut on the execution of another method someOtherMethod().
Then will Spring be able to generate one proxy where accountTransfer() is made transactional and someOtherMethod() is also given aop behaviour?
Does any one has an idea on how Spring resolves multiple AOP behaviors?
It looks like Spring creates a single proxy object with all of the advice types in it. This proxy object will implement the org.springframework.aop.framework.Advised regardless of if it's a JDK dynamic proxy or a CGLIB proxy.
If you have multiple advisors, the order of their execution is undefined unless you make it explict by implementing the Ordered interface or the #Ordered annotation. You can find more on ordering here. Springs transactional aspects default to lowest priority.