Injecting Spring beans into non-managed objects
Join the DZone community and get the full member experience.
Join For FreeSpring framework brings us two different solutions to achieve such requirement. I'll now describe them both of them. Let's start with with simpler one.
It's especially powerful when we've case such as generic repository, mentioned earlier aggregate factory, or even any other factory just ensuring that we have only few places in our code where will instantiate objects outside of the container. In this case we can make use of AutowireCapableBeanFactory class. In particular we will be interested in two methods:
- void autowireBean(Object existingBean)
- Object initializeBean(Object existingBean, String beanName)
public abstract class GenericFactory<T> { @Autowired private AutowireCapableBeanFactory autowireBeanFactory; public T createBean() { // creation logic autowireBeanFactory.autowireBean(createdBean); return createdBean; } }Simple and powerful - my favorite composition :)
But what can we do when we have plenty places in our code where objects get born? That's for example case of building Vaadin layouts in Spring web application. Injecting custom bean configurer objects invoking autowireBean method won't be the peak of productivity. Happily Spring developers brought us @Configurable annotation. This annotation connected with aspects will configure each annotated object even if we will create it outside of the container using new operator. Like with any other aspects we can choose between
- load-time-waving (LTW)
- compile-time-waving (CTW).
@Configurable public class MyCustomButton extends Button { @Autowired private MyAwesomeService myAwesomeService; // handlers making use of injected service }
The second option is a little bit more complex to setup but after this it will be a lot lighter in runtime. Because now we want to load aspects till compilation we have to integrate aspectj compiler into our build. In Maven you need to add few dependencies:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>3.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>3.2.4.RELEASE</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency>
I hope you are curious why above you can see persistence-api. That was also strange for me, when I saw "can't determine annotations of missing type javax.persistence.Entity" error during aspectj compilation. The answer can be found in SpringFramework JIRA in issue SPR-6819. This happens when you configure spring-aspects as a aspectLibrary in aspectj-maven-plugin. Issue is unresolved for over three year so better get used to it :) The last thing we need to do is to include above-mentioned plugin into our plugins section.
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.5</version> <configuration> <source>1.7</source> <target>1.7</target> <complianceLevel>1.7</complianceLevel> <showWeaveInfo>true</showWeaveInfo> <aspectLibraries> <aspectLibrary> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </aspectLibrary> </aspectLibraries> </configuration> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin>And that's all folks :)
Published at DZone with permission of Jakub Kubrynski, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments