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>
bundle 部署成功,服务注册成功.问题是当PatientService
被另一个bundle引用时,实体管理器并没有被注入,从而在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):
第一个输出似乎源自从
org.apache.felix
开始的 osgi 容器,或多或少以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.
推荐答案
我不确定这是否会奏效,因为您正在将 Spring 与蓝图混合在一起.我有一个仅基于蓝图的工作应用程序,我很高兴.对于您的用例,我建议至少为您的 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屋!