一、.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 userManager
bean, 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代理)不适用于此处!