JBoss AS5.1上でJPAを完全にSpring駆動で実行させる方法
JPAプロバイダーを起動するしくみがJavaEE5対応のアプリケーションサーバに組み込まれているため、JPAの仕様に従って、META-DATA/persistence.xmlファイルが格納されていると、アプリケーションサーバーによって読み込まれて処理されます。読み込まれたJPAの永続ユニットはローカルのJNDIコンテキストから参照できます。
しかしながら、
などの理由により、アプリケーションサーバーにJPAを処理させずに、Springの軽量コンテナーに処理させるという方法も時として便利です。このような場合、アプリケーションサーバーにpersistence.xmlを認識させないための、てっとり早い方法としては、persistence.xmlをpersistece-spring.xmlなどにリネームし、これをSpringに読み込ませるという方法があります。
<!-- JPA EntityManagerFactory の設定 --> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="sampleDB" /> <!-- JBoss が PersistenceUnit をロードしないようファイル名称を persistence.xml 以外に変更 --> <property name="persistenceXmlLocation" value="classpath*:META-INF/spring-persistence.xml" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL" /> <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> </bean> </property> <property name="jpaDialect"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> </property> </bean>
しかし、この方法ではJBoss AS5*1上で正しくJPAを動作させることができないようです。実際、以下の例外となりアプリケーションが起動しません。
java.lang.IllegalArgumentException: Can't find a persistence unit named 'null' in AbstractVFSDeploymentContext@2123658583{vfszip:/D:/development/tools/JBoss/jboss-5.1.0.GA/server/default/deploy/sample.war/} at org.jboss.jpa.resolvers.BasePersistenceUnitDependencyResolver.resolvePersistenceUnitSupplier(BasePersistenceUnitDependencyResolver.java:107) at org.jboss.web.tomcat.service.TomcatInjectionContainer.resolvePersistenceUnitSupplier(TomcatInjectionContainer.java:685) at org.jboss.injection.PersistenceUnitHandler.addPUDependency(PersistenceUnitHandler.java:130)
Springのアプリケーションでは部分的にJavaEEの標準アノテーションが利用できるようになっており、例えば、EJBでないPojoのDAOクラスの中で@PersisteceContextアノテーションを利用することができます。しかし、なぜか、このアノテーションがJBossに認識されてしまうという問題があるようです。(本来であれば、EJBやサーブレットなど特定のJavaEEのコンポーネント上でしか認識してほしくないのですが。)今の場合、persistence.xmlを別名にリネームしているため永続ユニットが初期化されていないとJBossに認識されているため、@PersistenceContextアノテーションの読み込みがされた時点でチェックされて上記のエラーとなるようです。この問題について、しばらく悩んでいたのですが、以下に解決策のヒントが書かれていました。
[JBSEAM-3587] Spring example on AS 5 throwns a non-jta-data-source error while deploying - JBoss Issue Tracker
結局、対処としては、web.xmlの
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5" metadata-complete="true"> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:appCommonContext.xml /WEB-INF/applicationContext.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> ... </web-app>
この属性により、JBossがxmlファイルによって設定が完結していると認識し、勝手にPojo内のアノテーションを探しに行く動作が抑制されるようです。さらに嬉しいことに、この属性により、起動時間も多少軽くなるようです。
ちなみに、以前からJBossとSpringの相性はよくなく、VFSから設定ファイルを読み込めず、Spring2.5まではSpring MVCがそのままでは起動すらしないという状態でした。SpringとJBossの連携については以下のプロジェクトも知られています。
Snowdrop - Cloud native Spring Boot applications
Spring3ではかなり相性の問題は解決されているようですが、古いバージョンを利用する場合には以上に紹介した連携モジュールの仕掛けが役に立つかもしれません。