未注入OSGI服务JPA PersistenceContext [英] OSGI service JPA PersistenceContext not injected

查看:124
本文介绍了未注入OSGI服务JPA PersistenceContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个核心库,该库具有要作为Fuse ESB(Apache ServiceMix和Karaf)中的OSGI服务公开的接口.目的是允许其他捆绑软件使用它.该服务使用JPA(OpenJPA)和Spring.以下是界面:

I have a core library that has an interface that I want to expose as an OSGI service in Fuse ESB (Apache ServiceMix and Karaf). The goal is to allow other bundles to use it. The service uses JPA (OpenJPA) and Spring. The following is the interface:

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环境中,一切正常.它使用felix maven-bundle-plugin,因此要创建OSGi服务,我添加了以下OSGI-INF/blueprint/osgi-context.xml:

In a non-OSGi environment, everything works great. It uses the felix maven-bundle-plugin, so to create the OSGi service, I added the following 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时,尚未注入实体管理器,因此在find(Integer id)方法中抛出了NullPointerException.以下是使用者的META-INF/spring/consumer-context.xml的代码段:

The bundle is deployed successfully and the service is registered. The problem is that when the PatientService is referenced from another bundle, the entity manager has not been injected, thus throwing a NullPointerException in the find(Integer id) method. The following is a snippet of the consumer's 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被注入到使用者捆绑中,但是实体管理器未被注入到提供者捆绑中.另外,由于在启动原始服务时,以下日志输出显示,持久性单元似乎也不是问题:

Just to be clear, the PatientService is injected in the consumer bundle, but the entity manager is not injected in the provider bundle. Also, it does not appear to be an issue with the persistence unit due to the following log output when starting the original service:

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类的构造函数中记录了对象内存引用和堆栈跟踪.构造函数被调用两次(创建两个不同的对象):

To get an idea what is going on, I logged the the object memory reference and stack trace in the constructor of the PatientServiceJpaImpl class. The constructor was called twice (creating two different objects):

  1. 第一个输出似乎来自osgi容器,该容器从org.apache.felix开始,或多或少以org.apache.aries.blueprint结尾.

  1. The first output appears to originate from the osgi container starting from org.apache.felix and more or less ending in org.apache.aries.blueprint.

第二个输出似乎源自spring框架,该框架从org.springframework.osgi开始,或多或少以org.springframework.beans.BeanUtils结尾.

The second output appears to originate from the spring framework starting from org.springframework.osgi and more or less ending in org.springframework.beans.BeanUtils.

调用使用者服务时,它具有的引用是对实例化蓝图的对象的,该对象没有注入的实体管理器.同样从日志中,在PatientServiceJpaImpl对象的蓝图实例化之后,实例化持久性单元.

When the consumer service is called, the reference it has is to the blueprint instantiated object, which does not have an injected entity manager. Also from the logs, the persistence unit is instantiated after the blueprint instantiation of the PatientServiceJpaImpl object.

我已经搜索并修正了这个问题已有相当长的一段时间了,我的想法已经用完了.具有讽刺意味的是,它实际上只在某一时刻起作用,但是我进行了很多更改才能使其起作用,以至于它是老鼠窝,所以我无法成功退出.

I have searched and tinkered with this issue for quite a while and I've run out of ideas. The irony is that it actually worked at one point, but I had made so many changes to get it to work that it was a rats nest that I was not able to back out of successfully.

为什么持久性上下文没有注入到蓝图托管对象中?任何想法将不胜感激.谢谢.

Why is the persistence context not injected in the blueprint managed object? Any ideas will be appreciated. Thanks.

推荐答案

我不确定这是否行得通,因为您将弹簧与蓝图混在一起.我有一个仅基于蓝图的工作应用程序,我感到非常高兴.对于您的用例,我建议至少在您的JPA部分中使用蓝图.您仍然可以使用spring-dm将jpa类用作服务.

I'm not sure if this is going to work, cause you are mixing spring with blueprint. I have a working application based only on blueprint and I'm quite happy. For your use-case I'd suggest using blueprint at least for your JPA part. You still can use spring-dm for using the jpa classes as services.

<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我将更改为不包含任何注释.

Your PatientServiceJPAImpl I would change to not contain any annotations.

public class PatientServiceJpaImpl implements PatientService {
    protected EntityManager em;

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

这篇关于未注入OSGI服务JPA PersistenceContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