Spring 的 bean 做用域(scope)類型java
一、singleton:單例,默認做用域。安全
二、prototype:原型,每次建立一個新對象。session
三、request:請求,每次Http請求建立一個新對象,適用於WebApplicationContext環境下。多線程
四、session:會話,同一個會話共享一個實例,不一樣會話使用不用的實例。併發
五、global-session:全局會話,全部會話共享一個實例。mvc
線程安全這個問題,要從單例與原型Bean分別進行說明。ide
單例Bean:高併發
原型(prototype)Bean:每次建立一個新對象,也就是線程之間並不存在Bean共享,天然是不會有線程安全的問題。
spa
對於有狀態的bean,Spring官方提供的bean,通常提供了經過ThreadLocal去解決線程安全的方法,好比RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等,使用ThreadLocal的好處 使得多線程場景下,多個線程對這個單例Bean的成員變量並不存在資源的競爭,由於ThreadLocal爲每一個線程保存線程私有的數據。這是一種以空間換時間的方式。固然也能夠經過加鎖的方法來解決線程安全,這種以時間換空間的場景在高併發場景下顯然是不實際的。prototype
下面分析下經過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); }