How to inject application context into AspectJ aspects? - java

How can I inject beans into a real AspectJ aspect using an annotation based application context?
I've created an aspect with AspectJ that implements ApplicationContextAware to access spring beans. Whenever the new-operator of a specified class is invoked, the aspect should inject a spring bean into the newly created instance.
To inject the application context into the aspect, Spring needs a handle to this aspect. The aspect itself is not created by spring but by the AspectJ runtime.
In an xml based application context one can achieve this by
<bean class="SomeAspectClass"
factory-method="aspectOf">
</bean>
But how can I do this in an annotation based context?
My current workaround is to provide an xml based context that contains just this bean definition and merge it into my annotation based application context. But I just want to solve this with my annotation based context.

As avery aspect has a static method 'aspectOf' to access its unique instance, just use reflection to invoke 'aspectOf' and get this instance.

Related

Why you have to anotate classes in Spring boot with service etc.?

Everyone says that it's because spring boot in that case will know that service exists. But if you call that service's method in another method that you try to run when the web app is running. Should it know the service exists without the annotation or not?
The main reason you put these stereotype annotations to classes is creating beans in application context and let the IOC container to provide the management and configuration of these beans depending on their stereotypes.
Spring is an IOC container responsible for instantiating, configuring and assembling these beans. And putting stereotype annotation is just a way to define bean.
You can define beans in various ways such as using #Bean annotation, stereotype annotations, XML definitions etc. and if you don't define your bean, the IOC container can not detect and instantiate the service.

Can I inject properties to third-party beans?

Suppose I have classes, which were instantiated not by Spring. For example, they can be instantiated by deserializer or by JavaFX.
Can I code these classes in the same way I code Spring beans and inject properties into them later?
Actually, I would like a routine, which would scan class with reflection, find all #Autowired annotations in it and inject values from application context?
Will this happen, if I call applicationContext.getBeanFactory().registerSingleton("myName", myBean)? Note, that I would no limit myself with singletons.
If beans are not instantiated by Spring, then you cannot ask Spring to inject dependencies or advise them.
This is a common mistake I see Spring neophytes make. They call new to instantiate a bean with annotations and can't understand why their dependencies aren't injected.
Spring will handle all the beans you instantiate with the bean factory. You are on your own with all others created using new.

Where do those beans returned by Spring getBean method come from?

Could you please list all possible sources of getBean?
BTW, If I just write context.getBean(SomeInterface.class), can I get the implementation of the interface class?
They come from the Spring application context (which is what you are calling the getBean method on).
Spring has this concept of an application context, which is an object that contains things such as all the beans managed by Spring.
You put beans in the application context by configuring them in a Spring XML configuration file or by annotating classes with annotations such as #Component, #Service etc. and then letting Spring find them by scanning packages for those classes.
If you write context.getBean(SomeInterface.class) and there is a Spring bean that implements that interface, then that method call will return the bean that implements the interface.
These are basic concepts of the Spring framework. See chapter 5, The IoC Container in the Spring documentation for a detailed explanation of how it works.
If you go into the ApplicationContext class hierarchy, you will find that all spring Application Context file are child of org.springframework.core.io.DefaultResourceLoader class.
What DefaultResourceLoader does is it get the current thread context class loader(if none is provided). So we can understand that all application context file first load the classes defined. Application Context load all the beans defined in xml file, marked using #Bean annotation or other available spring annotations. Once the context scan through the annotation and/ or xml and load all the beans in the class loader. Context first create the dependencies and inject them in dependent.
To get context.getBean(SomeInterface.class), please refer below documentation.
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/context/support/AbstractApplicationContext.html#getBean(java.lang.Class)
As per my understanding of documentation, you shall get the bean if exact one implementation bean class is defined.

Difference between JavaBean and Spring bean

