Add additional class conditions for JTA auto-configuration

Previously, JTA auto-configuration would fail with a variety of
ClassNotFoundExceptions and NoClassDefFoundErrors if it was used with
an “incomplete” classpath. This commit adds a number of classes to
@ConditionalOnClass annotations so that the auto-configuration backs
off gracefully in the absence of certain classes.

Specifically, the following now work as expected:

 - Deploying an app to a server with JTA available via JNDI when the
   app does not use transactions
 - Auto-configuration of Atomikos without JMS
 - Auto-configuration of Bitronix without JMS

Both XADataSourceAutoConfiguration and JndiDataSourceAutoConfiguration
have been updated to back off in the absence of spring-jdbc; a
dependency of DataSourceProperties which is used by both classes.

Error handling in AtomikosDependsOnBeanFactoryPostProcessor and
BitronixDependentBeanFactoryPostProcessor has been enhanced so that the
correct dependencies are established, even in the absence of JMS.

Fixes gh-1538
pull/1652/head
Andy Wilkinson 10 years ago
parent 59ce634437
commit 6f9f335ea1

@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
/**
@ -38,7 +39,7 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
@Configuration
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class,
DataSourceAutoConfiguration.class })
@ConditionalOnClass(DataSource.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnProperty(prefix = DataSourceProperties.PREFIX, name = "jndi-name")
@EnableConfigurationProperties(DataSourceProperties.class)
public class JndiDataSourceAutoConfiguration {

@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.XADataSourceWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@ -50,7 +51,8 @@ import org.springframework.util.StringUtils;
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@AutoConfigureAfter(JtaAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@ConditionalOnClass({ DataSource.class, TransactionManager.class })
@ConditionalOnClass({ DataSource.class, TransactionManager.class,
EmbeddedDatabaseType.class })
@ConditionalOnBean(XADataSourceWrapper.class)
@ConditionalOnMissingBean(DataSource.class)
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jta;
import java.io.File;
import java.util.Properties;
import javax.jms.Message;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
@ -51,7 +52,7 @@ import com.atomikos.icatch.jta.UserTransactionManager;
* @since 1.2.0
*/
@Configuration
@ConditionalOnClass(UserTransactionManager.class)
@ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class)
class AtomikosJtaConfiguration {
@ -99,12 +100,6 @@ class AtomikosJtaConfiguration {
return new AtomikosXADataSourceWrapper();
}
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new AtomikosXAConnectionFactoryWrapper();
}
@Bean
@ConditionalOnMissingBean
public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
@ -117,4 +112,16 @@ class AtomikosJtaConfiguration {
return new JtaTransactionManager(userTransaction, transactionManager);
}
@Configuration
@ConditionalOnClass(Message.class)
static class AtomikosJtaJmsConfiguration {
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new AtomikosXAConnectionFactoryWrapper();
}
}
}

@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jta;
import java.io.File;
import javax.jms.Message;
import javax.transaction.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
@ -47,7 +48,7 @@ import bitronix.tm.jndi.BitronixContext;
* @since 1.2.0
*/
@Configuration
@ConditionalOnClass(BitronixContext.class)
@ConditionalOnClass({ JtaTransactionManager.class, BitronixContext.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class)
class BitronixJtaConfiguration {
@ -89,12 +90,6 @@ class BitronixJtaConfiguration {
return new BitronixXADataSourceWrapper();
}
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new BitronixXAConnectionFactoryWrapper();
}
@Bean
@ConditionalOnMissingBean
public static BitronixDependentBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
@ -106,4 +101,13 @@ class BitronixJtaConfiguration {
return new JtaTransactionManager(transactionManager);
}
@ConditionalOnClass(Message.class)
static class BitronixJtaJmsConfiguration {
@Bean
@ConditionalOnMissingBean
public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
return new BitronixXAConnectionFactoryWrapper();
}
}
}

@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.jta;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
@ -24,12 +25,13 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
/**
* JTA Configuration for a JDNI managed {@link JtaTransactionManager}.
* JTA Configuration for a JNDI-managed {@link JtaTransactionManager}.
*
* @author Phillip Webb
* @since 1.2.0
*/
@Configuration
@ConditionalOnClass(JtaTransactionManager.class)
@ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME,
"java:comp/TransactionManager", "java:appserver/TransactionManager",
"java:pm/TransactionManager", "java:/TransactionManager" })

@ -61,7 +61,7 @@ public class JtaAutoConfigurationTests {
}
@Test
public void customPatformTransactionManager() throws Exception {
public void customPlatformTransactionManager() throws Exception {
this.context = new AnnotationConfigApplicationContext(
CustomTransactionManagerConfig.class, JtaAutoConfiguration.class);
this.thrown.expect(NoSuchBeanDefinitionException.class);

@ -94,6 +94,9 @@ public class AtomikosDependsOnBeanFactoryPostProcessor implements
catch (ClassNotFoundException ex) {
// Ignore
}
catch (NoClassDefFoundError ex) {
// Ignore
}
return NO_BEANS;
}

@ -70,6 +70,9 @@ public class BitronixDependentBeanFactoryPostProcessor implements
catch (ClassNotFoundException ex) {
// Ignore
}
catch (NoClassDefFoundError ex) {
// Ignore
}
return NO_BEANS;
}

Loading…
Cancel
Save