| Prev | 6. AOP 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
@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>