I am new to Spring MVC and have a little idea of the usage of java beans in Java.
What is the basic difference between a Java bean and Spring bean?
JavaBeans:
At a basic level, JavaBeans are simply Java classes which adhere to certain coding conventions. Specifically, classes that
have public default (no argument) constructors
allow access to their properties using accessor (getter and setter) methods
implement java.io.Serializable
Spring Beans:
A Spring bean is basically an object managed by Spring. More specifically, it is an object that is instantiated, configured and otherwise managed by a Spring Framework container. Spring beans are defined in Spring configuration files (or, more recently, with annotations), instantiated by Spring containers, and then injected into applications.
Note that Spring beans need not always be JavaBeans. Spring beans might not implement the java.io.Serializable interface, can have arguments in their constructors, etc.
This is the very basic difference between JavaBeans and Spring beans.
For more information, refer to the source of the above text, Shaun Abram's article JavaBeans vs Spring beans vs POJOs.
Java bean is a class that should follow following conventions:
1.Must implement Serializable.
2.It should have a public no-arg constructor.
3.All properties in java bean must be private with public getters and setter methods.
Spring beans are the objects that form the backbone of your application and are managed by the Spring IoC container .
Spring Bean:
A class which is developed as part of a spring application. Its life cycle which is managed by Spring Container is called as Spring Bean.
Java beans and Spring beans are more related than different.
For a Java class to be usable as a Java bean, its setter- and getter-method names need to be as per the JavaBean guidelines (also called design patterns) for properties. If such a Java class is instantiable & manageable by the Spring IoC container, it is a Spring bean. To achieve this, the programmer wires the class as a bean definition of a suitable scope by using XML config files or annotations or a mix of both. The programmer can create new Spring beans out of existing Spring beans by wiring further by passing the latter to constructor-arguments of the former either as string-names as <idref> elements or by dependency injection (it can be recursive).
This answer may be read in conjunction with my this SO answer to get more background information.

Enable Spring AOP or AspectJ

This is following on from this question:
Spring autowired bean for #Aspect aspect is null
My initial understanding was that when using Spring AOP, classes annotated with #Aspect are created as spring managed beans, so dependency injection would work as normal. However it seems that an object with the #Aspect annotation is created as a singleton outside the spring container, hence me having to configure it in XML like so in order to enable it as a spring managed bean:
<bean id="aspect" class="com.mysite.aspect" factory-method="aspectOf" />
This has now completely confused me. I thought the following configuration would use spring AOP:
<context:component-scan base-package="com.mysite.aspectPackage"/>
<aop:aspectj-autoproxy/>
So it would scan for #Aspect annotations using component-scan creating aspect beans, and then autoproxy would create a beanPostProcessor which proxies all beans within my context with the appropriate advice. I then thought to enable aspectJ I would need a completely different XML configuration (which incidentally I can't seem to find an example of in the documentation). It would be this configuration that uses aspectJ to create aspects that would be outside of my container or which work by manipulating bytecode rather than proxying.
Note
This is not a question on the difference between spring AOP and aspect J, this is well articulated here:
Spring AOP vs AspectJ
#Aspect is not a spring annotation, and it is not detected by component-scan. So you have to register it somehow as a spring bean. The aspectOf solution works. You can also try
#Aspect
#Component
#Component will create 2 instances, one inside the Spring container, one inside the aspectJ container.
use #Configurable to allow spring to manage dependency injection etc. for your class when instantiated by the aspectj container.
#Aspect is an aspectj style annotation that is supported by spring-aop, where runtime weaving is used to handle interception etc.
Compile-time weaving allows you to disregard the use of as pointcuts will be present in the bytecode, this is done via the aspectj compiler (See https://www.mojohaus.org/aspectj-maven-plugin/ for mvn integration) .
Whether you use the aspectj compiler or spring-aop makes no difference, it wont create your aspect as a managed bean in the way you want unless you use factory / configurable.
Aspectj configuration is, strictly, the pointcut definitions etc that will be present inside your class.

Categories