본문 바로가기

프레임워크/Spring

No JTA TransactionManager found at fallback JNDI location

Jetty 6.1.11 + Spring 2.5.6에서 트랜잭션관리자를 <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> 와 같이 선언하고 로그레벨을 DEBUG 모드로 실행하면 다음과 같은 에러들을 볼 수 있다.

[DEBUG] (JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:comp/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'TransactionManager'

...

[DEBUG] (JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:appserver/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'appserver/TransactionManager'

...

(JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:pm/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'pm/TransactionManager'

...

(JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'TransactionManager'

그러나 위의 예외메시지는 무시해도 될 것 같다. 
만약 JBoss에서 실행하면 java:/TransactionManager 은 설정되는 것을 확인했다. 

[DEBUG] (JtaTransactionManager.java:676) - JTA UserTransaction found at default JNDI location [java:comp/UserTransaction]

Jetty에서는 [java:comp/UserTransaction]만 설정하는 것같다.

JtaTransactionManager.java 파일의 내용을 보면 아래와 같은데 그냥 정보성으로 출력만 한다.
/**
* Fallback JNDI locations for the JTA TransactionManager. Applied if
* the JTA UserTransaction does not implement the JTA TransactionManager
* interface, provided that the "autodetectTransactionManager" flag is "true".
* @see #setTransactionManagerName
* @see #setAutodetectTransactionManager
*/
public static final String[] FALLBACK_TRANSACTION_MANAGER_NAMES =
new String[] {"java:comp/TransactionManager", "java:appserver/TransactionManager",
"java:pm/TransactionManager", "java:/TransactionManager"};

...

// Check fallback JNDI locations.
for (int i = 0; i < FALLBACK_TRANSACTION_MANAGER_NAMES.length; i++) {
String jndiName = FALLBACK_TRANSACTION_MANAGER_NAMES[i];
try {
TransactionManager tm = (TransactionManager) getJndiTemplate().lookup(jndiName, TransactionManager.class);
if (logger.isDebugEnabled()) {
logger.debug("JTA TransactionManager found at fallback JNDI location [" + jndiName + "]");
}
return tm;
}
catch (NamingException ex) {
if (logger.isDebugEnabled()) {
logger.debug("No JTA TransactionManager found at fallback JNDI location [" + jndiName + "]", ex);
}
}
}

위의 소스코드를 추적해보면 알겠지만 결국 최종 목적은 UserTransaction을 생성하는 것에 있다. 그리고 TransactionManager는 UserTransaction을 생성하기 위해 필요한 것이다.
       /**
* Initialize the UserTransaction as well as the TransactionManager handle.
* @throws TransactionSystemException if initialization failed
*/
protected void initUserTransactionAndTransactionManager() throws TransactionSystemException {
// Fetch JTA UserTransaction from JNDI, if necessary.
if (this.userTransaction == null) {
if (StringUtils.hasLength(this.userTransactionName)) {
this.userTransaction = lookupUserTransaction(this.userTransactionName);
this.userTransactionObtainedFromJndi = true;
}
else {
this.userTransaction = retrieveUserTransaction();
}
}

// Fetch JTA TransactionManager from JNDI, if necessary.
if (this.transactionManager == null) {
if (StringUtils.hasLength(this.transactionManagerName)) {
this.transactionManager = lookupTransactionManager(this.transactionManagerName);
}
else {
this.transactionManager = retrieveTransactionManager();
}
}

// Autodetect UserTransaction at its default JNDI location.
if (this.userTransaction == null && this.autodetectUserTransaction) {
this.userTransaction = findUserTransaction();
}

// Autodetect UserTransaction object that implements TransactionManager,
// and check fallback JNDI locations else.
if (this.transactionManager == null && this.autodetectTransactionManager) {
this.transactionManager = findTransactionManager(this.userTransaction);
}

// If only JTA TransactionManager specified, create UserTransaction handle for it.
if (this.userTransaction == null && this.transactionManager != null) {
this.userTransaction = buildUserTransaction(this.transactionManager);
}
}

이소스코드로 부터 예외를 내지 않게 하는 방법을 찾았는데 다음과 같이 WAS가 제공하는 것을 설정해주면 정상동작했다. 그러나 굳이 DEBUG 모드에서 스프링을 실행하지 않을 것이고 로드할 당시에만 발생하므로 무시해도 될것 같다.

  JBoss에서 예외로그 없이 동작하는 JtaTransactionManager 설정.
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
    <property name="autodetectTransactionManager" value="false"/>
    <property name="transactionManagerName" value="java:/TransactionManager"/>
  </bean>

결론은 내가 너무 예민한 것같다. ^^;