-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Description
Ben Rowlands opened SPR-5035 and commented
Spring has no extension point to provide custom resolution of transaction resources. This hook is required to implement a "lazy enlistment" transaction manager.
A "lazy-enlistement" transaction manager differs from Springs "out-the-box" single resource transaction managers in that transaction resources (JMS connections or JDBC connections) are bound to the transaction when they are first used. The transaction manager collects resources during the life of the transaction rather than forcing developers to declare the resources they anticipate they will use upfront. Our developers find this programming model simpler and vastly reduces configuration overhead. Once a transaction manager is defined and code executed inside the transaction boundary any resources used are implicitly bound to the transaction.
The following pattern is used extensively throughout Springs resource handling code, for example in DataSourceUtils and ConnectionFactoryUtils:
public Resource doGetResource(ResourceFactory factory) {
Resource resource = getResourceFromTSM(factory);
// (1) resource found in transaction
if (resource != null){
return resource;
}
// (2) resource not found, create a new resource
resource = factory.getResource();
if (isSynchronizationActive()) {
addResourceToTSM(factory,resource);
addSynchronizationToCleanupResource(resource);
}
return resource;
}
Branch (2) may appear to show lazy creation of the resource however this can't be used for the following reasons:
* No mechanism exists to get notified of the resource's addition to the TransactionSynchronizationManager.
* The resource cleanup synchronization may cleanup the resource before the transaction manager enters the commit phase (as a result of closing of the connection in beforeCompletion). There is no way to disable this synchronization from been added.
* There is no control over configuration of the resource, for example, after getting a JDBC Connection (the Resource) from a DataSource (the ResourceFacotry?) one must disable auto-commit in addition to other connection preparation such as configuring the isolation level.
Spring's transaction managers pre-populate the TransactionSynchronizationManager with the resource(s) they will manage so transactional resources are always found and branch (1) is taken.
A transaction manager supporting "lazy enlistment" would need to plug in its own resource resolution strategy before Spring takes its fallback logic in (2).
We propose an extension point to be added to TransactionSynchronizationManager. A sketch of the extension point API is shown below:
interface TransactionResourceResolver
{
public Object resolveResource(Object key);
}
The following API would be used to register a custom strategy with the current transaction:
TransactionSynchronizationManager.setResourceResolver( resolver );
resolveResource() is invoked from TransactionSynchronizationManager#getResource(key) when the key is unbound. To clarify, the logic in getResource() would follow this pattern:
public Object getResource(Object key) {
// 1) Check resources map
Object resource = resources.get(key);
if (resource != null){
return resource;
}
// 2) Consult custom strategy
Object resource = resolver.resolveResource(key);
if (resource != null)
{
resources.put(key, resource);
return resource;
}
// 3) Give up
return null;
}
This small extension enables the implementation of the "lazy enlistment" Transaction Manager. Note, this is similar to the request in #7996. This new issue clarifies the requests made in the comments with a focus on lazy enlistment.
Issue Links:
- Provide listener for TransactionSynchronizationManager [SPR-3311] #7996 Provide listener for TransactionSynchronizationManager
6 votes, 10 watchers