Hibernate-ExtenderまたはHibernate、Spring、およびOSGi







残念ながら、現時点では、HibernateにはOSGi環境での作業に必要な統合メカニズムがありませんが、この方向での進展は顕著です(4番目のブランチでパケットを分割することによる初期OSGiフィクション)。 これにより、独自のメカニズムの開発が促進され、かなりの追加作業が必要になります。



この記事は、興味のある開発者を対象としています。Hibernateを多数のSpring + OSGiで使用するにはどうすればよいですか。 エクステンダーパターンとは何ですか。 特定の動作でClassLoaderを実装する方法。 Spring FrameworkのHibernateでサポートされており、このコードの拡張についても少し説明しています。 もちろん、この記事を読むには、Spring、Hibernate、OSGiのテクノロジーを理解し、マルチスレッド環境でのコード実行の主な問題を理解する必要があります。 OSGi環境でSpring Frameworkを使用することに不慣れな方は、入門記事「OSGiコンテナーでのSpringの使用」を参照してください。



提示されているすべてのコードは、トレーニングプロジェクトの一部であり、そのリンクは記事の最後にあります。 したがって、すぐに使用できるフラグメントではなく、プロトタイプとして提示されたすべての例を検討してください。



エクステンダーパターン





OSGiコンテナで実行されるソフトウェアは、個別のモジュール(バンドル)で構成され、各モジュールが特定の役割を果たします。 あるモジュールが別のモジュールにある複雑なランタイムメカニズムを使用する必要がある場合はどうすればよいですか? 答えは明らかです-OSGiサービスを使用してください。 また、これらのメカニズムで初期化(サーブレットコンテナへのサーブレットの登録、またはこの場合のようにHibernateエンティティのマッピングされたクラスの登録)が必要な場合の対処方法。 この質問に対する答えは、すでにそれほど明白ではありません。 実際、主なオプションは2つだけです。最初のオプション-この初期化を必要とする各モジュールは、独自に呼び出します(たとえば、BundleActivatorから)。 2番目は、OSGiには十分に開発されたイベントシステムがあるため、そのような初期化を必要とするモジュールには、別のモジュールが必要なすべての作業を開始できるいくつかの特徴的なメタデータがあります。 2番目のオプションには明確な利点があります。同じコードの束をモジュール間で分散せず、追加の作業を負担しませんが、この責任を別のモジュールに移します。 実際、Spring DMはこの原則に基づいて機能します。 この動作原理は、Extenderパターン[http://www.aqute.biz/Snippets/Extender]であり、OSGiの世界では非常に一般的です。



C   Extender








Hibernate-Extenderの作業の全体像の説明





Hibernate-Extenderの一般的な作業スキームについて説明し始めます。 まず、メタデータを選択する必要があります。これにより、エクステンダーは、拡張が必要な​​モジュールと非拡張モジュールを区別します。 それをHibernateエンティティのクラスのリストを含むMETA-INF / MANIFEST.MFのEntity-Classes見出しとします(xml-mappingの愛好家は今のところ仕事を辞めます)。 次に、Active状態に入るモジュールとこの状態から出るモジュールからイベントを受け取る必要がありますこれを行うには、OSGiイベントメカニズムを使用し、SynchronousBundleListenerインターフェイスを実装します。 非同期BundleListenerを呼び出す前に、モジュールの状態の変化に即座に応答するために、モジュールからの同期イベントハンドラーを使用します。 同時に、ハンドラーの原因となったスレッドをブロックしないように、イベントを処理するための最短時間を確保する必要があります。 これは、イベントハンドラーがProducerとして機能するProducer-Consumerパターンを実装することで実現されます。このイベントハンドラーは、モジュールに関する情報をConsumerに渡し、Consumerはすべての長い操作を個別のスレッドで実行します。 この場合、Hibernateのランタイム構造を再初期化します。



Extenderメカニズムはかなり一般化されているため、以下の実装はコードの再利用を容易にするために、依存関係反転の原則(SOLID)に従います。



public class Extender implements SynchronousBundleListener { private BundleContext bundleContext; private Executor executor; private BlockingQueue<ExtendedBundle> bundles = new LinkedBlockingQueue<ExtendedBundle>(); private BundleConsumer bundleConsumer; private ExtendedBundleFactory extendedBundleFactory; // getter's  setter's @Override public void bundleChanged(BundleEvent event) { Actions action = null; switch (event.getType()) { case BundleEvent.STARTED: action = Actions.ADDING; break; case BundleEvent.STOPPING: action = Actions.REMOVING; break; }; if (action == null) return; ExtendedBundle extendedBundle = extendedBundleFactory.newExtendedFactory( event.getBundle(), action ); try { bundles.put(extendedBundle); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public void initialize() { getBundleConsumer().initialize(getBundles()); getExecutor().execute(bundleConsumer); getBundleContext().addBundleListener(this); for (Bundle bundle: getBundleContext().getBundles()) { if (Bundle.ACTIVE != bundle.getState()) continue; ExtendedBundle extendedBundle = extendedBundleFactory.newExtendedFactory( bundle, Actions.ADDING ); try { bundles.put(extendedBundle); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } }
      
      







Extenderの実装には、Extender自体がモジュールからのイベントのリスナーとして登録されているBundleContextが含まれます。 エグゼキューターはjava.util.concurrentフレームワークからのエグゼキューターの実装であり、コンシューマーは長期的な操作を実行します。 Producer-Consumer実行スレッドが同期されるBlockingQueueブロッキングキュー。 イベントモジュールのBundleConsumer固有のコンシューマー実装。 ExtendedBundleFactoryファクトリの「拡張」モジュール。



public void initialize()メソッドは、オブジェクトを構築した直後に呼び出されます。 このメソッドでは、Extenderが拡張可能なモジュールの後に起動する場合に備えて、Extenderをハンドラーとして登録し、コンシューマーの実行を開始し、OSGiコンテナーに既にあるモジュールを処理します。



バンドル消費者





BundleConsumerはインターフェースです。このインターフェースを実装するタイプのオブジェクトは、Extenderによってキューに入れられたモジュールを処理する必要があります。



 public interface BundleConsumer extends Runnable { void run(); void initialize( BlockingQueue<ExtendedBundle> newBundles ); }
      
      







上記のコードから、これは追加の初期化メソッドを備えたRunnableであることが明らかです。 void run()メソッドの実装で興味深いことが起こるはずです。 Hibernate-Extenderの大部分の作業を行うこのインターフェイスの特定の実装を見てみましょう。



 public class SessionFactoryCreator implements BundleConsumer { private volatile Extendable extendable; private volatile ExtenderClassLoader extenderClassLoader; private volatile BlockingQueue<ExtendedBundle> newBundles; // getter's, setter's    @Override public void run() { ExtendedBundle bundle = null; while (!Thread.currentThread().isInterrupted()) { try { bundle = newBundles.take(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } if (!bundle.isValidForExtending()) continue; if (Actions.ADDING.equals(bundle.getAction())) { addBundle(bundle); } else if (Actions.REMOVING.equals(bundle.getAction())) { removeBundle(bundle); } } } private void addBundle(ExtendedBundle bundle) { bundle.extend(); extenderClassLoader.addBundle(bundle); extendable.addBundle(bundle); bundle.markAsCompleted(); } private void removeBundle(ExtendedBundle bundle) { bundle.extend(); extendable.removeBundle(bundle); extenderClassLoader.removeBundle(bundle); bundle.markAsCompleted(); } }
      
      







void run()メソッドのメインループは、newBundlesキューを処理します。 キューに拡張可能なモジュールがない場合、newBundles.take()メソッドの呼び出しで実行がブロックされます。 拡張可能なモジュールが表示されると、それらは1つずつ移動します。 これらの各モジュールでisValidForExtending()メソッドが呼び出され、モジュールが拡張に適している場合はtrue値を返す必要があります。 この検証方法は、パッケージの内部リソースへのアクセス(たとえば、I / O操作の呼び出し)にかなり時間がかかるため、Extenderではなくここで呼び出されます。 モジュールが拡張に適している場合、そのモジュールで実行する必要があるアクション(Actions.ADDINGまたはActions.REMOVING)についてメタ情報がチェックされます。 必要なアクションに応じて、追加または削除操作が実行され、モジュールは処理済みとしてマークされます。



メイン処理ループを終了するための条件に読者の注意を引きたい!Thread.currentThread()。IsInterrupted()、割り込みフラグが設定されたときにスレッドが正しく終了することを保証する。 このフラグが使用される別の場所は、発生時にブロッキングメソッドnewBundles.take()によってスローされる例外の処理です。ストリームを中断するためのフラグが設定され、メインループが終了します。



クラス属性は、マルチスレッド環境での可視性を保証するためにvolatileとしてマークされます。 オブジェクトの作成は1つのスレッドで行われ、さらに別のスレッドで使用されます。 BlockingQueueの実装はスレッドセーフであるため、マルチスレッド環境での使用に追加の同期は必要ありません。



HibernateSessionFactoryBean





多数のさまざまなフレームワークが偶然ではありません。 サードパーティの十分にテストされたすぐに使用できるコードを使用すると、開発が大幅に促進されます。 したがって、あまり発明しないようにします。 Spring FrameworkはHibernateとの統合をサポートしています。 この統合の主要なクラスの1つはLocalSessionFactoryBeanです。 セッションファクトリを初期化して作成し、Hibernate APIを使用するコードで使用します。 このクラスにはAnnotationSessionFactoryBeanの子孫があり、アノテーションをサポートする機能を追加します。 後者から、実装を継承します。そのコードを以下に示します。



 public class HibernateSessionFactoryBean extends AnnotationSessionFactoryBean { private SessionFactory sessionFactoryProxy; private Lock sessionFactoryAccessLock = new ReentrantLock(true); private ClassLoader classLoader; private Set<Class<?>> annotatedClasses = new CopyOnWriteArraySet<Class<?>>(); /** *   ClassLoader * @param classLoader */ public void setClassLoader(ClassLoader classLoader) { super.setBeanClassLoader(classLoader); this.classLoader = classLoader; } /** *   ClassLoader    BeanClassLoaderAware * @param beanClassLoader */ @Override public void setBeanClassLoader(ClassLoader beanClassLoader) { } @Override public void afterPropertiesSet() throws Exception { //  ClassLoader ProxyFactory.classLoaderProvider = new ClassLoaderProvider() { public ClassLoader get(ProxyFactory pf) { return HibernateSessionFactoryBean.this.classLoader; } }; super.afterPropertiesSet(); sessionFactoryProxy = createSessionFactoryProxy(); } @Override public SessionFactory getObject() { return sessionFactoryProxy; } /** *    Hibernate */ protected void recreateSessionFactory() throws Exception { sessionFactoryAccessLock .tryLock(3000, TimeUnit.MILLISECONDS); try { //  runtime-   Hibernate super.destroy(); //  runtime-   Hibernate super.afterPropertiesSet(); } finally { sessionFactoryAccessLock.unlock(); } } protected SessionFactory createSessionFactoryProxy() throws InstantiationException, IllegalAccessException, InterruptedException { //     //   SessionFactory  Extendable ProxyFactory sessionFactoryProxyFactory = new ProxyFactory(); sessionFactoryProxyFactory.setInterfaces( new Class[] {SessionFactory.class, Extendable.class} ); //    finalize sessionFactoryProxyFactory.setFilter(new MethodFilter() { public boolean isHandled(Method m) { return !m.getName().equals("finalize"); } }); Class<?> sessionFactoryProxyClass = sessionFactoryProxyFactory.createClass(); MethodHandler mi = new MethodHandler() { public Object invoke( Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { Object result = null; // TCCL ClassLoader defaultClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(classLoader); try { if (thisMethod.getName().contains("addBundle")) { addBundle((HibernateBundle) args[0]); } else if (thisMethod.getName().contains("removeBundle")) { removeBundle((HibernateBundle) args[0]); } else { sessionFactoryAccessLock .tryLock(3000, TimeUnit.MILLISECONDS); try { //   SessionFactory result = thisMethod .invoke(getSessionFactory(), args); } finally { sessionFactoryAccessLock.unlock(); } } } finally { // TCCL    Thread.currentThread() .setContextClassLoader(defaultClassLoader); } return result; } }; SessionFactory sessionFactory = (SessionFactory)sessionFactoryProxyClass.newInstance(); ((ProxyObject)sessionFactory).setHandler(mi); return sessionFactory; } private void addBundle(HibernateBundle bundle) throws Exception { for (String entityClassName: bundle.getEntityClassNames()) { annotatedClasses.add(classLoader.loadClass(entityClassName)); } setAnnotatedClasses( annotatedClasses.toArray( new Class[annotatedClasses.size()])); recreateSessionFactory(); } private void removeBundle(HibernateBundle bundle) throws Exception { for (Class<?> annotatedClass: annotatedClasses) { if (bundle.getEntityClassNames().contains( annotatedClass.getCanonicalName())) { annotatedClasses.remove(annotatedClass); } } setAnnotatedClasses( annotatedClasses.toArray( new Class[annotatedClasses.size()])); recreateSessionFactory(); } }
      
      







このコードを実行するための主な計画は次のとおりです。 AbstractSessionFactoryBeanはFactoryBeanインターフェースを実装し、Springコンテナーでこのインターフェースを実装するクラスオブジェクトの作成を処理することは特別な方法で行われます。 詳細については、Spring Frameworkのドキュメントをご覧ください。 具体的な実装ではなく、単なるSessionFactoryオブジェクトのファクトリーであることだけに言及する価値があります。 LocalSessionFactoryBeanで作成されたSessionFactoryオブジェクトの代わりに、コードは、すべての呼び出しをネイティブSessionFactoryメソッドに転送するプロキシオブジェクトを返しますが、グローバルロックで呼び出しを保護します(このアーキテクチャは、パフォーマンスの観点から作り直すことができます。 ) 拡張可能なモジュールのセットが変更されるたびに、これを考慮してSessionFactoryオブジェクトが再作成されます。



オブジェクトプロキシメソッド呼び出しハンドラーは、スレッドコンテキストクラスローダー(TCCL)オーバーライドを使用します。 TCCLとして、メソッドが呼び出される間、独自のクラスローダーがトピックを設定します。これについては、後で説明します。



OSGiとClassLoader





jvm環境で実行される典型的なアプリケーションでは、クラスローダーは階層的にリンクされ(親を参照)、最初に親への委任によってクラスとリソースをロードし、障害の場合はすでに独立しています。 OSGi環境の場合、この動作は適切ではありません。 同様に、Extenderの場合には適していません。 OSGiコンテナーでは、各モジュールは(モジュール)のニーズを完全に満たす独自のクラスローダーを受け取ります。 また、モジュールクラスローダーは、より複雑な委任ネットワークに接続されます。 このような各ローダーには、フレームワーククラスのローダーと、インポートが実行されるモジュールのローダーへのリンクがあります。 この委任ネットワークは、OSGiコンテナーでの解決プロセスの結果として構築されます。



     OSGi








Extenderの場合、インポートされたエンティティクラスをMANIFEST.MFで宣言することができないため、一般的なモジュールクラスローダーは適していません。 そのようなクラスは、Extender開発の時点では単純に不明です。 したがって、必要な動作を備えた独自のブートローダーを実装する必要があります。 Extenderのクラスローダーコードを以下に示します。



 public class ExtenderClassLoader extends ClassLoader { private volatile ClassLoader defaultClassLoader = null; private Set<ExtendedBundle> bundles = new CopyOnWriteArraySet<ExtendedBundle>(); public ClassLoader getDefaultClassLoader() { return defaultClassLoader; } public void setDefaultClassLoader( ClassLoader defaultClassLoader) { this.defaultClassLoader = defaultClassLoader; } public void addBundle( ExtendedBundle bundle) { bundles.add(bundle); } public void removeBundle(ExtendedBundle bundle) { bundles.remove(bundle); } @Override public Class<?> loadClass( String name) throws ClassNotFoundException { Class<?> c = null; for (ExtendedBundle bundle: bundles) { try { c = bundle.loadClass(name); break; } catch (ClassNotFoundException e) {} } if (c == null && getDefaultClassLoader() != null) { try { c = getDefaultClassLoader().loadClass(name); } catch (ClassNotFoundException e) {} } if (c == null) throw new ClassNotFoundException(name); return c; } //   }
      
      







以下のコードを詳しく見てみましょう。 彼の仕事の主なロジックはloadClassメソッドにあります。 このフラグメントでは省略されているリソースをロードするための同様に実装されたメソッドを強調する必要があります。 ExtenderClassLoaderには、エンティティクラスを含むモジュールのコレクションが含まれ、クラスとリソースのロードをそれらに委任します。 これにより、インポートする必要なく、必要なコードにアクセスできます。 ExtenderClassLoaderは、残りの必要なクラスのロードをデフォルトのブートローダーに委任します。 このコードのスレッドセーフは、多くのCopyOnWriteArraySetおよびスレッドセーフクラスローダーのノンブロッキング実装を使用することで保証されます。



すべてをまとめる





この時点で、読者はHibernate-Extenderの基本要素がどのように機能するかを理解する必要があります。 ここで、すべての部品を一緒に組み立てる必要があります。 これを行うには、spring dmを使用してOSGi環境で動作するようにモジュールを構成する必要があります。 オブジェクトの構成をよりよく理解するために、システムのクラス図を検討してください。



UML-




確立された規範によると、spring dmモジュールの構成は少なくとも2つのファイルに分割されます。 最初は、スプリングコンテナの実際の構成です。 2番目は、OSGi環境に固有の構成です。 私たちの場合、これらはcontext.xmlおよびosgi-context.xmlファイルです。



spring dmのHibernate-Extender構成は、クラス図と同じです。 context.xml構成ファイルの最初に、dataSourceオブジェクトが記述されています-これは、データベースとのすべての対話が実行されるデータソースです。 次に、Spring環境でトランザクションサポートを提供するtransactionManagerオブジェクトの構成があります。 sessionFactoryオブジェクトは、SessionFactoryの作成を担当する上記のHibernateSessionFactoryBeanクラスのインスタンスです。 sessionFactory参照は、transactionManagerに渡されます。 構成内の次のオブジェクトはextenderClassLoaderであり、defaultClassLoaderとして作成されると、デフォルトのクラスローダーがSpring環境にインストールされます。 sessionFactoryCreatorオブジェクトは、モジュールに関する変更されたデータを考慮して、Hibernate環境の再構成を開始するすべての基本的な作業を行います。 モジュールの中心的なオブジェクトはExtenderであり、作成の過程で、オブジェクトへの参照を受け取ります:bundleContext、新しい名前のないExecutor、新しい名前のないExtendedBundleFactoryおよびsessionFactoryCreator。 2番目のosgi-context.xml構成ファイルでは、OSGiサービスが宣言されています:dataSource、transactionManager、sessionFactory。



context.xml

 <?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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:osgi="http://www.springframework.org/schema/osgi" xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton"> <property name="driverClass" value="org.hsqldb.jdbc.JDBCDriver" /> <property name="jdbcUrl" value="jdbc:hsqldb:hsql://localhost/test" /> <property name="user" value="SA" /> <property name="password" value="" /> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" scope="singleton"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="sessionFactory" class="iconcerto.hibernate.HibernateSessionFactoryBean" scope="singleton"> <property name="dataSource" ref="dataSource" /> <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> <property name="classLoader" ref="extenderClassLoader" /> </bean> <bean id="extenderClassLoader" class="iconcerto.extender.ExtenderClassLoader" scope="singleton"> <property name="defaultClassLoader"> <bean class="org.springframework.util.ClassUtils" factory-method="getDefaultClassLoader"/> </property> </bean> <bean id="sessionFactoryCreator" class="iconcerto.hibernate.extender.SessionFactoryCreator" scope="singleton"> <property name="extenderClassLoader" ref="extenderClassLoader" /> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="extender" class="iconcerto.extender.Extender" scope="singleton" init-method="initialize"> <property name="bundleContext" ref="bundleContext" /> <property name="executor"> <bean class="java.util.concurrent.Executors" factory-method="newSingleThreadExecutor" /> </property> <property name="extendedBundleFactory"> <bean class="iconcerto.hibernate.extender.HibernateBundleFactory"/> </property> <property name="bundleConsumer" ref="sessionFactoryCreator" /> </bean> </beans>
      
      







osgi-context.xml



 <?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:osgi="http://www.springframework.org/schema/osgi" xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium-1.2.xsd"> <osgi:service ref="dataSource" interface="javax.sql.DataSource" /> <osgi:service ref="transactionManager"> <osgi:interfaces> <value> org.springframework.transaction.support.ResourceTransactionManager </value> </osgi:interfaces> </osgi:service> <osgi:service ref="sessionFactory" interface="org.hibernate.SessionFactory" /> </beans>
      
      







プロトタイプの欠陥





他のプロトタイプと同様に、Hibernate-Extenderにはいくつかの欠陥があります。 一方で、主要なアイデアを多数の副次的な詳細と混合する場合、主要なアイデアを伝えることは困難です。 一方、実際のアプリケーションでこのコードを使用することを妨げる非常に明らかな欠陥に言及するしかありません。



春の設定から、最初に目を引くのは、context.xmlファイル自体にデータソースのプロパティを直接設定することです。 実際のアプリケーションでは、これを変更する必要があります。 たとえば、プロパティプレースホルダーのSpringメカニズムを使用して外部プロパティファイルからこのデータをインストールするか、実行時にデータベース接続パラメーターに変更を提供するより複雑なシステムを実装します。



上記のリストでは、ロギングの原因となるコードは省略されています。これがないと、モジュールの使用はほとんど考えられません。



説明した実装には、次の重大な欠点があります。 既に拡張されている別のモジュールがHibernate APIを使用して操作を実行し、トランザクション内にあるときに、モジュールが拡張機能に追加されるとどうなりますか? 現在の実装では、このような操作は失敗する運命にありますが、コードでこれを考慮すると、唯一の不便は、もはや関連のないSessionオブジェクトでの操作の呼び出しに関連する特定の例外の処理です。



そして、強調したい最後の欠点は、多くの拡張可能なモジュールへの各変更後に発生するHibernateランタイム環境を再構成するときに発生するパフォーマンスの問題です。



サードパーティのOSGiフィクション





多くのJavaライブラリはすでにOSGiで実行できる状態で出荷されていますが、残念ながらすべてではありません。 この状況から抜け出すには2つの方法があります。サードパーティ(たとえば、SpringSource Enterprise Bundle Repository [http://ebr.springsource.com/repository/app/])によって準備されたOSGi修正バージョンを使用するか、そのようなバージョンのライブラリを自分で準備します。 例のソースコードを含むプロジェクトでは、このような準備が実行されます(サブプロジェクトlib)。 複雑なライブラリの場合、これは決して些細な作業ではないことに注意してください。 サードパーティのコードで使用できるパッケージをエクスポートするには、ライブラリの構造を理解する必要があります。 OSGi環境との互換性が不十分または互換性のない内部ライブラリメカニズムが原因で、追加の問題が発生する場合があります。 しかし、ほとんどすべての場合、これは解決可能なタスクです。 ライブラリアーキテクチャの技術的な問題は手動でしか解決できませんが、エクスポートの問題はさまざまなユーティリティ(bnd、mavenプラグインなど)を使用して自動化できます



おわりに





これで、OSGiでHibernateを操作するエクステンダーアプローチの説明を終了します。 残る唯一のことは、結果のモジュールを使用する方法を追加することです。 META-INF / MANIFEST.MFのEntity-Classesヘッダーの拡張可能モジュールは、完全なHibernateエンティティクラス名のリストを配置する必要があります。 次に、このモジュールを実行すると、ExtenderはClassLoader実装を使用してこれらのクラスをロードし、Hibernateランタイム環境を再初期化します。 さらに、Hibernate APIの使用を必要とするモジュールは、OSGiサービスのSessionFactoryおよびResourceTransactionManagerをインポートする必要があります。 その後、モジュールはSpring環境でHibernate APIを通常の方法で使用できます(公式ガイドに従って)。

エクステンダーの完全なコードと単体テストおよび統合テストは、記事の最後にあるgooglecodeリポジトリから入手できます。 このコードは開発されるので、興味のある人は誰でも変更を追うことができます。 このコードの開発に参加したい人は私に連絡することができます。 さて、いつものように、誰にも質問があります、コメントを歓迎します!



追加のソース





code.google.com/p/iconcerto/source/browse

www.aqute.biz/Bnd/Bnd

www.aqute.biz/Snippets/Extender

static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html

docs.jboss.org/hibernate/core/3.6/reference/en-US/html

static.springsource.org/osgi/docs/1.2.1/reference/html



All Articles