目的
LibertyのSpring Framework 環境を構築して HelloWorld のような簡単なプログラムでテストします。
Spring プログラムの説明
Eclipse で必要な ソースコードとXMLを用意するところからの説明です。
SomeBean.java
ここで
- transactionManager は bean の property で application-context.xml に指定
- @Transactional は tx:annotation-driven/
- test は transactionManager.getTransaction でトランザクション開始
package pdprof.spring.transaction;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.jta.WebSphereUowTransactionManager;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class SomeBean {
WebSphereUowTransactionManager transactionManager;
public WebSphereUowTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(WebSphereUowTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Transactional
public void testAnnotation() {
System.out.println("Some testAnnotation()");
}
public void test() {
try {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus status = transactionManager.getTransaction(def);
System.out.println("Is the transaction new ? " + status.isNewTransaction());
transactionManager.commit(status);
} catch (TransactionException e) {
e.printStackTrace();
}
System.out.println("Some test()");
}
}
application-context.xml
- SomeBean.java から使用される内容を指定する
<?xml version="1.0" encoding="UTF-8"?>
<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:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<tx:jta-transaction-manager/>
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
</bean>
<bean id="someBean" class="pdprof.spring.transaction.SomeBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
</bean>
</beans>
ApplicationContext の初期化
- ApplicationContext を application-context.xml を読み込んで初期化
- サーブレット実行時に test(), testAnnotation() メソッドを実行してトランザクションをテスト
package pdprof.spring.transaction;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Servlet implementation class SpringTransactionServlet
*/
@WebServlet("/transaction")
public class SpringTransactionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public SpringTransactionServlet() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
test();
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
SomeBean bean = (SomeBean) context.getBean("someBean");
bean.test();
bean.testAnnotation();
}
}
Libertyテスト環境
これまでの方法で既存環境に構成は可能ですが、環境をdockerで用意する方法です。
今回は tWAS でも動作するように、Java8, jsp-2.3, jpa-2.2 で動かします。
server 構成は以下になります。
<server description="new server">
<!-- Enable features -->
<featureManager>
<feature>jsp-2.3</feature>
<feature>jdbc-4.2</feature>
<feature>cdi-2.0</feature>
<feature>jpa-2.2</feature>
<feature>localConnector-1.0</feature>
<feature>eventLogging-1.0</feature>
<feature>requestTiming-1.0</feature>
</featureManager>
<httpAccessLogging id="pdprofAccessLogging" logFormat="%h %u %t "%r" %s %b %{remote}p %D %{JSESSIONID}C %{Set-Cookie}o"/>
<httpEndpoint accessLoggingRef="pdprofAccessLogging" host="*" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>
<eventLogging logMode="entryExit" minDuration="1ms"/>
<requestTiming slowRequestThreshold="5s" hungRequestThreshold="10m">
</requestTiming>
<logging traceSpecification="TransactionSummary=all"
traceFileName="trace.log"
maxFileSize="20"
maxFiles="10"
traceFormat="BASIC" />
<basicRegistry id="basic">
<user name="wsadmin" password="passw0rd" />
<user name="reader" password="passw0rd" />
</basicRegistry>
<administrator-role>
<user>wsadmin</user>
</administrator-role>
<reader-role>
<user>reader</user>
</reader-role>
<!-- Automatically expand WAR files and EAR files -->
<applicationManager autoExpand="true"/>
<!-- Default SSL configuration enables trust for default certificates from the Java runtime -->
<ssl id="defaultSSLConfig" trustDefaultCerts="true"/>
<applicationMonitor updateTrigger="mbean"/>
<webApplication id="spring.transaction" location="spring.transaction.war" name="spring.transaction"/>
</server>
Libertyテスト環境の自動構築
これまでの方法で既存環境に構成は可能ですが、環境をdockerで用意する方法です。
用意したGitレポジトリをクローンします。
git clone http://github.com/pdprof/spring-transaction.git
cd spring-transaction/spring-transaction-docker
Libertyのイメージをビルドして開始します。
./setup-docker.sh
./start.sh
Libertyの起動を確認します。SpringTransactionServlet にアクセスします。
と表示されれば問題ありません。
トランザクション処理を確認
docker container にアクセスしてtrace.logでトランザクションを確認します。
podman exec -it spring-transaction bash
more /logs/trace.log
getTransaction() でトランザクション開始
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
の呼び出しが確認できます。
4/29/25 15:01:52:648 UTC] 00000033 TransactionIm 3 Transaction created.
com.ibm.tx.jta.embeddable.impl.EmbeddableTransactionImpl@a8adf6fe#tid=138827292,active=0,suspended=0,Not on a thread,gtrid=0000019682119585000000010846561c88a9e4b2aacda5c60ff4e6ce705569cfddc6e538
{XidImpl: formatId(57415344), gtrid_length(36), bqual_length(40),
data(0000019682119585000000010846561c88a9e4b2aacda5c60ff4e6ce705569cfddc6e5380000019682119585000000010846561c88a9e4b2aacda5c60ff4e6ce705569cfddc6e53800000001)}
trace java.lang.Throwable: Transaction creation stack--More--(41%)
at com.ibm.tx.jta.impl.TransactionImpl.traceCreate(TransactionImpl.java:3383)
at com.ibm.tx.jta.impl.TransactionImpl.<init>(TransactionImpl.java:334)
at com.ibm.tx.jta.embeddable.impl.EmbeddableTransactionImpl.<init>(EmbeddableTransactionImpl.java:89)
at com.ibm.tx.jta.embeddable.impl.EmbeddableTranManagerImpl.createNewTransaction(EmbeddableTranManagerImpl.java:78)
at com.ibm.tx.jta.embeddable.impl.EmbeddableTranManagerImpl.createNewTransaction(EmbeddableTranManagerImpl.java:30)
at com.ibm.tx.jta.impl.TranManagerImpl.beginUserTran(TranManagerImpl.java:124)
at com.ibm.tx.jta.impl.TranManagerSet.beginUserTran(TranManagerSet.java:107)
at com.ibm.tx.jta.impl.UserTransactionImpl.begin(UserTransactionImpl.java:66)
at com.ibm.tx.jta.embeddable.impl.EmbeddableUserTransactionImpl.begin(EmbeddableUserTransactionImpl.java:71)
at com.ibm.ws.transaction.services.UserTransactionService.begin(UserTransactionService.java:68)
at org.springframework.transaction.jta.JtaTransactionManager.doJtaBegin(JtaTransactionManager.java:886)
TransactionManager.java:849)rk.transaction.jta.JtaTransactionManager.doBegin(Jta--More--(48%)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at pdprof.spring.transaction.SomeBean.test(SomeBean.java:32)
at pdprof.spring.transaction.SomeBean$$FastClassBySpringCGLIB$$b1dba14.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy.invokeMethod(CglibAopProxy.java:386)
at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:85)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)
at pdprof.spring.transaction.SomeBean$$EnhancerBySpringCGLIB$$bd4c84c6.test(<generated>)
at pdprof.spring.transaction.SpringTransactionServlet.test(SpringTransactionServlet.java:50)
at pdprof.spring.transaction.SpringTransactionServlet.doGet(SpringTransactionServlet.java:33)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
@Transactional でのトランザクション開始
<tx:annotation-driven/>
と <bean id="transactionManager" ../>
の指定で
org.springframework.transaction.jta.WebSphereUowTransactionManager.execute(WebSphereUowTransactionManager.java:306)
が実行されています。トレースが出力されていることでLibertyのトランザクションマネージャーが使われていることが分かります。
[4/29/25 15:01:52:660 UTC] 00000033 TransactionIm 3 Transaction created.
com.ibm.tx.jta.embeddable.impl.EmbeddableTransactionImpl@fd6d3e5b#tid=138827300,active=0,suspended=0,Not on a thread,gtrid=0000019682119594000000010846562488a9e4b2aacda5c60ff4e6ce705569cfddc6e538
{XidImpl: formatId(57415344), gtrid_length(36), bqual_length(40),
data(0000019682119594000000010846562488a9e4b2aacda5c60ff4e6ce705569cfddc6e5380000019682119594000000010846562488a9e4b2aacda5c60ff4e6ce705569cfddc6e53800000001)}
java.lang.Throwable: Transaction creation stack trace
at com.ibm.tx.jta.impl.TransactionImpl.traceCreate(TransactionImpl.java:3383)
at com.ibm.tx.jta.impl.TransactionImpl.<init>(TransactionImpl.java:334)
at com.ibm.tx.jta.embeddable.impl.EmbeddableTransactionImpl.<init>(EmbeddableTransactionImpl.java:89)
nsaction(EmbeddableTranManagerImpl.java:78)mbeddableTranManagerImpl.createNewTra--More--(74%)
at com.ibm.tx.jta.embeddable.impl.EmbeddableTranManagerImpl.createNewTransaction(EmbeddableTranManagerImpl.java:30)
at com.ibm.tx.jta.impl.TranManagerImpl.beginUserTran(TranManagerImpl.java:124)
at com.ibm.tx.jta.impl.TranManagerSet.beginUserTran(TranManagerSet.java:107)
at com.ibm.tx.jta.impl.UserTransactionImpl.begin(UserTransactionImpl.java:66)
at com.ibm.ws.uow.embeddable.EmbeddableUOWManagerImpl.uowBegin(EmbeddableUOWManagerImpl.java:885)
at com.ibm.ws.uow.embeddable.EmbeddableUOWManagerImpl.runUnderNewUOW(EmbeddableUOWManagerImpl.java:727)
at com.ibm.ws.uow.embeddable.EmbeddableUOWManagerImpl.runUnderUOW(EmbeddableUOWManagerImpl.java:331)
at org.springframework.transaction.jta.WebSphereUowTransactionManager.execute(WebSphereUowTransactionManager.java:306)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:417)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707)
at pdprof.spring.transaction.SomeBean$$EnhancerBySpringCGLIB$$bd4c84c6.testAnnotation(<generated>)
at pdprof.spring.transaction.SpringTransactionServlet.test(SpringTransactionServlet.java:51)
at pdprof.spring.transaction.SpringTransactionServlet.doGet(SpringTransactionServlet.java:33)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
トラブルシューティング
毎度のことですが、よくつかう dockerコマンドを書いておきます。この文書でもpodman, dockerとまとまりがないですが、Linux では dockerがpodmanを呼び出すようになっていました。
docker ps # 動作中のContainer確認
docker logs -f spring-transaction # ログ確認
docker restart spring-transaction # 再起動
docker inspect spring-transaction # container 確認
docker exec -it spring-transaction bash # Container内状況確認
まとめ
Libertyの環境を構築して、Spring Framework のトランザクションをテストしました。
参考
以下ページを参考にさせていただきました。