Bis Spring 2.0 gab es im Wesentlichen nur eine Möglichkeit, Spring-Beans zu deklarieren und Bean-Referenzen zu injizieren. Ab Spring 2.0 und besonders in Spring 2.5 gibt es einen Richtungswechsel. Statt Bean-Definitionen und Injizierungsanweisungen ausschließlich über XML-Dokumente zu beschreiben, kommen Annotationen hinzu. Spring nutzt zum Einen Standard-Annotationen aus Java 6 (Common Annoations) aber auch eigene.
Nehmen wir zwei Beans an:
<bean id="today" class="java.util.Date" />
<bean id="calendarPrinter"
class="com.tutego.spring.annotation.CalendarPrinter" />
Die Bean CalendarPrinter soll ein Datum injiziert bekommen.
public class CalendarPrinter {
public void setDate( Date date ) …
Über XML lässt sich das einfach beschreiben, doch seit Spring 2.5 veranlasst eine Annotation Spring dazu, die Verweise automatisch zu injizieren:
@Autowired
@Autowired ist eine Annotation für Methoden und Attribute, damit Spring selbständig den Verweis setzt:
public class CalendarPrinter {
@Autowired
public void setDate(@Qualifier("today") Date d) …
}
Die Annotation @Qualifier ist nur dann nötig, wenn es mehrere Beans dieses Typs gibt. (Nicht bei uns.)
Damit Spring überhaupt die Verknüpfung vornimmt, ist in der XML-Datei ein Hinweis zu setzen.
Die erste Möglichkeit ist:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
Eine im Allgemeinen bessere Alternative (die AutowiredAnnotationBeanPostProcessor und CommonAnnotationBeanPostProcessor zusammenfasst) ist
<context:annotation-config/>
Die Annotation @Autowired ist genauso gültig bei Attributen:
public class CalendarPrinter
{
@Autowired Date date;
public void doIt()
{
System.out.println( date );
}
}
<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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="today" class="java.util.Date" />
<bean id="calendarPrinter" class="com.tutego.spring.annotation.CalendarPrinter" />
</beans>
Java 6 (für Java 5 ist ein Extra-Jar nötig) führt aus JSR-250 die Lebenszyklus-Annotationen @PostConstruct und @PreDestroy sowie @Resource ein.
public class CalendarPrinter {
@PostConstruct public void initialize() {
System.out.println( "init" );
}
/* @PreDestroy public void remove() {
System.out.println( "destroy" );
} */
}
Beans deklarieren
Die Verknüpfung ist durch Autowire automatisiert und minimiert die XML-Konfigurationsdatei.
Zum Deklarieren von neuen Beans bringt Spring ebenfalls Annotationen mit.
Statt in der XML-Datei zu schreiben
<bean id="calendarPrinter" class="com.tutego.spring.annotation.CalendarPrinter" />
können wir annotieren:
@Component class CalendarPrinter
Damit Spring nach annotierten Beans sucht, ist nötig:
<context:component-scan base-package="com.tutego.spring" />
Die Annotation @Component ist an allen Typen erlaubt und natürlich zur Laufzeit sichtbar:
@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
public @interface Component
{
String value();
}
API zur Eigenschaft: „The value may indicate a suggestion for a logical component name, to be turned into a Spring bean in case of an autodetected component.“
Geben wir dem CalendarPrinter den Bean-Namen „ cal-printer“:
@Component("cal-printer")
public class CalendarPrinter
Aus dem ApplicationContext genommen folgt:
ApplicationContext context =
new ClassPathXmlApplicationContext( … );
Object bean = context.getBean( "cal-printer" );
System.out.println( bean.getClass() );
// class com.tutego.spring.annotation.CalendarPrinter
@Component ist eine sehr allgemeine Annotation.
Besser ist es, semantische Annotationen zu nutzen, die @Component erweitern. Spring liefert drei mit:
- @Target(value=TYPE) … @Component
public @interface Repository - @Target(value=TYPE) … @Component
public @interface Service - @Target(value=TYPE) … @Component
public @interface Controller