3

Fuse ESB(Apache ServiceMixおよびKaraf)でOSGIサービスとして公開したいインターフェイスを持つコアライブラリがあります。目標は、他のバンドルがそれを使用できるようにすることです。このサービスはJPA(OpenJPA)とSpringを使用します。インターフェースは次のとおりです。

public interface PatientService {
    public Patient find(Integer id);
}

とクラス:

@Repository
public class PatientServiceJpaImpl implements PatientService {
    @PersistenceContext(unitName="psu")
    private EntityManager entityManager;

    @Override
    public Patient find(Integer id) {
        return entityManager.find(Patient.class, id);
    }
}

以下は省略形META-INF/spring/beans.xmlです:

<beans xmlns="http://www.springframework.org/schema/beans" ...>
    <context:annotation-config />
    <context:component-scan base-package="..." />

    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="emf" />
    </bean>

    <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="psu" />
        <property name="jpaVendorAdapter" ref="jpaAdapter" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter" />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${database.driver}" />
        <property name="url" value="${database.url}" />
        <property name="username" value="${database.username}" />
        <property name="password" value="${database.password}" />
    </bean>

    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>

そしてMETA-INF/persistence.xml(略称):

<persistence xmlns="http://java.sun.com/xml/ns/persistence" ...>
    <persistence-unit name="psu" transaction-type="RESOURCE_LOCAL">
        <class>...</class>
</persistence>

OSGi以外の環境では、すべてがうまく機能します。これはfelixmaven-bundle-pluginを使用するため、OSGiサービスを作成するために、以下を追加しましたOSGI-INF/blueprint/osgi-context.xml

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0
    http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

    <bean id="patientService" class="com.test.service.PatientServiceJpaImpl" />
    <service id="osgiPatientService" ref="patientService" interface="com.test.service.PatientService" />

</blueprint>

バンドルが正常にデプロイされ、サービスが登録されます。問題は、PatientServiceが別のバンドルから参照されている場合、エンティティマネージャーが挿入されていないためNullPointerExceptionfind(Integer id)メソッドにがスローされることです。以下は、消費者の抜粋ですMETA-INF/spring/consumer-context.xml

<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:jaxws="http://cxf.apache.org/jaxws"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://cxf.apache.org/jaxws
    http://cxf.apache.org/schemas/jaxws.xsd
    http://www.springframework.org/schema/osgi
    http://www.springframework.org/schema/osgi/spring-osgi.xsd">

    <bean id="patientServiceImpl" class="com.test.ws.PatientWebServiceImpl" >
        <property name="patientService">
            <osgi:reference interface="com.test.service.PatientService"/>
        </property>
    </bean>

    ...

</beans>

明確にするために、PatientServiceはコンシューマーバンドルに注入されますが、エンティティマネージャーはプロバイダーバンドルに注入されません。また、元のサービスの開始時に次のログ出力が表示されるため、永続性ユニットの問題ではないようです。

125  psu  TRACE  [SpringOsgiExtenderThread-14] openjpa.Runtime - org.apache.openjpa.persistence.PersistenceProviderImpl@24a5031d creating container org.apache.openjpa.persistence.EntityManagerFactoryImpl@4d6f77b6 for PU psu.

何が起こっているのかを理解するために、オブジェクトメモリ参照とスタックトレースをPatientServiceJpaImplクラスのコンストラクターに記録しました。コンストラクターが2回呼び出されました(2つの異なるオブジェクトが作成されました)。

  1. org.apache.felix最初の出力は、で始まり、多かれ少なかれで終わるosgiコンテナから発信されているように見えますorg.apache.aries.blueprint

  2. org.springframework.osgi2番目の出力は、で始まり、多かれ少なかれで終わるSpringFrameworkから発生しているように見えますorg.springframework.beans.BeanUtils

コンシューマーサービスが呼び出されると、その参照は、注入されたエンティティマネージャーを持たないブループリントのインスタンス化されたオブジェクトへの参照になります。また、ログから、オブジェクトのブループリントのインスタンス化の後に永続性ユニットがインスタンス化されPatientServiceJpaImplます。

私はかなり長い間この問題を検索していじくり回してきました、そして私はアイデアを使い果たしました。皮肉なことに、実際にはある時点で機能していましたが、機能させるために多くの変更を加えたため、ネズミの巣であったため、元に戻すことができませんでした。

ブループリント管理対象オブジェクトに永続コンテキストが挿入されないのはなぜですか?任意のアイデアをいただければ幸いです。ありがとう。

4

2 に答える 2

2

これがうまくいくかどうかはわかりません。春と青写真を混ぜているからです。ブループリントのみに基づいた実用的なアプリケーションがあり、非常に満足しています。ユースケースでは、少なくともJPA部分にブループリントを使用することをお勧めします。jpaクラスをサービスとして使用するためにspring-dmを引き続き使用できます。

<blueprint default-activation="eager"
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0">

<bean id="patientService" class="com.test.service.PatientServiceJpaImpl" >
    <jpa:context property="em" unitname="dn1" />
<tx:transaction method="*" value="Required" />
</bean>
<service id="osgiPatientService" ref="patientService" interface="com.test.service.PatientService" />
</blueprint>

あなたのPatientServiceJPAImpl私は注釈を含まないように変更します。

public class PatientServiceJpaImpl implements PatientService {
    protected EntityManager em;

    @Override
    public Patient find(Integer id) {
        return em.find(Patient.class, id);
    }
}
于 2012-12-03T22:18:51.117 に答える
0

これに対処する良い方法は、GeminiJPAを使用することです。Gemini JPAを使用すると、JPAバンドルは、persistence.xmlの構成に基づいて、EntityManagerFactoryOSGiサービスを自動的に公開します。したがって、JPAクライアントバンドルでは、ブループリントは、永続性ユニット名を指定するフィルター条件を使用してこのサービスをインポートする必要があります。

これらの行の小さな実装は次のとおりです:mvc-osgi

EMFサービスが機能しない場合は、Gemini JPAバンドルによって公開されているEntityManagerFactoryBuilderサービスを使用して、EMFを手動で作成できます。これには、「createEntityManagerFactory」を呼び出す必要があります。

于 2013-10-20T04:42:01.133 に答える