Enterprise Java

Injecting Spring beans into non-managed objects

Advantages coming from dependency injection can be addicting. It’s a lot easier to configure application structure using injections than doing all resolutions manually. It’s hard to resign from it when we have some non-managed classes that are instantiated outside of the container – for example being part of other frameworks like Vaadin UI components or JPA entities. The latter are especially important when we’re using Domain Driven Design. During DDD training ran by Slawek Sobotka we were talking about options to remove “bad coupling” from aggregate factories. I’m sure you’ll admit, that it’s better to have generic mechanism able to “energize” objects by dependencies defined by e.g. @Inject annotation than inject all necessary dependencies into particular factory and then pass them into object by constructor, builder or simple setters.

Spring 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)

The first one just populates our bean without applying specific post processors (e.g. @PostConstruct, etc). The second one additionally applies factory callbacks like setBeanName and setBeanFactory, as well as any other post processors with @PostConstruct of course. In our code it’ll look like this:

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)
  • build-time-waving (BTW).

The first one is easier to configure but we become (due to instrumentation) dependent from application server, which can be undesirable in some cases.  To use it we need to annotate our @Configuration class by @EnableLoadTimeWeaving (or add <context:load-time-weaver/> tag if you like Flintstones and XML configuration) After completing configuration just annotate class by @Configurable:

@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!
 

Reference: Injecting Spring beans into non-managed objects from our JCG partner Jakub Kubrynski at the Java(B)Log blog.

Jakub Kubrynski

I'm software developer by vocation. Java team leader at work and open source enthusiast at home. Strongly interested in new technologies. Fan of java.util.concurrent and sun.misc.Unsafe. My motto is "minimum code, maximum functionality.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tomek N.
10 years ago

Good article. One tiny thing – static weaving is typically called CTW (compile-time weaving), not build-time weaving.

Kuba Kubrynski
10 years ago

Glad you like it. You are right – I’ve just fixed it :)

Binh Nguyen Thanh
Binh Nguyen Thanh
10 years ago

Thanks, nice post.

Steve Solomon
Steve Solomon
9 years ago

Compile-time weaving did not work for me. Neither field injection (@Autowired, with @Qualifier) nor setter injection (@Resource). The maven output indicates a join point and before and after advice in the non-managed class, but at runtime, I get an NPE when the injected field is read, because the expected dependency was not injected. Also, my log4j log file does not have any errors related to the failure to inject the bean.

Back to top button