我有一个核心库,它有一个接口,我想将其公开为 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>
And the 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
:
<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
从另一个包引用,实体管理器尚未被注入,因此抛出NullPointerException
in the find(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
班级。构造函数被调用两次(创建两个不同的对象):
第一个输出似乎源自 osgi 容器,从org.apache.felix
或多或少以org.apache.aries.blueprint
.
第二个输出似乎源自 spring 框架,从org.springframework.osgi
或多或少以org.springframework.beans.BeanUtils
.
当调用消费者服务时,它所拥有的引用是对蓝图实例化对象的引用,该对象没有注入的实体管理器。另外从日志来看,持久化单元是在蓝图实例化之后实例化的PatientServiceJpaImpl
object.
我已经搜索和修改这个问题很长一段时间了,但我已经没有想法了。具有讽刺意味的是,它确实在某一时刻发挥了作用,但我做了很多改变才能让它发挥作用,以至于它就像一个老鼠巢,我无法成功退出。
为什么持久化上下文没有注入到蓝图托管对象中?任何想法将不胜感激。谢谢。