Thomas Darimont
Erfahrenes Mitglied
Hallo!
Hier mal ein Beispiel für die Realisierung einer auf Springframework / Hibernate
basierenden Anwendung die OSGi-Bundles als Modularisierungs- und Eclipse ExtensionPoints
als flexiblen Erweiterungsmechanismus verwendet und auf der Equinox OSGi-Runtime von Eclipse läuft.
Das Springframework bietet mit Spring-OSGi ( http://www.springframework.org/osgi ) eine Alternative OSGi Integration an auf die ich hier nicht näher eingehe.
Aufgrund der statischen Natur dieses Ansatzes wird das dynamische starten/stoppen von Anwendungsmodulen (Bundles) nicht unterstützt.
In unserem Szenario haben wir 3 Bundles (Eclipse Plugins):
Anwendung bereit. Beispielsweise enthält das framework Bundle die Konfiguration der
Hibernate-Laufzeit, die Definition der Hibernate SessionFactory, die Definiton der
DataSource und eines TransactionManagers.
Das framework.libraries Plugin stellt die vom Framework benötigten Bilbiotheken bereit.
Das masterdata Plugin beinhaltet in unserem Beispiel einen einfachen Dienst zum
anlegen und auffinden von Personen der die Anfragen an ein entsprechendes DAO übergibt welches von HibernateDAOSupport abgeleitet ist und an ein HibernateTemplate delegiert. Dieser Dienst ist in einem eigenen Application-Context Konfigurationsfile konfiguriert.
In diesem Beispiel werden mehrere AplicationContext-Definitonen (aus unterschiedlichen Bundles) zur Laufzeit zu einem zentralen Spring-ApplicationContext zusammengefasst. Die einzelnen ApplicationContext-Konfigurationsfiles werden über einen eigenen Eclipse ExtensionPoint de.tutorials.framework.applicationContexts bereitgestellt und beim Start des framework-Bundles zur Erzeugung eines neuen ApplicationContexts verwendet.
So ist es möglich Bundle-übergreifend BeanDefinition aus anderen ApplicationContext-Konfigurationsdateien zu verwenden.
(In diesem Beispiel greife ich beispielsweise in der masterdata ApplicationContext Definition auf die SessionFactory und den TransactionManager zurück der im framework Bundle definiert ist.)
Soweit so gut, nun haben wir bei der Erzeugung unseres zentralen ApplicationContexts alle ApplicationContext-Konfigurationsfiles der entsprechenden Bundles vorliegen. Nun ist die Frage wie bekommen wir die Hibernate-MappingLocations, die wir für die Konfiguration der Sessionfactory benötigen, über alle Bundles zum Zeitpunkt der ApplicationContext Erzeugung?
Ganz einfach Wir verwenden auch hier den ExtensionPoint Mechanismus von Eclipse
und stellen die HibernateMappingDirectoryLocations zu Verfügung. Dazu definieren wir
nun den ExtensionPoint de.tutorials.framework.hibernateMappingLocations.
So haben wir nun auch die HibernateMapingLocations über alle Bundles zum Zeitpunkt der ApplicationContext Erzeugung verfügbar.
Wie können wir es nun schaffen die HibernateMappingLocations für das im framework-context konfigurierte LocalSessionFactoryBean in das Property mappingDirectoryLocations zu stecken?
Eine Möglichkeit wäre beispielsweise auszunutzen, dass das mappingDirectoryLocations
Property eine <list> Element entgegennimmt. D.h. wir könnten ein eigenes Bean definieren dass das List Interface implementiert und dieses dann per ref-Attribut in das mappingDirectoryLocations Property schieben.
In meinem Beispiel schaut das Teil dann wie folgt aus:
Mein framework-context.xml im de.tutorials.framework Bundle:
Damit triggert die Erzeugung des ApplicationContexts durch das starten des Framework-Plugins implizit das ermitteln der über den de.tutorials.framework.hibernateMappingLocations bereitgestellten HibernateMappingLocations an. Somit sind die Bundle-übergreifenden Hibernate-MappingLocations nun auch in der
Springkonfiguraton verfügbar.
Mein masterdata-context.xml im de.tutorials.masterdata Bundle
Im Anhang finden sich die Beispiel Projekte zu den entsprechenden Bundles.
Aus dem framework.libraries Bundle habe ich Third-Party jars herausgenommen um die maximale Uploadgrenze nicht zu überschreiten. Die benötigten jars sollten über die Classpath einträge und dem Screenshot ersichtlich sein.
Die detaillierte Konfiguration des BuddyClassLoadings / der Plugin Abhängigkeiten, die Definition der Extension-Points und der exportieren packages kann man den Beispielen entnehmen.
Um das Beispiel auszuführen muss man die Verbindungsinformationen im de.tutorials.framework Bundle unter config/jdbc.properties entsprechend anpassen und folgende Tabelle anlegen:
Gruß Tom
Hier mal ein Beispiel für die Realisierung einer auf Springframework / Hibernate
basierenden Anwendung die OSGi-Bundles als Modularisierungs- und Eclipse ExtensionPoints
als flexiblen Erweiterungsmechanismus verwendet und auf der Equinox OSGi-Runtime von Eclipse läuft.
Das Springframework bietet mit Spring-OSGi ( http://www.springframework.org/osgi ) eine Alternative OSGi Integration an auf die ich hier nicht näher eingehe.
Aufgrund der statischen Natur dieses Ansatzes wird das dynamische starten/stoppen von Anwendungsmodulen (Bundles) nicht unterstützt.
In unserem Szenario haben wir 3 Bundles (Eclipse Plugins):
- de.tutorials.framework
- de.tutorials.framework.libraries
- de.tutorials.masterdata
Anwendung bereit. Beispielsweise enthält das framework Bundle die Konfiguration der
Hibernate-Laufzeit, die Definition der Hibernate SessionFactory, die Definiton der
DataSource und eines TransactionManagers.
Das framework.libraries Plugin stellt die vom Framework benötigten Bilbiotheken bereit.
Das masterdata Plugin beinhaltet in unserem Beispiel einen einfachen Dienst zum
anlegen und auffinden von Personen der die Anfragen an ein entsprechendes DAO übergibt welches von HibernateDAOSupport abgeleitet ist und an ein HibernateTemplate delegiert. Dieser Dienst ist in einem eigenen Application-Context Konfigurationsfile konfiguriert.
In diesem Beispiel werden mehrere AplicationContext-Definitonen (aus unterschiedlichen Bundles) zur Laufzeit zu einem zentralen Spring-ApplicationContext zusammengefasst. Die einzelnen ApplicationContext-Konfigurationsfiles werden über einen eigenen Eclipse ExtensionPoint de.tutorials.framework.applicationContexts bereitgestellt und beim Start des framework-Bundles zur Erzeugung eines neuen ApplicationContexts verwendet.
So ist es möglich Bundle-übergreifend BeanDefinition aus anderen ApplicationContext-Konfigurationsdateien zu verwenden.
(In diesem Beispiel greife ich beispielsweise in der masterdata ApplicationContext Definition auf die SessionFactory und den TransactionManager zurück der im framework Bundle definiert ist.)
Soweit so gut, nun haben wir bei der Erzeugung unseres zentralen ApplicationContexts alle ApplicationContext-Konfigurationsfiles der entsprechenden Bundles vorliegen. Nun ist die Frage wie bekommen wir die Hibernate-MappingLocations, die wir für die Konfiguration der Sessionfactory benötigen, über alle Bundles zum Zeitpunkt der ApplicationContext Erzeugung?
Ganz einfach Wir verwenden auch hier den ExtensionPoint Mechanismus von Eclipse
und stellen die HibernateMappingDirectoryLocations zu Verfügung. Dazu definieren wir
nun den ExtensionPoint de.tutorials.framework.hibernateMappingLocations.
So haben wir nun auch die HibernateMapingLocations über alle Bundles zum Zeitpunkt der ApplicationContext Erzeugung verfügbar.
Wie können wir es nun schaffen die HibernateMappingLocations für das im framework-context konfigurierte LocalSessionFactoryBean in das Property mappingDirectoryLocations zu stecken?
Eine Möglichkeit wäre beispielsweise auszunutzen, dass das mappingDirectoryLocations
Property eine <list> Element entgegennimmt. D.h. wir könnten ein eigenes Bean definieren dass das List Interface implementiert und dieses dann per ref-Attribut in das mappingDirectoryLocations Property schieben.
In meinem Beispiel schaut das Teil dann wie folgt aus:
Java:
/**
*
*/
package de.tutorials.framework.util.hibernate;
import java.util.ArrayList;
import java.util.Collections;
import de.tutorials.framework.osgi.Activator;
/**
* @author Tom
*
*/
public class HibernateMappingLocationProvider extends ArrayList<String> {
/**
*
*/
private static final long serialVersionUID = 2740757538764255296L;
public HibernateMappingLocationProvider() {
Collections.addAll(this, Activator.getDefault()
.getContributedHibernateMappingLocations());
}
}
Mein framework-context.xml im de.tutorials.framework Bundle:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Application context definition for JPetStore's business layer.
- Contains bean references to the transaction manager and to the DAOs in
- dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").
-->
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="config/jdbc.properties"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingDirectoryLocations">
<bean class="de.tutorials.framework.util.hibernate.HibernateMappingLocationProvider"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
Damit triggert die Erzeugung des ApplicationContexts durch das starten des Framework-Plugins implizit das ermitteln der über den de.tutorials.framework.hibernateMappingLocations bereitgestellten HibernateMappingLocations an. Somit sind die Bundle-übergreifenden Hibernate-MappingLocations nun auch in der
Springkonfiguraton verfügbar.
Mein masterdata-context.xml im de.tutorials.masterdata Bundle
XML:
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Application context definition for JPetStore's business layer.
- Contains bean references to the transaction manager and to the DAOs in
- dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").
-->
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
default-lazy-init="true">
<bean name="personService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<bean class="de.tutorials.masterdata.services.internal.PersonService">
<property name="personDAO">
<ref bean="personDAO"/>
</property>
</bean>
</property>
<property name="proxyInterfaces">
<list>
<value>de.tutorials.masterdata.services.IPersonService</value>
</list>
</property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean name="personDAO" class="de.tutorials.masterdata.dao.internal.PersonDAO">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
</beans>
Im Anhang finden sich die Beispiel Projekte zu den entsprechenden Bundles.
Aus dem framework.libraries Bundle habe ich Third-Party jars herausgenommen um die maximale Uploadgrenze nicht zu überschreiten. Die benötigten jars sollten über die Classpath einträge und dem Screenshot ersichtlich sein.
Die detaillierte Konfiguration des BuddyClassLoadings / der Plugin Abhängigkeiten, die Definition der Extension-Points und der exportieren packages kann man den Beispielen entnehmen.
Um das Beispiel auszuführen muss man die Verbindungsinformationen im de.tutorials.framework Bundle unter config/jdbc.properties entsprechend anpassen und folgende Tabelle anlegen:
SQL:
create table person(id int null auto_increment, firstname varchar(255), lastname varchar(255), primary key(id));
Gruß Tom
Anhänge
Zuletzt bearbeitet von einem Moderator: