spring 自定义事物同步器(一): TransactionSynchronizationManager 解析
一、.JPA 获取 Hibernate的session
try {
session = entityManager.unwrap(Session.class);
} catch (Exception e) {// from transactionTemplate?
//throw new IllegalStateException("No transactional EntityManager available");
EntityManagerFactory entityManagerFactory = jpaTransactionManager.getEntityManagerFactory();
EntityManagerHolder holder;
if(TransactionSynchronizationManager.hasResource(entityManagerFactory)){
holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(entityManagerFactory);
}else{
holder = new EntityManagerHolder(entityManagerFactory.createEntityManager());
TransactionSynchronizationManager.bindResource(entityManagerFactory, holder);
}
session = holder.getEntityManager().unwrap(Session.class);
}
二、TransactionSynchronizationManager.getResource()
/**
* Retrieve a resource for the given key that is bound to the current thread.
* @param key the key to check (usually the resource factory)
* @return a value bound to the current thread (usually the active
* resource object), or {@code null} if none
* @see ResourceTransactionManager#getResourceFactory()
*/
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
三、TransactionSynchronizationUtils.unwrapResourceIfNecessary(key)
/**
* Unwrap the given resource handle if necessary; otherwise return
* the given handle as-is.
* @see org.springframework.core.InfrastructureProxy#getWrappedObject()
*/
static Object unwrapResourceIfNecessary(Object resource) {
Assert.notNull(resource, "Resource must not be null");
Object resourceRef = resource;
// unwrap infrastructure proxy
if (resourceRef instanceof InfrastructureProxy) {
resourceRef = ((InfrastructureProxy) resourceRef).getWrappedObject();
}
if (aopAvailable) {
// now unwrap scoped proxy
resourceRef = ScopedProxyUnwrapper.unwrapIfNecessary(resourceRef);
}
return resourceRef;
}
四、ScopedProxy
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> <bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
In the preceding example, the singleton bean userManager is injected with a reference to the HTTP Session-scoped bean userPreferences. The salient point here is that the userManager bean is a singleton: it will be instantiated exactly once per container, and its dependencies (in this case only one, the userPreferences bean) are also injected only once. This means that the userManager bean will only operate on the exact same userPreferences object, that is, the one that it was originally injected with.
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived scoped bean, for example injecting an HTTP Session-scoped collaborating bean as a dependency into singleton bean. Rather, you need a single userManager object, and for the lifetime of an HTTP Session, you need a userPreferences object that is specific to said HTTP Session. Thus the container creates an object that exposes the exact same public interface as the UserPreferences class (ideally an object that is a UserPreferences instance) which can fetch the realUserPreferences object from the scoping mechanism (HTTP request, Session, etc.). The container injects this proxy object into the userManagerbean, which is unaware that this UserPreferences reference is a proxy. In this example, when a UserManager instance invokes a method on the dependency-injected UserPreferences object, it actually is invoking a method on the proxy. The proxy then fetches the real UserPreferences object from (in this case) the HTTP Session, and delegates the method invocation onto the retrieved real UserPreferences object.
引用:spring docs
五、InfrastructureProxy 结构代理
Interface to be implemented by transparent resource proxies that need to be considered as equal to the underlying resource,
for example for consistent lookup key comparisons. Note that this interface does imply such special semantics and does not
constitute a general-purpose mixin!
Such wrappers will automatically be unwrapped for key comparisons in TransactionSynchronizationManager. Only fully transparent
proxies, e.g. for redirection or service lookups, are supposed to implement this interface. Proxies that decorate the target object
with new behavior, such as AOP proxies, do not qualify here!
被认为等同于底层资源的透明资源代理要实现的接口,例如用于一致的查找的关键字比较。注意,这个接口意味着这样的特殊语义,并不构成一般用途的聚合!
这种包装器将在TransactionSynchronizationManager中自动被拆箱来进行关键字比较。只有完全透明的代理,例如 对于重定向或服务查找,应该实现此接口。
使用新行为来装饰目标对象的代理(例如AOP代理)不适用于此处!
spring 自定义事物同步器(一): TransactionSynchronizationManager 解析的更多相关文章
- spring自定义事务同步器(二):借助redisson实现自己的同步器
1. 借助redis的java客户端redisson实现自己的事物同步器 @Override public void lockWithinCurrentTransaction(Object key) ...
- [转载]开发 Spring 自定义视图和视图解析器
原文出处 http://www.ibm.com/developerworks/cn/java/j-lo-springview/ 概述 Spring 3.0 默认包含了多种视图和视图解析器,比如 JSP ...
- 这一次搞懂Spring自定义标签以及注解解析原理
前言 在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如何解析的.同时我们常用的注解如:@Se ...
- Spring源码-IOC部分-自定义IOC容器及Bean解析注册【4】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- spring 自定义解析类
设计配置属性和JavaBean 编写XSD文件 编写NamespaceHandler和BeanDefinitionParser完成解析工作 编写spring.handlers和spring.schem ...
- spring的事物实现
Spring的事物主要有三个接口 PlatformTransactionManager. 根据TransactionDefinition配置的事物信息创建事物 TransactionDefinitio ...
- Spring自定义类扫描器 ClassPathScanningCandidateComponentProvider
项目中有个需求 读取xml文件,然后 对xml文件进行解析,比如如果是 Gender=0/1的话,分别代表男女. 所以需要在构造函数之后,初始化bean之前进行过滤解析 xml文件: <inte ...
- spring 自定义标签的实现
在我们进行Spring 框架开发中,估计用到最多的就是bean 标签吧,其实在Spring中像<mvc/><context/>这类标签以及在dubbo配置的标签都是属于自定义的 ...
- spring基础---->spring自定义初始化(二)
这里新增了对ref属性的支持,并且过滤了已经解析的元素.人生有两个词很棒,一言不合和不提也罢. spring自定义对ref属性支持 项目的结构如下:新增一个ThirdBean类,修改了ParseXml ...
随机推荐
- 转:linux添加用户
功能说明:建立用户帐号. 语 法:useradd [-mMnr][-c <备注>][-d <登入目录>][-e <有效期限>][-f <缓冲天数>][- ...
- java自带线程池和队列详细讲解<转>
Java线程池使用说明 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后 ...
- Sys未定义处理方法
网上很多方法都试过,但是我发现,如果我把iis的端口号换一下,然后重新部署,就正常了,然后你可以再换回原来的端口号,也不会再报错了,应该是微软的一个bug,不知道大伙有什么更好的办法么
- 在Javascript弹出窗口中输入换行符
private void showMessage(string strMsg) { Page.RegisterStartupScript("scriptStr", "&l ...
- selenium测试环境搭建(一)
selenium测试环境搭建 下载资源 1. selenium-java-2.53.0.zip 下载地址:http://pan.baidu.com/s/1dFDf27Z 2. Firefox Set ...
- install phalcon on mac with XAMPP
首先使用brew安装对应版本的phalcon,参考https://docs.phalconphp.com/en/latest/reference/tutorial.html 安装好后会有 phalco ...
- Thinkphp新增字段无法插入到数据库问题
Thinkphp框架开发过程中,因需求需要改动数据表,新增了几个字段. 调用 M(‘xxx’)->add($data) 插入值时,新增的字段数据总是插入不进去,每次都是默认的值,于是恍然—-缓存 ...
- C# 创建XML文件
private void CreateXMLFile(string pathAndFileName) { XmlDocument doc = new XmlDocument(); XmlElement ...
- 打印出现:You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:
解决办法: 第一种:Product -> Target -> Capabilities -> Background Modes -> 勾选Remote notification ...
- SQL Server计算列
计算列由可以使用同一表中的其他列的表达式计算得来.表达式可以是非计算列的列名.常量.函数,也可以是用一个或多个运算符连接的上述元素的任意组合.表达式不能为子查询. 例如,在 AdventureWork ...