GH-3733 Configure TxManager for DefLockRepository (#3782)
* GH-3733 Configure TxManager for DefLockRepository Fixes https://github.com/spring-projects/spring-integration/issues/3733 The `@Transactional` resolves a primary `TransactionManager` bean from the application context which might not be sufficient for all the use-case. To make it work with the custom (or specific) `TransactionManager` we have to extend a `DefaultLockRepository` and override all those `@Transactional` method * Change the logic of the `DefaultLockRepository` from `@Transactional` to the `TransactionTemplate` and use provided `TransactionManager` or resolve one from the application context * Adjust tests to use explicit `TransactionManager` and call `afterSingletonsInstantiated()` to initialize a default `TransactionTemplate` * Mention the change in the docs * * Extracted all the `TransactionTemplate`s to the properties for caching * Add `BeanInitializationException` for no-unique `PlatformTransactionManager` bean in the `afterSingletonsInstantiated()` * Fix language in the exception message Co-authored-by: Gary Russell <grussell@vmware.com> Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2022 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.
|
||||
@@ -23,10 +23,10 @@ import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.integration.jdbc.lock.DefaultLockRepository;
|
||||
import org.springframework.integration.jdbc.lock.JdbcLockRegistry;
|
||||
@@ -34,6 +34,7 @@ import org.springframework.integration.leader.Context;
|
||||
import org.springframework.integration.leader.DefaultCandidate;
|
||||
import org.springframework.integration.leader.event.LeaderEventPublisher;
|
||||
import org.springframework.integration.support.leader.LockRegistryLeaderInitiator;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
@@ -49,7 +50,7 @@ public class JdbcLockRegistryLeaderInitiatorTests {
|
||||
|
||||
public static EmbeddedDatabase dataSource;
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void init() {
|
||||
dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
@@ -58,7 +59,7 @@ public class JdbcLockRegistryLeaderInitiatorTests {
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@AfterAll
|
||||
public static void destroy() {
|
||||
dataSource.shutdown();
|
||||
}
|
||||
@@ -70,7 +71,9 @@ public class JdbcLockRegistryLeaderInitiatorTests {
|
||||
List<LockRegistryLeaderInitiator> initiators = new ArrayList<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
DefaultLockRepository lockRepository = new DefaultLockRepository(dataSource);
|
||||
lockRepository.setTransactionManager(new DataSourceTransactionManager(dataSource));
|
||||
lockRepository.afterPropertiesSet();
|
||||
lockRepository.afterSingletonsInstantiated();
|
||||
LockRegistryLeaderInitiator initiator = new LockRegistryLeaderInitiator(
|
||||
new JdbcLockRegistry(lockRepository),
|
||||
new DefaultCandidate("foo", "bar"));
|
||||
@@ -170,7 +173,7 @@ public class JdbcLockRegistryLeaderInitiatorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Looks like an embedded DBd is not fully cleared if we don't close application context")
|
||||
@Disabled("Looks like an embedded DBd is not fully cleared if we don't close application context")
|
||||
public void testLostConnection() throws InterruptedException {
|
||||
CountDownLatch granted = new CountDownLatch(1);
|
||||
CountingPublisher countingPublisher = new CountingPublisher(granted);
|
||||
|
||||
@@ -79,7 +79,7 @@ public class JdbcLockRegistryDifferentClientTests {
|
||||
this.registry.expireUnusedOlderThan(0);
|
||||
this.client.close();
|
||||
this.child = new AnnotationConfigApplicationContext();
|
||||
this.child.register(DefaultLockRepository.class);
|
||||
this.child.registerBean("childLockRepository", DefaultLockRepository.class, this.dataSource);
|
||||
this.child.setParent(this.context);
|
||||
this.child.refresh();
|
||||
}
|
||||
@@ -195,7 +195,9 @@ public class JdbcLockRegistryDifferentClientTests {
|
||||
for (int j = 0; j < 20; j++) {
|
||||
Callable<Boolean> task = () -> {
|
||||
DefaultLockRepository client = new DefaultLockRepository(this.dataSource);
|
||||
client.setApplicationContext(this.context);
|
||||
client.afterPropertiesSet();
|
||||
client.afterSingletonsInstantiated();
|
||||
Lock lock = new JdbcLockRegistry(client).obtain("foo");
|
||||
try {
|
||||
if (locked.isEmpty() && lock.tryLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS)) {
|
||||
@@ -231,9 +233,13 @@ public class JdbcLockRegistryDifferentClientTests {
|
||||
@Test
|
||||
public void testExclusiveAccess() throws Exception {
|
||||
DefaultLockRepository client1 = new DefaultLockRepository(dataSource);
|
||||
client1.setApplicationContext(this.context);
|
||||
client1.afterPropertiesSet();
|
||||
final DefaultLockRepository client2 = new DefaultLockRepository(dataSource);
|
||||
client1.afterSingletonsInstantiated();
|
||||
DefaultLockRepository client2 = new DefaultLockRepository(dataSource);
|
||||
client2.setApplicationContext(this.context);
|
||||
client2.afterPropertiesSet();
|
||||
client2.afterSingletonsInstantiated();
|
||||
Lock lock1 = new JdbcLockRegistry(client1).obtain("foo");
|
||||
final BlockingQueue<Integer> data = new LinkedBlockingQueue<>();
|
||||
final CountDownLatch latch1 = new CountDownLatch(1);
|
||||
@@ -278,10 +284,14 @@ public class JdbcLockRegistryDifferentClientTests {
|
||||
public void testOutOfDateLockTaken() throws Exception {
|
||||
DefaultLockRepository client1 = new DefaultLockRepository(dataSource);
|
||||
client1.setTimeToLive(100);
|
||||
client1.setApplicationContext(this.context);
|
||||
client1.afterPropertiesSet();
|
||||
client1.afterSingletonsInstantiated();
|
||||
DefaultLockRepository client2 = new DefaultLockRepository(dataSource);
|
||||
client2.setTimeToLive(100);
|
||||
client2.setApplicationContext(this.context);
|
||||
client2.afterPropertiesSet();
|
||||
client2.afterSingletonsInstantiated();
|
||||
Lock lock1 = new JdbcLockRegistry(client1).obtain("foo");
|
||||
final BlockingQueue<Integer> data = new LinkedBlockingQueue<>();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
@@ -316,10 +326,14 @@ public class JdbcLockRegistryDifferentClientTests {
|
||||
public void testRenewLock() throws Exception {
|
||||
DefaultLockRepository client1 = new DefaultLockRepository(dataSource);
|
||||
client1.setTimeToLive(500);
|
||||
client1.setApplicationContext(this.context);
|
||||
client1.afterPropertiesSet();
|
||||
client1.afterSingletonsInstantiated();
|
||||
DefaultLockRepository client2 = new DefaultLockRepository(dataSource);
|
||||
client2.setTimeToLive(500);
|
||||
client2.setApplicationContext(this.context);
|
||||
client2.afterPropertiesSet();
|
||||
client2.afterSingletonsInstantiated();
|
||||
JdbcLockRegistry registry = new JdbcLockRegistry(client1);
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
final BlockingQueue<Integer> data = new LinkedBlockingQueue<>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2021 the original author or authors.
|
||||
* Copyright 2016-2022 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.
|
||||
@@ -36,6 +36,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
@@ -67,6 +68,9 @@ public class JdbcLockRegistryTests {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
@BeforeEach
|
||||
public void clear() {
|
||||
this.registry.expireUnusedOlderThan(0);
|
||||
@@ -143,7 +147,9 @@ public class JdbcLockRegistryTests {
|
||||
public void testReentrantLockAfterExpiration() throws Exception {
|
||||
DefaultLockRepository client = new DefaultLockRepository(dataSource);
|
||||
client.setTimeToLive(1);
|
||||
client.setApplicationContext(this.context);
|
||||
client.afterPropertiesSet();
|
||||
client.afterSingletonsInstantiated();
|
||||
JdbcLockRegistry registry = new JdbcLockRegistry(client);
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
assertThat(lock1.tryLock()).isTrue();
|
||||
|
||||
Reference in New Issue
Block a user