Support spring transaction manager properties

Add Spring TransactionManager properties to allow timeout and rollback
settings to be configured.

See gh-7561
This commit is contained in:
Kazuki Shimizu 2016-12-03 18:49:15 +09:00 committed by Phillip Webb
parent 30ea1338de
commit 80eee6b30f
15 changed files with 275 additions and 26 deletions

View File

@ -30,6 +30,7 @@ import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean; import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
@ -40,6 +41,7 @@ import org.springframework.util.StringUtils;
* *
* @author Dave Syer * @author Dave Syer
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Kazuki Shimizu
*/ */
public class BasicBatchConfigurer implements BatchConfigurer { public class BasicBatchConfigurer implements BatchConfigurer {
@ -47,6 +49,8 @@ public class BasicBatchConfigurer implements BatchConfigurer {
private final BatchProperties properties; private final BatchProperties properties;
private final TransactionProperties transactionProperties;
private final DataSource dataSource; private final DataSource dataSource;
private final EntityManagerFactory entityManagerFactory; private final EntityManagerFactory entityManagerFactory;
@ -62,21 +66,24 @@ public class BasicBatchConfigurer implements BatchConfigurer {
/** /**
* Create a new {@link BasicBatchConfigurer} instance. * Create a new {@link BasicBatchConfigurer} instance.
* @param properties the batch properties * @param properties the batch properties
* @param transactionProperties the transaction properties
* @param dataSource the underlying data source * @param dataSource the underlying data source
*/ */
protected BasicBatchConfigurer(BatchProperties properties, DataSource dataSource) { protected BasicBatchConfigurer(BatchProperties properties, TransactionProperties transactionProperties, DataSource dataSource) {
this(properties, dataSource, null); this(properties, transactionProperties, dataSource, null);
} }
/** /**
* Create a new {@link BasicBatchConfigurer} instance. * Create a new {@link BasicBatchConfigurer} instance.
* @param properties the batch properties * @param properties the batch properties
* @param transactionProperties the transaction properties
* @param dataSource the underlying data source * @param dataSource the underlying data source
* @param entityManagerFactory the entity manager factory (or {@code null}) * @param entityManagerFactory the entity manager factory (or {@code null})
*/ */
protected BasicBatchConfigurer(BatchProperties properties, DataSource dataSource, protected BasicBatchConfigurer(BatchProperties properties, TransactionProperties transactionProperties, DataSource dataSource,
EntityManagerFactory entityManagerFactory) { EntityManagerFactory entityManagerFactory) {
this.properties = properties; this.properties = properties;
this.transactionProperties = transactionProperties;
this.entityManagerFactory = entityManagerFactory; this.entityManagerFactory = entityManagerFactory;
this.dataSource = dataSource; this.dataSource = dataSource;
} }
@ -150,10 +157,15 @@ public class BasicBatchConfigurer implements BatchConfigurer {
} }
protected PlatformTransactionManager createTransactionManager() { protected PlatformTransactionManager createTransactionManager() {
PlatformTransactionManager txManager;
if (this.entityManagerFactory != null) { if (this.entityManagerFactory != null) {
return new JpaTransactionManager(this.entityManagerFactory); txManager = new JpaTransactionManager(this.entityManagerFactory);
} }
return new DataSourceTransactionManager(this.dataSource); else {
txManager = new DataSourceTransactionManager(this.dataSource);
}
this.transactionProperties.applyTo(txManager);
return txManager;
} }
} }

View File

@ -37,11 +37,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -57,6 +59,7 @@ import org.springframework.util.StringUtils;
* *
* @author Dave Syer * @author Dave Syer
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Kazuki Shimizu
*/ */
@Configuration @Configuration
@ConditionalOnClass({ JobLauncher.class, DataSource.class, JdbcOperations.class }) @ConditionalOnClass({ JobLauncher.class, DataSource.class, JdbcOperations.class })
@ -133,15 +136,18 @@ public class BatchAutoConfiguration {
return factory; return factory;
} }
@ConditionalOnClass(name = "javax.persistence.EntityManagerFactory") @EnableConfigurationProperties({BatchProperties.class, TransactionProperties.class})
@ConditionalOnClass(value = PlatformTransactionManager.class, name = "javax.persistence.EntityManagerFactory")
@ConditionalOnMissingBean(BatchConfigurer.class) @ConditionalOnMissingBean(BatchConfigurer.class)
@Configuration @Configuration
protected static class JpaBatchConfiguration { protected static class JpaBatchConfiguration {
private final BatchProperties properties; private final BatchProperties properties;
private final TransactionProperties transactionProperties;
protected JpaBatchConfiguration(BatchProperties properties) { protected JpaBatchConfiguration(BatchProperties properties, TransactionProperties transactionProperties) {
this.properties = properties; this.properties = properties;
this.transactionProperties = transactionProperties;
} }
// The EntityManagerFactory may not be discoverable by type when this condition // The EntityManagerFactory may not be discoverable by type when this condition
@ -151,14 +157,14 @@ public class BatchAutoConfiguration {
@ConditionalOnBean(name = "entityManagerFactory") @ConditionalOnBean(name = "entityManagerFactory")
public BasicBatchConfigurer jpaBatchConfigurer(DataSource dataSource, public BasicBatchConfigurer jpaBatchConfigurer(DataSource dataSource,
EntityManagerFactory entityManagerFactory) { EntityManagerFactory entityManagerFactory) {
return new BasicBatchConfigurer(this.properties, dataSource, return new BasicBatchConfigurer(this.properties, this.transactionProperties, dataSource,
entityManagerFactory); entityManagerFactory);
} }
@Bean @Bean
@ConditionalOnMissingBean(name = "entityManagerFactory") @ConditionalOnMissingBean(name = "entityManagerFactory")
public BasicBatchConfigurer basicBatchConfigurer(DataSource dataSource) { public BasicBatchConfigurer basicBatchConfigurer(DataSource dataSource) {
return new BasicBatchConfigurer(this.properties, dataSource); return new BasicBatchConfigurer(this.properties, this.transactionProperties, dataSource);
} }
} }

View File

@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -48,12 +49,13 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @author Josh Long * @author Josh Long
* @author Vince Bickers * @author Vince Bickers
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.4.0 * @since 1.4.0
*/ */
@Configuration @Configuration
@ConditionalOnClass(SessionFactory.class) @ConditionalOnClass({SessionFactory.class, PlatformTransactionManager.class})
@ConditionalOnMissingBean(SessionFactory.class) @ConditionalOnMissingBean(SessionFactory.class)
@EnableConfigurationProperties(Neo4jProperties.class) @EnableConfigurationProperties({Neo4jProperties.class, TransactionProperties.class})
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class Neo4jDataAutoConfiguration { public class Neo4jDataAutoConfiguration {
@ -87,8 +89,11 @@ public class Neo4jDataAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
public Neo4jTransactionManager transactionManager(SessionFactory sessionFactory) { public Neo4jTransactionManager transactionManager(SessionFactory sessionFactory,
return new Neo4jTransactionManager(sessionFactory); TransactionProperties transactionProperties) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(sessionFactory);
transactionProperties.applyTo(transactionManager);
return transactionManager;
} }
private String[] getPackagesToScan(ApplicationContext applicationContext) { private String[] getPackagesToScan(ApplicationContext applicationContext) {

View File

@ -23,6 +23,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -39,6 +41,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
* @author Dave Syer * @author Dave Syer
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Kazuki Shimizu
*/ */
@Configuration @Configuration
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class }) @ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@ -47,6 +50,7 @@ public class DataSourceTransactionManagerAutoConfiguration {
@Configuration @Configuration
@ConditionalOnSingleCandidate(DataSource.class) @ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(TransactionProperties.class)
static class DataSourceTransactionManagerConfiguration { static class DataSourceTransactionManagerConfiguration {
private final DataSource dataSource; private final DataSource dataSource;
@ -57,8 +61,10 @@ public class DataSourceTransactionManagerAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
public DataSourceTransactionManager transactionManager() { public DataSourceTransactionManager transactionManager(TransactionProperties transactionProperties) {
return new DataSourceTransactionManager(this.dataSource); DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
transactionProperties.applyTo(transactionManager);
return transactionManager;
} }
} }

View File

@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -59,8 +60,9 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @author Dave Syer * @author Dave Syer
* @author Oliver Gierke * @author Oliver Gierke
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Kazuki Shimizu
*/ */
@EnableConfigurationProperties(JpaProperties.class) @EnableConfigurationProperties({JpaProperties.class, TransactionProperties.class})
@Import(DataSourceInitializedPublisher.Registrar.class) @Import(DataSourceInitializedPublisher.Registrar.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware { public abstract class JpaBaseConfiguration implements BeanFactoryAware {
@ -81,8 +83,10 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
@Bean @Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
public PlatformTransactionManager transactionManager() { public PlatformTransactionManager transactionManager(TransactionProperties transactionProperties) {
return new JpaTransactionManager(); JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionProperties.applyTo(transactionManager);
return transactionManager;
} }
@Bean @Bean

View File

@ -0,0 +1,79 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.transaction;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
/**
* External configuration properties for a {@link org.springframework.transaction.PlatformTransactionManager} created by
* Spring. All {@literal spring.transaction.} properties are also applied to the {@code PlatformTransactionManager}.
*
* @author Kazuki Shimizu
* @since 1.5.0
*/
@ConfigurationProperties(prefix = "spring.transaction")
public class TransactionProperties {
/**
* The default transaction timeout (sec).
*/
private Integer defaultTimeout;
/**
* The indicating flag whether perform the rollback processing on commit failure (If perform rollback, set to the true).
*/
private Boolean rollbackOnCommitFailure;
public Integer getDefaultTimeout() {
return this.defaultTimeout;
}
public void setDefaultTimeout(Integer defaultTimeout) {
this.defaultTimeout = defaultTimeout;
}
public Boolean getRollbackOnCommitFailure() {
return this.rollbackOnCommitFailure;
}
public void setRollbackOnCommitFailure(Boolean rollbackOnCommitFailure) {
this.rollbackOnCommitFailure = rollbackOnCommitFailure;
}
/**
* Apply all transaction custom properties to a specified {@link PlatformTransactionManager} instance.
*
* @param transactionManager the target transaction manager
* @see AbstractPlatformTransactionManager#setDefaultTimeout(int)
* @see AbstractPlatformTransactionManager#setRollbackOnCommitFailure(boolean)
*/
public void applyTo(PlatformTransactionManager transactionManager) {
if (transactionManager instanceof AbstractPlatformTransactionManager) {
AbstractPlatformTransactionManager abstractPlatformTransactionManager =
(AbstractPlatformTransactionManager) transactionManager;
if (this.defaultTimeout != null) {
abstractPlatformTransactionManager.setDefaultTimeout(this.defaultTimeout);
}
if (this.rollbackOnCommitFailure != null) {
abstractPlatformTransactionManager.setRollbackOnCommitFailure(this.rollbackOnCommitFailure);
}
}
}
}

View File

@ -30,6 +30,7 @@ import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.boot.ApplicationHome; import org.springframework.boot.ApplicationHome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.XAConnectionFactoryWrapper; import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.boot.jta.XADataSourceWrapper; import org.springframework.boot.jta.XADataSourceWrapper;
@ -50,18 +51,21 @@ import org.springframework.util.StringUtils;
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration @Configuration
@EnableConfigurationProperties(AtomikosProperties.class) @EnableConfigurationProperties({AtomikosProperties.class, JtaProperties.class, TransactionProperties.class})
@ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class }) @ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
class AtomikosJtaConfiguration { class AtomikosJtaConfiguration {
private final JtaProperties jtaProperties; private final JtaProperties jtaProperties;
private final TransactionProperties transactionProperties;
AtomikosJtaConfiguration(JtaProperties jtaProperties) { AtomikosJtaConfiguration(JtaProperties jtaProperties, TransactionProperties transactionProperties) {
this.jtaProperties = jtaProperties; this.jtaProperties = jtaProperties;
this.transactionProperties = transactionProperties;
} }
@Bean(initMethod = "init", destroyMethod = "shutdownForce") @Bean(initMethod = "init", destroyMethod = "shutdownForce")
@ -111,7 +115,9 @@ class AtomikosJtaConfiguration {
@Bean @Bean
public JtaTransactionManager transactionManager(UserTransaction userTransaction, public JtaTransactionManager transactionManager(UserTransaction userTransaction,
TransactionManager transactionManager) { TransactionManager transactionManager) {
return new JtaTransactionManager(userTransaction, transactionManager); JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, transactionManager);
this.transactionProperties.applyTo(jtaTransactionManager);
return jtaTransactionManager;
} }
@Configuration @Configuration

View File

@ -28,7 +28,9 @@ import bitronix.tm.jndi.BitronixContext;
import org.springframework.boot.ApplicationHome; import org.springframework.boot.ApplicationHome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.XAConnectionFactoryWrapper; import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.boot.jta.XADataSourceWrapper; import org.springframework.boot.jta.XADataSourceWrapper;
import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor; import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor;
@ -46,17 +48,21 @@ import org.springframework.util.StringUtils;
* @author Josh Long * @author Josh Long
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Kazuki Shimizu
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration @Configuration
@EnableConfigurationProperties({JtaProperties.class, TransactionProperties.class})
@ConditionalOnClass({ JtaTransactionManager.class, BitronixContext.class }) @ConditionalOnClass({ JtaTransactionManager.class, BitronixContext.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
class BitronixJtaConfiguration { class BitronixJtaConfiguration {
private final JtaProperties jtaProperties; private final JtaProperties jtaProperties;
private final TransactionProperties transactionProperties;
BitronixJtaConfiguration(JtaProperties jtaProperties) { BitronixJtaConfiguration(JtaProperties jtaProperties, TransactionProperties transactionProperties) {
this.jtaProperties = jtaProperties; this.jtaProperties = jtaProperties;
this.transactionProperties = transactionProperties;
} }
@Bean @Bean
@ -105,7 +111,9 @@ class BitronixJtaConfiguration {
@Bean @Bean
public JtaTransactionManager transactionManager( public JtaTransactionManager transactionManager(
TransactionManager transactionManager) { TransactionManager transactionManager) {
return new JtaTransactionManager(transactionManager); JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(transactionManager);
this.transactionProperties.applyTo(jtaTransactionManager);
return jtaTransactionManager;
} }
@ConditionalOnClass(Message.class) @ConditionalOnClass(Message.class)

View File

@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.transaction.jta;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi; import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
@ -30,6 +32,7 @@ import org.springframework.transaction.jta.JtaTransactionManager;
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.2.0 * @since 1.2.0
*/ */
@Configuration @Configuration
@ -38,11 +41,20 @@ import org.springframework.transaction.jta.JtaTransactionManager;
"java:comp/TransactionManager", "java:appserver/TransactionManager", "java:comp/TransactionManager", "java:appserver/TransactionManager",
"java:pm/TransactionManager", "java:/TransactionManager" }) "java:pm/TransactionManager", "java:/TransactionManager" })
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
@EnableConfigurationProperties(TransactionProperties.class)
class JndiJtaConfiguration { class JndiJtaConfiguration {
private final TransactionProperties transactionProperties;
JndiJtaConfiguration(TransactionProperties transactionProperties) {
this.transactionProperties = transactionProperties;
}
@Bean @Bean
public JtaTransactionManager transactionManager() { public JtaTransactionManager transactionManager() {
return new JtaTransactionManagerFactoryBean().getObject(); JtaTransactionManager transactionManager = new JtaTransactionManagerFactoryBean().getObject();
this.transactionProperties.applyTo(transactionManager);
return transactionManager;
} }
} }

View File

@ -28,6 +28,8 @@ import org.jboss.tm.XAResourceRecoveryRegistry;
import org.springframework.boot.ApplicationHome; import org.springframework.boot.ApplicationHome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.transaction.TransactionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jta.XAConnectionFactoryWrapper; import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.boot.jta.XADataSourceWrapper; import org.springframework.boot.jta.XADataSourceWrapper;
import org.springframework.boot.jta.narayana.NarayanaBeanFactoryPostProcessor; import org.springframework.boot.jta.narayana.NarayanaBeanFactoryPostProcessor;
@ -47,18 +49,22 @@ import org.springframework.util.StringUtils;
* JTA Configuration for <a href="http://narayana.io/">Narayana</a>. * JTA Configuration for <a href="http://narayana.io/">Narayana</a>.
* *
* @author Gytis Trikleris * @author Gytis Trikleris
* @author Kazuki Shimizu
* @since 1.4.0 * @since 1.4.0
*/ */
@Configuration @Configuration
@ConditionalOnClass({ JtaTransactionManager.class, @ConditionalOnClass({ JtaTransactionManager.class,
com.arjuna.ats.jta.UserTransaction.class, XAResourceRecoveryRegistry.class }) com.arjuna.ats.jta.UserTransaction.class, XAResourceRecoveryRegistry.class })
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)
@EnableConfigurationProperties({JtaProperties.class, TransactionProperties.class})
public class NarayanaJtaConfiguration { public class NarayanaJtaConfiguration {
private final JtaProperties jtaProperties; private final JtaProperties jtaProperties;
private final TransactionProperties transactionProperties;
public NarayanaJtaConfiguration(JtaProperties jtaProperties) { public NarayanaJtaConfiguration(JtaProperties jtaProperties, TransactionProperties transactionProperties) {
this.jtaProperties = jtaProperties; this.jtaProperties = jtaProperties;
this.transactionProperties = transactionProperties;
} }
@Bean @Bean
@ -116,7 +122,9 @@ public class NarayanaJtaConfiguration {
@Bean @Bean
public JtaTransactionManager transactionManager(UserTransaction userTransaction, public JtaTransactionManager transactionManager(UserTransaction userTransaction,
TransactionManager transactionManager) { TransactionManager transactionManager) {
return new JtaTransactionManager(userTransaction, transactionManager); JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, transactionManager);
this.transactionProperties.applyTo(jtaTransactionManager);
return jtaTransactionManager;
} }
@Bean @Bean

View File

@ -58,6 +58,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -267,6 +269,42 @@ public class BatchAutoConfigurationTests {
.queryForList("select * from BATCH_JOB_EXECUTION"); .queryForList("select * from BATCH_JOB_EXECUTION");
} }
@Test
public void testCustomizeJpaTransactionManagerUsingProperties() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.transaction.default-timeout:30",
"spring.transaction.rollback-on-commit-failure:true");
this.context.register(TestConfiguration.class,
EmbeddedDataSourceConfiguration.class,
HibernateJpaAutoConfiguration.class, BatchAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
this.context.getBean(BatchConfigurer.class);
JpaTransactionManager transactionManager = JpaTransactionManager.class.cast(
this.context.getBean(BatchConfigurer.class).getTransactionManager());
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
@Test
public void testCustomizeDataSourceTransactionManagerUsingProperties() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.transaction.default-timeout:30",
"spring.transaction.rollback-on-commit-failure:true");
this.context.register(TestConfiguration.class,
EmbeddedDataSourceConfiguration.class,
BatchAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
this.context.getBean(BatchConfigurer.class);
DataSourceTransactionManager transactionManager = DataSourceTransactionManager.class.cast(
this.context.getBean(BatchConfigurer.class).getTransactionManager());
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
@Configuration @Configuration
protected static class EmptyConfiguration { protected static class EmptyConfiguration {

View File

@ -37,6 +37,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.template.Neo4jOperations; import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
@ -73,10 +74,21 @@ public class Neo4jDataAutoConfigurationTests {
.hasSize(1); .hasSize(1);
assertThat(this.context.getBeansOfType(SessionFactory.class)).hasSize(1); assertThat(this.context.getBeansOfType(SessionFactory.class)).hasSize(1);
assertThat(this.context.getBeansOfType(Neo4jOperations.class)).hasSize(1); assertThat(this.context.getBeansOfType(Neo4jOperations.class)).hasSize(1);
assertThat(this.context.getBeansOfType(Neo4jTransactionManager.class)).hasSize(1);
assertThat(this.context.getBeansOfType(OpenSessionInViewInterceptor.class)) assertThat(this.context.getBeansOfType(OpenSessionInViewInterceptor.class))
.isEmpty(); .isEmpty();
} }
@Test
public void customNeo4jTransactionManagerUsingProperties() {
load(null,
"spring.transaction.default-timeout=30",
"spring.transaction.rollback-on-commit-failure:true");
Neo4jTransactionManager transactionManager = this.context.getBean(Neo4jTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
@Test @Test
public void customSessionFactory() { public void customSessionFactory() {
load(CustomSessionFactory.class); load(CustomSessionFactory.class);

View File

@ -20,6 +20,7 @@ import javax.sql.DataSource;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -106,6 +107,19 @@ public class DataSourceTransactionManagerAutoConfigurationTests {
.isNotNull(); .isNotNull();
} }
@Test
public void testCustomizeDataSourceTransactionManagerUsingProperties() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.transaction.default-timeout:30",
"spring.transaction.rollback-on-commit-failure:true");
this.context.register(EmbeddedDataSourceConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class);
this.context.refresh();
DataSourceTransactionManager transactionManager = this.context.getBean(DataSourceTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
@EnableTransactionManagement @EnableTransactionManagement
protected static class SwitchTransactionsOn { protected static class SwitchTransactionsOn {

View File

@ -38,6 +38,7 @@ import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfigurati
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform; import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -171,6 +172,18 @@ public class HibernateJpaAutoConfigurationTests
.isEqualTo(TestJtaPlatform.class.getName()); .isEqualTo(TestJtaPlatform.class.getName());
} }
@Test
public void testCustomJpaTransactionManagerUsingProperties() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.transaction.default-timeout:30",
"spring.transaction.rollback-on-commit-failure:true");
setupTestConfiguration();
this.context.refresh();
JpaTransactionManager transactionManager = context.getBean(JpaTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
public static class TestJtaPlatform implements JtaPlatform { public static class TestJtaPlatform implements JtaPlatform {
@Override @Override

View File

@ -245,6 +245,32 @@ public class JtaAutoConfigurationTests {
assertThat(dataSource.getMaxPoolSize()).isEqualTo(10); assertThat(dataSource.getMaxPoolSize()).isEqualTo(10);
} }
@Test
public void atomikosCustomizeJtaTransactionManagerUsingProperties() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.transaction.default-timeout:30",
"spring.transaction.rollback-on-commit-failure:true");
this.context.register(AtomikosJtaConfiguration.class);
this.context.refresh();
JtaTransactionManager transactionManager = this.context.getBean(JtaTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
@Test
public void bitronixCustomizeJtaTransactionManagerUsingProperties() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.transaction.default-timeout:30",
"spring.transaction.rollback-on-commit-failure:true");
this.context.register(BitronixJtaConfiguration.class);
this.context.refresh();
JtaTransactionManager transactionManager = this.context.getBean(JtaTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
}
@Configuration @Configuration
@EnableConfigurationProperties(JtaProperties.class) @EnableConfigurationProperties(JtaProperties.class)
public static class JtaPropertiesConfiguration { public static class JtaPropertiesConfiguration {