Einsatz von Spring mit EJB 3.0
Einführung
Spring ist eines der am weitesten verbreiteten Java-Frameworks und wird insbesondere bei vielen Java-Projekten im Enterprise-Bereich verwendet.
Obwohl das Framework mittlerweile ein sehr breites Spektrum an Funktionalitäten abdeckt, ist der IoC Container (Inversion of Control) nach wie vor die am meisten eingesetzte Kern-Funktionalität von Spring.
Auch exensio nutzt die IoC-Funktionalitäten zur Erreichung einer losen Koppelung und insbesondere um Backend-Implementierungen über
Konfigurationen austauschbar zu machen.
Bei Web-Applikationen wird hierbei die Konfigurationsdatei für Spring in den meisten Fällen mit Hilfe eines Listener-Eintrags in der Datei web.xml geladen.
Doch wie lädt man eigentlich Spring-Konfigurationen in EJB-Projekten?
Spring und EJB 3.0
Zunächst ein einfaches Szenario: In einem EJB-Projekt existieren mehrere Session-Beans, die unter anderem auch Methoden eines Such-Service und eines CMS-Service aufrufen. Die Services sind zu Beginn eines Projektes noch nicht verfügbar und deshalb werden zunächst Mockup-Implementierungen eingesetzt. Um zu einem späteren Zeitpunkt einfach zwischen den Mockup und den richtigen Implementierungen switchen zu können erfolgt die Konfiguration über Spring.
Die nachfolgende Datei (serviceProviderContext.xml) zeigt die Konfiguration der Spring-Beans.
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="searchService" class="com.exensio.service.search.SearchService">
<property name="servers" value="ex_fast:15100,ex_fast2:15100"></property>
</bean>
<bean id="contentService" class="com.exensio.service.content.CMSService">
</bean>
</beans>
Relativ einfach funktioniert das Laden einer Spring-Konfiguration natürlich "von Hand", wie nachfolgend dargestellt:
public UserSearchService() {
ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext("serviceProviderContext.xml");
searchService = (SearchService)beanFactory.getBean("searchService");
}
Dass dies nicht besonders schön ist liegt auf der Hand. Werden der Such- und der CMS-Service von mehreren Session-Beans verwendet, dann muss des Weiteren in jeder Session-Bean der Ladevorgang und die Zuweisung erfolgen.
Deshalb stellt sich die Frage, ob dies auch eleganter funktioniert?
Wiring mit Interzeptoren
Mit EJB 3.0 wurden Interzeptoren eingeführt, mit deren Hilfe Spring-Konfiguration geladen werden können. Spring stellt hierfür den SpringBeanAutowiringInterceptor zur Verfügung, der bei Bedarf auch erweitert werden kann. Der Spring-Interzeptor muss hierfür der EJB 3.0 Annotation @Interceptors zugewiesen werden. Das Binding des Interzeptors kann alternativ neben der Annotation @Interceptors auch über den EJB Deployment Descriptor (ejb-jar.xml) vorgenommen werden.
Nachfolgend wird das Binding an den Interzeptor an einer Session-Bean illustriert, die über @Autowiring auch den Such-Service injiziert bekommt.
@Stateless(mappedName = "UserSearchService")
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class UserSearchService implements UserSearchServiceLocal {
@Autowired
private SearchService searchService;
public List<string> getSortFields() {
return searchService.getSortFields();
}
}
</string>
Der SpringBeanAutowiringInterceptor erwartet standardmäßig eine Datei mit dem Namen beanRefContext.xml im Klassenpfad. Diese nachfolgend dargestellte Datei verweist wiederum auf die eigentliche Konfigurationsdatei aus der die zu injizierdenden Service-Klassen entnommen werden.
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="ejb-context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="serviceProviderContext.xml" type="java.lang.String">
</constructor-arg></bean>
</beans>