「Struts2 + Spring + Slim3の連携に挑戦」の修正版です。
前回の内容を修正しました。
改めてSlim3のLocalTransactionとGlobalTransactionについて調べた結果、前回の内容では不完全だったことがわかりました。
今回は完全に書き直しです。
- Slim3の新規プロジェクト作成
- まず最初に、EclipseのSlim3プラグインを使用してSlim3の新規プロジェクトを作成します。
プロジェクト名とルートパッケージ Project name s3sample Root Package com.brightgenerous.s3.sample.data - 不要なファイルを削除しておきます。
削除するファイルとディレクトリ /src/application_en.properties /src/application_ja.properties /war/css /war/ktrwjr /war/common.jsp
- Jarファイル追加
- 以下のjarファイルを「war/WEB-INF/lib」に追加します。
追加するjarファイル aopalliance-1.0 commons-beanutils-1.7.0 commons-digester-2.0 commons-fileupload-1.2.1 commons-io-1.3.2 commons-lang-2.3 commons-logging-1.0.4 commons-validator-1.3.1 freemarker-gae-pre3 javassist ognl-3.0 spring-aop spring-beans spring-context spring-core spring-tx spring-web struts2-convention-plugin-2.2.1.1 struts2-core-2.2.1.1 struts2-spring-plugin-2.2.1.1 xwork-core-2.2.1.1 freemarker-gae-pre3は、gae用のfreemarkerです。
Springは2.5を使用します。
- web.xml
- 「war/WEB-INF」に配置するweb.xmlファイルです。
- <web-app version="2.5" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <context-param>
- <param-name>slim3.rootPackage</param-name>
- <param-value>com.brightgenerous.s3.sample.data</param-value>
- </context-param>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:applicationContext*.xml</param-value>
- </context-param>
- <filter>
- <filter-name>DatastoreFilter</filter-name>
- <filter-class>org.slim3.datastore.DatastoreFilter</filter-class>
- </filter>
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
- <init-param>
- <param-name>actionPackages</param-name>
- <param-value>com.brightgenerous.s3.sample.action</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>DatastoreFilter</filter-name>
- <url-pattern>/*</url-pattern>
- <dispatcher>REQUEST</dispatcher>
- </filter-mapping>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <servlet>
- <servlet-name>GlobalTransactionServlet</servlet-name>
- <servlet-class>org.slim3.datastore.GlobalTransactionServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>GlobalTransactionServlet</servlet-name>
- <url-pattern>/slim3/gtx</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <listener>
- <listener-class>com.brightgenerous.s3.sample.gae.GaeInitListener</listener-class>
- </listener>
- <security-constraint>
- <web-resource-collection>
- <url-pattern>/slim3/gtx</url-pattern>
- </web-resource-collection>
- <auth-constraint>
- <role-name>admin</role-name>
- </auth-constraint>
- </security-constraint>
- </web-app>
- Slim3の新規プロジェクトを作成して生成されるweb.xmlの内容の
ほとんど少しを消すことになります。
「com.brightgenerous.s3.sample.gae.GaeInitListener」は、独自に実装するクラスです。ソースは「実装するクラス」にて後述します。
- applicationContext.xml
- 「classpath:applicationContext*.xml」(src直下)に配置します。
- <beans xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-2.5.xsd">
- <context:annotation-config></context:annotation-config>
- <context:component-scan base-package="com.brightgenerous.s3.sample.action"></context:component-scan>
- <bean class="com.brightgenerous.s3.sample.gae.GaeFixInternalPersistenceAnnotationProcessor" id="org.springframework.context.annotation.internalPersistenceAnnotationProcessor"></bean>
- <bean class="com.brightgenerous.s3.sample.gae.Slim3TransactionManager" id="transactionManager"></bean>
- <bean class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource" id="transactionAttributeSource">
- <property name="properties">
- <props>
- <prop key="*">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
- <bean class="com.brightgenerous.s3.sample.gae.Slim3TransactionInterceptor" id="transactionInterceptor">
- <property name="transactionManager" ref="transactionManager"></property>
- <property name="transactionAttributeSource" ref="transactionAttributeSource"></property>
- </bean>
- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" id="beanNameAutoProxy">
- <property name="interceptorNames">
- <list>
- <value>transactionInterceptor</value>
- </list>
- </property>
- <property name="beanNames">
- <list>
- <value>*ServiceImpl</value>
- </list>
- </property>
- </bean>
- </beans>
「transactionManager」のみ用意してやれば他はそのまま使えます。なかなかナイスな設計です。
「transactionManager」と「transactionInterceptor」を用意します。
「com.brightgenerous.s3.sample.gae.GaeFixInternalPersistenceAnnotationProcessor」、 「com.brightgenerous.s3.sample.gae.Slim3TransactionManager」、 「com.brightgenerous.s3.sample.gae.Slim3TransactionInterceptor」については、後述です。
- 実装するクラス
- 1.com.brightgenerous.s3.sample.gae.GaeInitListener
- package com.brightgenerous.s3.sample.gae;
- import javax.servlet.ServletContextEvent;
- import javax.servlet.ServletContextListener;
- import javax.servlet.http.HttpSessionAttributeListener;
- import javax.servlet.http.HttpSessionBindingEvent;
- import javax.servlet.http.HttpSessionEvent;
- import javax.servlet.http.HttpSessionListener;
- import ognl.OgnlRuntime;
- public class GaeInitListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {
- @Override
- public void contextInitialized(ServletContextEvent sce) {
- OgnlRuntime.setSecurityManager(null);
- }
- @Override
- public void contextDestroyed(ServletContextEvent arg0) {
- }
- @Override
- public void sessionCreated(HttpSessionEvent arg0) {
- }
- @Override
- public void sessionDestroyed(HttpSessionEvent arg0) {
- }
- @Override
- public void attributeAdded(HttpSessionBindingEvent arg0) {
- }
- @Override
- public void attributeRemoved(HttpSessionBindingEvent arg0) {
- }
- @Override
- public void attributeReplaced(HttpSessionBindingEvent arg0) {
- }
- }
- OGNLのセキュリティマネージャがなんとかかんとか...理由については、詳しく調べていません。
- 2.com.brightgenerous.s3.sample.gae.GaeFixInternalPersistenceAnnotationProcessor
- package com.brightgenerous.s3.sample.gae;
- public class GaeFixInternalPersistenceAnnotationProcessor {
- }
- 「java.lang.NoClassDefFoundError」を回避することだけが目的です。
- 3.com.brightgenerous.s3.sample.gae.Slim3TransactionManager
- package com.brightgenerous.s3.sample.gae;
- import org.slim3.datastore.Datastore;
- import org.springframework.transaction.TransactionDefinition;
- import org.springframework.transaction.TransactionException;
- import org.springframework.transaction.support.AbstractPlatformTransactionManager;
- import org.springframework.transaction.support.DefaultTransactionStatus;
- public class Slim3TransactionManager extends AbstractPlatformTransactionManager {
- private static final long serialVersionUID = 3423679590583692519L;
- @Override
- protected void doBegin(Object x_arg0, TransactionDefinition x_arg1) throws TransactionException {
- TransactionObject transactionObject = (TransactionObject) x_arg0;
- transactionObject.setTransaction(Datastore.beginGlobalTransaction());
- }
- @Override
- protected void doCommit(DefaultTransactionStatus x_arg0) throws TransactionException {
- TransactionObject transactionObject = (TransactionObject) x_arg0.getTransaction();
- transactionObject.getTransaction().commit();
- }
- @Override
- protected Object doGetTransaction() throws TransactionException {
- return new TransactionObject();
- }
- @Override
- protected void doRollback(DefaultTransactionStatus x_arg0) throws TransactionException {
- TransactionObject transactionObject = (TransactionObject) x_arg0.getTransaction();
- transactionObject.getTransaction().rollback();
- }
- }
- package com.brightgenerous.s3.sample.gae;
- import java.io.Serializable;
- import org.slim3.datastore.GlobalTransaction;
- public class TransactionObject implements Serializable {
- private static final long serialVersionUID = -8353097480608667182L;
- private GlobalTransaction p_transaction;
- public GlobalTransaction getTransaction() {
- return p_transaction;
- }
- public void setTransaction(GlobalTransaction x_transaction) {
- p_transaction = x_transaction;
- }
- }
- package com.brightgenerous.s3.sample.gae;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Target(ElementType.FIELD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Slim3GlobalTransaction {
- }
- 「org.springframework.jdbc.datasource.DataSourceTransactionManager」の実装を参考にして、Slim3用に簡単に対応させています。
「TransactionObject」、「Slim3GlobalTransaction」も作成します。このクラスのみ自作です。間違い等あれば指摘していただけるとありがたいです。
- 4.com.brightgenerous.s3.sample.gae.Slim3TransactionInterceptor
- private void injectTransaction(Object x_obj, TransactionInfo x_txInfo) {
- TransactionStatus txStatus = x_txInfo.getTransactionStatus();
- DefaultTransactionStatus dtxStatus;
- if (!(txStatus instanceof DefaultTransactionStatus)) {
- return;
- }
- dtxStatus = (DefaultTransactionStatus) txStatus;
- Object tx = dtxStatus.getTransaction();
- if (tx instanceof TransactionObject) {
- tx = ((TransactionObject) tx).getTransaction();
- }
- if (!(tx instanceof GlobalTransaction)) {
- return;
- }
- @SuppressWarnings("rawtypes")
- Class clazz = x_obj.getClass();
- do {
- Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- if (!field.isAccessible()) {
- field.setAccessible(true);
- }
- Slim3GlobalTransaction s3gtx = field.getAnnotation(Slim3GlobalTransaction.class);
- if (s3gtx != null) {
- if (field.getType().isInstance(tx)) {
- try {
- field.set(x_obj, tx);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (IllegalArgumentException e) {
- throw new RuntimeException(e);
- }
- }
- }
- }
- clazz = clazz.getSuperclass();
- } while ((clazz != null) && !clazz.equals(Object.class));
- }
- 「org.springframework.transaction.interceptor.TransactionInterceptor」のソースをコピーしてきて、
上記のメソッドが適当な箇所で呼ばれるように書き換えます。
ライセンスを考慮して全体は公開しませんが、元のソースを読めば変更箇所はわかるはずです。
以上でStruts2 + Spring + Slim3の設定は完了です。
次回こそ、このフレームワークを使用して簡単なサンプルを書いてみます。
0 件のコメント:
コメントを投稿