Wer „Spring“ hört, denkt meistens sofort an riesige XML-Konfigurationen, und der ein oder andere verspürt das Bedürfnis, direkt über Spring herziehen zu müssen. Tatsächlich kann man aber inzwischen so ziemlich alles auch per Annotations konfigurieren.
Hin und wieder kommt man aber nicht umher, beides zu mischen – z.B. wenn es darum geht ein altes Projekt nach und nach zu refactoren und nicht alles auf einmal vom Kopf auf die Füße gestellt werden soll oder kann.
Dabei das wichtigste direkt vorweg. Wenn es nur darum geht per context:component-scan und context:annotation-config bestehende Beans zu erzeugen und zu injecten, dann ist das ohne weiteres möglich. Im Prinzip sind nur 4 Zeilen Code:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); Resource contextResource = new ClassPathResource("context/context-core.xml"); xmlBeanDefinitionReader.loadBeanDefinitions(contextResource);
Das XML muss dabei im günstigen Fall nicht komplexer aussehen als:
<?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> <context:component-scan base-package="de.flaviait.testfw" /> </beans>
Spannender wird es aber, wenn noch Klassen existieren, die ihrerseits als BeanFactory fungieren bzw. per Annotation als solche definiert wurden. Bspw.:
@Configuration public class ExampleBeanProvider { @Bean public ExampleBean exampleBean() { new ExampleBean(); } }
Die Zuvor geschilderte Konfiguration würde zwar eine Bean für ExampleBeanProvider erzeugen, nicht aber für ExampleBean.
Um das zu lösen, müssen wir den Annotations dediziert zu Leibe rücken. Zum Beispiel mit einem AnnotationConfigApplicationContext:
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("de.flaviait");
Wird der Classpath im Constructor angegeben, wird direkt ein Scan durchgeführt. Alternativ könnte man das auch später tun:
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); annotationConfigApplicationContext.scan("de.flaviait"); annotationConfigApplicationContext.refresh();
Da wir natürlich für die Beans aus der XML-Konfiguration die selbe BeanFactory benutzen möchten, müssen wir zum Parsen etwas anders vorgehen, indem wir keine neue DefaultListableBeanFactory erzeugen, sondern die aus dem Context benutzen:
DefaultListableBeanFactory beanFactory = annotationConfigApplicationContext.getDefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); Resource contextResource = new ClassPathResource("context/context-core.xml"); xmlBeanDefinitionReader.loadBeanDefinitions(contextResource);
Zu beachten wäre dabei nur noch, dass der AnnotationConfigApplicationContext natürlich zuerst zum Zug kommt. Das ist wichtig, weil es zu Problemen führen kann. Zum Beispiel wenn man spring-aop benutzen möchte und den Aspect per Annotation konfiguriert aber die aop-config in der XML definiert. Aber dazu mehr in einem anderen Blogeintrag über gewisse Eigenarten von spring-aop und mögliche Fallstricke.
Eine Antwort