Reinstate Bitronix's default server ID, provide property to override it
Previously, Bitronix's server ID was hard-coded to be spring-boot-jta-bitronix. This created the possibility of multiple transaction managers performing recovery on each other's behalf as they would be unable to identify their own XIDs due to the common server ID. This commit reinstates the default (which is the IP address of the machine on which Bitronix is running), and introduces a new property, spring.jta.transaction-manager-id, that can be used to configure the id for both Atomikos and Bitronix. A cautionary note has also been added to the documentation for Atomikos and Bitronix explaining the need to configure this property. Closes gh-1548
This commit is contained in:
parent
d251b51338
commit
01fd8cb8f3
|
|
@ -49,6 +49,7 @@ import com.atomikos.icatch.jta.UserTransactionManager;
|
|||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
|
|
@ -71,6 +72,10 @@ class AtomikosJtaConfiguration {
|
|||
public UserTransactionService userTransactionService(
|
||||
AtomikosProperties atomikosProperties) {
|
||||
Properties properties = new Properties();
|
||||
if (StringUtils.hasText(this.jtaProperties.getTransactionManagerId())) {
|
||||
properties.setProperty("com.atomikos.icatch.tm_unique_name",
|
||||
this.jtaProperties.getTransactionManagerId());
|
||||
}
|
||||
properties.setProperty("com.atomikos.icatch.log_base_dir", getLogBaseDir());
|
||||
properties.putAll(atomikosProperties.asProperties());
|
||||
return new UserTransactionServiceImp(properties);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import bitronix.tm.jndi.BitronixContext;
|
|||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
|
|
@ -60,7 +61,9 @@ class BitronixJtaConfiguration {
|
|||
@ConfigurationProperties(prefix = JtaProperties.PREFIX)
|
||||
public bitronix.tm.Configuration bitronixConfiguration() {
|
||||
bitronix.tm.Configuration config = TransactionManagerServices.getConfiguration();
|
||||
config.setServerId("spring-boot-jta-bitronix");
|
||||
if (StringUtils.hasText(this.jtaProperties.getTransactionManagerId())) {
|
||||
config.setServerId(this.jtaProperties.getTransactionManagerId());
|
||||
}
|
||||
File logBaseDir = getLogBaseDir();
|
||||
config.setLogPart1Filename(new File(logBaseDir, "part1.btm").getAbsolutePath());
|
||||
config.setLogPart2Filename(new File(logBaseDir, "part2.btm").getAbsolutePath());
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.springframework.transaction.jta.JtaTransactionManager;
|
|||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = JtaProperties.PREFIX, ignoreUnknownFields = true)
|
||||
|
|
@ -35,6 +36,8 @@ public class JtaProperties {
|
|||
|
||||
private String logDir;
|
||||
|
||||
private String transactionManagerId;
|
||||
|
||||
public void setLogDir(String logDir) {
|
||||
this.logDir = logDir;
|
||||
}
|
||||
|
|
@ -43,4 +46,12 @@ public class JtaProperties {
|
|||
return this.logDir;
|
||||
}
|
||||
|
||||
public String getTransactionManagerId() {
|
||||
return this.transactionManagerId;
|
||||
}
|
||||
|
||||
public void setTransactionManagerId(String transactionManagerId) {
|
||||
this.transactionManagerId = transactionManagerId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,28 +16,41 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.jta;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.jta.XADataSourceWrapper;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosDependsOnBeanFactoryPostProcessor;
|
||||
import org.springframework.boot.jta.atomikos.AtomikosProperties;
|
||||
import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
import com.atomikos.icatch.config.UserTransactionService;
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
|
|
@ -45,6 +58,7 @@ import static org.mockito.Mockito.mock;
|
|||
*
|
||||
* @author Josh Long
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class JtaAutoConfigurationTests {
|
||||
|
||||
|
|
@ -53,6 +67,11 @@ public class JtaAutoConfigurationTests {
|
|||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void cleanUpLogs() {
|
||||
FileSystemUtils.deleteRecursively(new File("target/transaction-logs"));
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
if (this.context != null) {
|
||||
|
|
@ -94,6 +113,62 @@ public class JtaAutoConfigurationTests {
|
|||
this.context.getBean(JtaTransactionManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultBitronixServerId() throws UnknownHostException {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
JtaPropertiesConfiguration.class, BitronixJtaConfiguration.class);
|
||||
String serverId = this.context.getBean(bitronix.tm.Configuration.class)
|
||||
.getServerId();
|
||||
assertThat(serverId, is(equalTo(InetAddress.getLocalHost().getHostAddress())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customBitronixServerId() throws UnknownHostException {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"spring.jta.transactionManagerId:custom");
|
||||
this.context.register(JtaPropertiesConfiguration.class,
|
||||
BitronixJtaConfiguration.class);
|
||||
this.context.refresh();
|
||||
String serverId = this.context.getBean(bitronix.tm.Configuration.class)
|
||||
.getServerId();
|
||||
assertThat(serverId, is(equalTo("custom")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultAtomikosTransactionManagerName() throws UnknownHostException {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"spring.jta.logDir:target/transaction-logs");
|
||||
this.context.register(JtaPropertiesConfiguration.class,
|
||||
AtomikosJtaConfiguration.class);
|
||||
this.context.refresh();
|
||||
|
||||
File epochFile = new File("target/transaction-logs/"
|
||||
+ InetAddress.getLocalHost().getHostAddress() + ".tm0.epoch");
|
||||
assertTrue(epochFile.isFile());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customAtomikosTransactionManagerName() throws BeansException, Exception {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"spring.jta.transactionManagerId:custom",
|
||||
"spring.jta.logDir:target/transaction-logs");
|
||||
this.context.register(JtaPropertiesConfiguration.class,
|
||||
AtomikosJtaConfiguration.class);
|
||||
this.context.refresh();
|
||||
|
||||
File epochFile = new File("target/transaction-logs/custom0.epoch");
|
||||
assertTrue(epochFile.isFile());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(JtaProperties.class)
|
||||
public static class JtaPropertiesConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class CustomTransactionManagerConfig {
|
||||
|
||||
|
|
|
|||
|
|
@ -2047,6 +2047,12 @@ customize the Atomikos `UserTransactionServiceIml`. See the
|
|||
{dc-spring-boot}/jta/atomikos/AtomikosProperties.{dc-ext}[`AtomikosProperties` javadoc]
|
||||
for complete details.
|
||||
|
||||
CAUTION: To ensure that multiple transaction managers can safely coordinate the same
|
||||
resource managers, each Atomikos instance must be configured with a unique ID. By default
|
||||
this ID is the IP address of the machine on which Atomikos is running. To ensure
|
||||
uniqueness in production, you should configure the `spring.jta.transaction-manager-id`
|
||||
property with a different value for each instance of your application.
|
||||
|
||||
|
||||
|
||||
=== Using a Bitronix transaction manager
|
||||
|
|
@ -2063,6 +2069,12 @@ are also bound to the `bitronix.tm.Configuration` bean, allowing for complete
|
|||
customization. See the http://btm.codehaus.org/api/2.0.1/bitronix/tm/Configuration.html[Bitronix
|
||||
documentation] for details.
|
||||
|
||||
CAUTION: To ensure that multiple transaction managers can safely coordinate the same
|
||||
resource managers, each Bitronix instance must be configured with a unique ID. By default
|
||||
this ID is the IP address of the machine on which Bitronix is running. To ensure
|
||||
uniqueness in production, you should configure the `spring.jta.transaction-manager-id`
|
||||
property with a different value for each instance of your application.
|
||||
|
||||
|
||||
|
||||
=== Using a Java EE managed transaction manager
|
||||
|
|
|
|||
Loading…
Reference in New Issue