Spring 的 bean 作用域(scope)类型
singleton:单例,默认作用域。
prototype:原型,每次创建一个新对象。
request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
session:会话,同一个会话共享一个实例,不同会话使用不用的实例。
global-session:全局会话,所有会话共享一个实例。
线程安全这个问题,要从单例与原型Bean分别进行说明。
(singleton)Bean:所有线程都共享一个单例实例Bean,因此是存在资源的竞争, 如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等,使用ThreadLocal的好处使得多线程场景下,多个线程对这个单例Bean的成员变量并不存在资源的竞争,因为ThreadLocal为每个线程保存线程私有的数据。这是一种以空间换时间的方式。当然也可以通过加锁的方法来解决线程安全,这种以时间换空间的场景在高并发场景下显然是不实际的。
下面分析下通过TreadLocal解决线程安全的三个类:
RequestContextHolder
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
//获取HttpServletRequest
HttpServletRequest request = requestAttributes.getRequest();
RequestContextHolder
public abstract class RequestContextHolder {
private static final boolean jsfPresent = ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");
public RequestContextHolder() {
}
------------------------------------省略部分代码-----------------------------------
@Nullable
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
if (attributes == null) {
attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();
}
return attributes;
}
------------------------------------省略部分代码-----------------------------------
LocaleContextHolder
Locale locale = LocaleContextHolder.getLocale();
System.out.println(locale.toString());//语言
LocaleContextHolder
public final class LocaleContextHolder {
private static final ThreadLocal<LocaleContext> localeContextHolder =
new NamedThreadLocal<>("LocaleContext");
private static final ThreadLocal<LocaleContext> inheritableLocaleContextHolder =
new NamedInheritableThreadLocal<>("LocaleContext");
// Shared default locale at the framework level
@Nullable
private static Locale defaultLocale;
// Shared default time zone at the framework level
@Nullable
private static TimeZone defaultTimeZone;
------------------------------------省略部分代码-----------------------------------
public static Locale getLocale() {
return getLocale(getLocaleContext());
}
------------------------------------省略部分代码-----------------------------------
@Nullable
public static LocaleContext getLocaleContext() {
LocaleContext localeContext = localeContextHolder.get();
if (localeContext == null) {
localeContext = inheritableLocaleContextHolder.get();
}
return localeContext;
}
------------------------------------省略部分代码-----------------------------------
TransactionSynchronizationManager
@Transactional
public void doInTransaction() {
TransactionSynchronizationManager.bindResource("key", "value");//ThreadLocal维护
TransactionSynchronizationManager.registerSynchronization
(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
System.out.println("transaction commit");
}
});
}
TransactionSynchronizationManager 部分源码
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
------------------------------------省略部分代码-----------------------------------
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
Thread.currentThread().getName() + "]");
}
}
------------------------------------省略部分代码-----------------------------------
public static void registerSynchronization(TransactionSynchronization synchronization)
throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
if (!isSynchronizationActive()) {
throw new IllegalStateException("Transaction synchronization is not active");
}
synchronizations.get().add(synchronization);
}
=========================================================================================================================================
我只是一粒简单的石子,未曾想掀起惊涛骇浪,也不愿随波逐流
每个人都很渺小,努力做自己,不虚度光阴,做真实的自己,无论是否到达目标点,既然选择了出发,便勇往直前
我不能保证所有的东西都是对的,但都是能力范围内的深思熟虑和反复斟酌