As a followup to yesterday's post about using Spring 2.1's annotation injection, I'm now ready to show you how to get rid of the XML altogether.
When we last saw our Spring XML file (ctx.xml in the downloadable example), it looked like this:
<?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:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.1.xsd"> <context:component-scan base-package="com.springinaction.chapter01.knight" /> <aop:aspectj-autoproxy/> </beans>
I had eliminated all of the app-specific beans ("knight", "quest", "minstrel") and had replaced them with only two infrastructural elements. <context:component-scan> to automatically scan for and load classes annotated with @Component, @Repository, or @Aspect; and <aop:aspectj-autoproxy> to automatically create proxies for any beans annotated with @Aspect.
You can now delete that XML file...we won't be needing it anymore. We can get the same behavior of <context:component-scan> by changing the main() method to look like this:
package com.springinaction.chapter01.knight; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.support.GenericApplicationContext; public class KnightApp { public static void main(String[] args) throws Exception { GenericApplicationContext ctx = new GenericApplicationContext(); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(ctx); scanner.scan("com.springinaction.chapter01.knight"); ctx.refresh(); Knight knight = (Knight) ctx.getBean("knight"); knight.embarkOnQuest(); } }
Previously, I was using a ClassPathXmlApplicationContext to load the Spring definition from an XML file in the classpath. But since the XML is going away completely, we won't need that application context class anymore. This time I'm using GenericApplicationContext...it doesn't load anything. Instead, we'll load it using ClassPathBeanDefinitionScanner.
ClassPathBeanDefinitionScanner does the work of <context:component-scan> scanning the com.springinaction.chapter01.knight package for classes that are annotated with @Component, @Repository, or @Aspect. When it finds them, it automatically registers them in the Spring context.
After the context has been loaded with all of the bean definitions, I refresh the context to be sure that all of the wiring takes place. Without calling refresh(), the beans are loaded, but not wired together.
Finally, I retrieve the knight bean from the context and invoke the embarkOnQuest() method.
If you run this, you'll notice that the Minstrel aspect doesn't get woven. I haven't figured that one out yet, but I'm really close. Stay tuned. In the meantime, you can download the XML-free version from here. After unzipping it, notice that aside from the Maven POM file, there's no XML to be found in the entire project.
Disclaimer P.S.: As I've stated before, I have no problems with Spring XML and still prefer to configure my Spring apps this way. But I also enjoy trying out the other configuration options and letting my readers choose for themselves.