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);
    }

=========================================================================================================================================

              我只是一粒简单的石子,未曾想掀起惊涛骇浪,也不愿随波逐流

              每个人都很渺小,努力做自己,不虚度光阴,做真实的自己,无论是否到达目标点,既然选择了出发,便勇往直前

              我不能保证所有的东西都是对的,但都是能力范围内的深思熟虑和反复斟酌