I've been using XML based configuration for a while - we've got a Vaadin application with Spring used as DI, but we are not interested in DispacherServlet
- only root context, which we use to inject global (not user owned dependencies).
The way it works
I've defined root-context.xml
file with content:
<context:annotation-config />
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.example" />
And my web.xml
has in it:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then, some of my classes are defined with @Component
annotation and others with @Configurable
(the latter mostly belong to user session, so require DI for each instance created with new
keyword).
I've got context.xml
file with line:
<Loader delegate="false" loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />
And spring-instrument-tomcat-3.2.1.RELEASE.jar
in Tomcat's lib
directory.
All the dependencies are injected (with @Autowire
) to my @Configurable
classes correctly.
The way it doesn't work
Recently I've tried to get rid of root-context.xml
and move context initialisation to Java @Configuration
class.
I've created a class as follows:
@Configuration
@EnableSpringConfigured
@EnableLoadTimeWeaving
@ComponentScan("com.example")
public class BeansConfiguration
{
}
In addition I changed web.xml
entries:
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.spring.BeansConfiguration</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Unfortunately, strange things started to happen. Let me show you an example. Simplifying my class structure looks as follows:
@Component
public class ComponentA
{
}
@Configurable
public class BeanB
{
@Autowired
private ComponentA componentA;
}
@Configurable
public class BeanC
{
@Autowired
private ComponentA componentA;
private BeanB beanB;
public BeanC(BeanB beanB)
{
this.beanB = beanB;
}
}
@Configurable
public class Application
{
@Autowired
private ComponentA componentA;
public Application()
{
}
public void init()
{
BeanC beanC = new BeanC(new BeanB());
}
}
With the XML setup, when it does work, ComponentA
is correctly injected by Spring into all my @Configurable
objects.
Strangely, with annotation-only configuration BeanC
doesn't get the ComponentA
injected (it's always null
), howewer BeanB
and Application
do get that!
Have you got any ideas why would it happen? As soon as I comment out lines in web.xml
to go back to my previous (XML-based) configuration all starts to work.
My happy guess is that XML Spring entries register something more under the cover than their annotation based counterparts. I've spend half a day trying to find out, what could that be, but I gave up. I would appreciate any suggestions.