一、demo实例
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
/**
* Bean 是否缓存示例
*/
public class BeanCachingDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册 Configuration Class
context.register(BeanCachingDemo.class);
// 启动 Spring 应用上下文
context.refresh();
// BeanCachingDemo 是 Configuration Class,Singleton Scope Bean
BeanCachingDemo beanCachingDemo = context.getBean(BeanCachingDemo.class);
for (int i = 0; i < 9; i++) {
// Singleton Scope Bean 是存在缓存
System.out.println(beanCachingDemo == context.getBean(BeanCachingDemo.class));
}
User user = context.getBean(User.class);
for (int i = 0; i < 9; i++) {
// Prototype Scope Bean
System.out.println(user == context.getBean(User.class));
}
// 关闭 Spring 应用上下文
context.close();
}
@Bean
@Scope("prototype") // 原型 scope
public static User user() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
}
由结果我们可以看出,每次获取的单例Bean,都是相同的;每次获取的原型Bean,每次都是不同的。
二、单例Bean(Singleton)会被缓存
1、当我们调用getBean()方法时,会执行以下逻辑:
resolveNamedBean方法中会调用getBean方法,最终会执行org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// ...
// Create bean instance.
if (mbd.isSingleton()) {
// 获取单实例bean
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ...
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName); // 缓存,如果有直接返回
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 如果是true,会被缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton
// 此处的singletonObjects 就是单例bean的缓存,它是一个ConcurrentHashMap
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
三、原型Bean(Prototype)不会缓存
原型Bean每次获取都会创建新的bean,并不会缓存。
// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
四、其他Scope Bean
- request:每个ServletRequest内部缓存,生命周期维持在每次HTTP请求。
- session:每个HttpSession内部缓存,生命周期维持在每个用户HTTP会话。
- application:当前Serviet应用内部缓存。
1、我们继续看else判断逻辑
// // org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// 调用了scope的get方法
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
关于scope,我们可以查看该文章:
详解SpringBean的作用域(Scopes)
2、我们发现,request和session的scope,都继承了AbstractRequestAttributesScope,我们继续查看其get方法
我们发现是用attribute来实现的。
// org.springframework.web.context.request.AbstractRequestAttributesScope#get
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
attributes.setAttribute(name, scopedObject, getScope());
// Retrieve object again, registering it for implicit session attribute updates.
// As a bonus, we also allow for potential decoration at the getAttribute level.
Object retrievedObject = attributes.getAttribute(name, getScope());
if (retrievedObject != null) {
// Only proceed with retrieved object if still present (the expected case).
// If it disappeared concurrently, we return our locally created instance.
scopedObject = retrievedObject;
}
}
return scopedObject;
}
3、而application的scope,是基于ServletContext来实现的:
// org.springframework.web.context.support.ServletContextScope#get
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Object scopedObject = this.servletContext.getAttribute(name);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
this.servletContext.setAttribute(name, scopedObject);
}
return scopedObject;
}
转载:https://blog.csdn.net/A_art_xiang/article/details/128466494
查看评论