我有一個核心庫,它具有一個我想在Fuse ESB(Apache ServiceMix和Karaf)中公開爲OSGI服務的接口。目標是允許其他軟件包使用它。該服務使用JPA(OpenJPA)和Spring。以下是該接口:OSGI服務未注入JPA PersistenceContext
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環境中,一切都很好。它採用了菲利克斯行家束-插件,所以創建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
被另一個包引用時,實體管理器沒有被注入,因此在find(Integer id)
方法中拋出NullPointerException
。以下是消費者的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 - [email protected] creating container [email protected] for PU psu.
爲了得到一個想法是怎麼回事,我記錄的對象內存引用和堆棧跟蹤PatientServiceJpaImpl
類的構造函數中。構造函數被調用兩次(產生兩個不同的對象):
第一輸出出現從
org.apache.felix
和更或更少org.apache.aries.blueprint
結束開始OSGi容器發起。第二個輸出似乎源自彈簧框架從
org.springframework.osgi
開始,或多或少以org.springframework.beans.BeanUtils
結尾。
當消費者服務被調用,它具有參考的藍圖實例化對象,它沒有注入實體管理器。同樣從日誌中,持久性單元在PatientServiceJpaImpl
對象的藍圖實例化之後被實例化。
我已經搜索了這個問題並修改了很長一段時間,並且我已經用完了想法。具有諷刺意味的是,它確實在某一時刻起作用,但我做了很多改變才能使它起作用,以至於我無法成功退出,這是一個老鼠巢。
爲什麼持久性上下文沒有注入到藍圖管理對象中?任何想法將不勝感激。謝謝。
感謝您的回覆。該庫也將被其他開發人員在非OSGI環境中使用。有沒有辦法維護這兩種解決方案?換句話說,在藍圖環境中保留「PatientServiceJpaImpl」註釋有什麼作用(如果有的話)? –
在這種情況下,請確保您不是通過藍圖導出服務,而是使用spring-dm導出服務。如果你必須使用spring-dm的彈簧棒,並且通過藍圖來引用你的服務,那麼兩者的混合都不起作用。 –
我最初通過在spring上下文xml文件中定義osgi服務來嘗試這種方法。但是,在使用felix maven-bundle-plugin構建包之後,我沒有在MANIFEST-MF中看到Export-Service聲明,並且部署該包沒有註冊該服務。自從春天DM似乎已經停止以後,我決定不採取後續行動。是否可以在karaf中使用spring-dm(我正在使用Fuse ESB發行版)?如果是這樣,在道路上這樣做是否有意義?謝謝。 –