未注入OSGI服务JPA PersistenceContext [英] OSGI service JPA PersistenceContext not injected
问题描述
我有一个核心库,该库具有要作为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):
-
第一个输出似乎来自osgi容器,该容器从
org.apache.felix
开始,或多或少以org.apache.aries.blueprint
结尾.
The first output appears to originate from the osgi container starting from
org.apache.felix
and more or less ending inorg.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屋!