6.3 Context Spring Configured

Just because some of your code may not be directly configured by Spring doesn't mean you can't still use dependency injection. This may happen if you're working on legacy code that can't fully be ported to be used by Spring or when working in a framework where you don't have control over an class' instantiation (like in a Servlet or Java EE Container). A custom Spring aspect (pointcuts & advice) for AspectJ, context:spring-configured, and @Configurable provide a solution for this situation along with AspectJ's compile-time and load-time weaving.

When enabling AspectJ's compile-time or load-time weaving, Spring's AnnotationBeanConfigurerAspect should be registered to provide advice and can be found in spring-aspects.jar. This jar isn't included in the convenience spring.jar archive and must be included explicitly on the classpath. AnnotationBeanConfigurerAspect will configure any class as it's instantiated with the @Configurable annotation and inject or autowire any beans it needs. The context:spring-configured element configures the AspectJ aspect and indicates which Spring context should be used when giving advice. Only one context can be used to provide advice for each classloader. When using the context:load-time-weaver, it will automatically call the same processing code for context:spring-configured if AnnotationBeanConfigurerAspect is available in the classpath. In this case, it isn't necessary to specify context:spring-configured, although it won't hurt.

The @Configurable annotation has a few different configuration options. It can be configured with an XML based template, using autowiring by name or type, or with annotation-based autowiring. The XML template should be a prototype scoped bean whose class matches this class. By default a class marked with @Configurable annotation will look for a bean definition based on the full class name. In this case the prototype bean template doesn't need to specify an id and then the class attribute will be used as the id. When no other values are passed into @Configurable, there must be only one bean definition of this type if a template is being used. If there is a need to have multiple templates, the name of the bean can be passed into the annotation (ex: @Configurable(“myBean”)).

Autowiring and dependency checking are also available. Autowire by type can be set with @Configurable(autowire=Autowire.BY_TYPE) and by name with @Configurable(autowire=Autowire.BY_NAME). If dependency checking should be used to check if any properties that aren't primitives or collections haven't been set by the injection process, this can be configured with @Configurable(dependencyCheck=true).

Spring considers it preferable to use annotation-based autowiring using @Autowired or @Resource instead of using XML templates and autowiring by type & name. Using @Autowired and @Resource is exactly the same as covered in the annotation-based configuration chapter.

By default the injected values won't be available until after the constructor is run, but if the injected values are really needed for use inside the constructor setting @Configurable(preConstruction=true) will let the values be injected before the body of the constructor is run. Although there is a bit of trick to get the pre-constructor injection to work. The injection must occur on a parent class for the constructor to be able to access the injected values. For example, to inject a person instance the field and setter should be in the parent class.

Example 6.2. Context Spring Configured

Excerpt from chapter06-spring-configurable/src/main/java/org/springbyexample/springindepth/chapter06/springConfigured/PersonContainer.java
                
@Configurable
public class PersonContainer { 
                
            
Excerpt from chapter06-spring-configurable/src/main/java/org/springbyexample/springindepth/chapter06/springConfigured/PersonAutowiredContainer.java
                
@Configurable
public class PersonAutowiredContainer { 

    @Autowired
    protected Person person = null;

...
                
            
Excerpt from chapter06-spring-configurable/src/main/java/org/springbyexample/springindepth/chapter06/AbstractPersonAutowiredConstructor.java
                
public abstract class AbstractPersonAutowiredConstructor { 
    
    @Autowired
    protected Person person = null;

...
                
            
Excerpt from chapter06-spring-configurable/src/main/java/org/springbyexample/springindepth/chapter06/springConfigured/PersonAutowiredConstructorContainer.java
                
@Configurable(preConstruction=true)
public class PersonAutowiredConstructorContainer extends AbstractPersonAutowiredConstructor { 
                
            
chapter06-spring-configurable/src/main/resources/META-INF/aop.xml
                
<!DOCTYPE aspectj PUBLIC
        "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
    <weaver>
        <!-- only weave classes in this package -->
        <include within="org.springbyexample.springindepth.chapter06.springConfigured.*" />
    </weaver>
    <aspects>
        <!-- Spring provided AspectJ aspect (in spring-aspects.jar) -->
        <aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" />
    </aspects>
</aspectj>
                
            
chapter06-spring-configurable/src/main/resources/org/springbyexample/springindepth/chapter06/springConfigured/ConfigurableAnnotationTest-context.xml
                
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>        
    <context:load-time-weaver/>
 
    <bean id="person" class="org.springbyexample.springindepth.bean.Person">
...
    </bean>

    <!-- Template for PersonContainer. -->
    <bean class="org.springbyexample.springindepth.chapter06.springConfigured.PersonContainer"
               scope="prototype">
        <property name="person" ref="person" />
    </bean>

    <!-- Template by name for PersonNameContainer. -->
    <bean id="personNameTemplate"
          class="org.springbyexample.springindepth.chapter06.springConfigured.PersonNameContainer"
          scope="prototype">
        <property name="person" ref="person" />
    </bean>
    <bean id="altPersonNameTemplate"
          class="org.springbyexample.springindepth.chapter06.springConfigured.PersonNameContainer"
          scope="prototype">
        <property name="person">
            <bean class="org.springbyexample.springindepth.bean.Person">
...
            </bean>
        </property>
    </bean>

</beans>