Spring之单例Bean的创建

更新时间:2023-05-04 17:01:49 阅读: 评论:0

Spring之单例Bean的创建
本⽂基于Spring 5.2.7
Spring最基础的功能是IoC容器,能够容纳bean,就需要实例化bean并放⼊容器内。在Spring中,bean是有范围属性的,这个范围是时间、空间维度的,叫做scope,⼀个bean如果存在与应⽤整个⽣命期内,就是⼀个shared bean instance,他的scope值是singleton,如果⼀个bean只存在于应⽤⽣命器的⼀段时间内,是⼀个prototype bean instance,他的scope值就是prototype。这⾥的prototype意思和设计模式中的原型模式类似,就是直接创建对象的意思。
⼀、Spring的设计
对于bean的创建,⽤户是不需要知道的,⽤户需要知道的是获取bean,所以Spring将创建bean的⼊⼝放在获取bean中。
⼆、创建bean的关键点
创建⼀个bean有⼀些关键步骤:
1、实例化,⽣成引⽤值,这个动作由jdk实现,Spring不⽤⼲涉
2、对象需要⼀次或多次代理,Spring需要完成代理对象创建
3、完成依赖注⼊晚安语句
4、当依赖注⼊时发⽣环形依赖,且同时有代理对象,Spring要处理好
5、只有scope=singleton的bean才会添加到缓存中
6、只有scope=singleton且允许环形依赖才会添加到第三级缓存singletonFactories中,也就是说基本只要是单例的bean,都会到三级缓存中
7、添加到第三级缓存中的是⼀个ObjectFactory类型的函数接⼝,取出的时候会执⾏
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()⽅法(如果存在的话)
8、
三、单例bean的创建步骤
1、通过反射实例化bean,⽣成原⽣对象引⽤
2、如果是scope=singleton且允许环形依赖,添加⼀个getEarlyBeanReference()到第三级缓存中(处理⼀下对象)
3、populateBean(),填充bean引⽤的对象,也就是依赖注⼊,这⾥就是可能触发环形依赖的地⽅
在给引⽤赋值时,需要创建引⽤对象,如果依赖的应⽤对象引⽤的当前对象,那么就会触发从三级缓存中获取当前对象,执⾏早期引⽤的逻辑,然后升级到⼆级缓存,并删除三级缓存中当前对象,此时⼆级缓存中的对象依然是未初始化完成的对象,注意,在升级到⼆级缓存之后,如果还有动态代理逻辑要处理,这是不⾏的,因为此时引⽤已经给出去了,引⽤的那些对象是拿不到最终的代理对象的,这样会使某些功能失效。所以如果想要在循环依赖时将代理对象返回给其他对象,必须在将代理的创建逻辑放在SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()豆角焖面的家常做法 中。
4、initializeBean(),在完成所有的依赖注⼊后,进⾏bean的各种后置处理,可以⽣成代理对象
5、如果scope=singleton且允许环形依赖,检测⼀下bean的类型和被其他类型引⽤的类型是否⼀致,不⼀致就要报错
6、初始化完毕后,调⽤addSingleton()⽅法,将bean从电脑锁屏时间怎么设置 ⼆级缓存中提升到⼀级缓存
所以,为什么需要三级缓存,
三、BeanFactory获取bean
Spring中获取bean的⼊⼝都在AbstractBeanFactory中,创建bean的⼊⼝也在这⾥。
org.springframework.beans.factory.support.AbstractBeanFactory
这⾥getBean()⽅法⼀共重载了4次,最终都调⽤了doGetBean()⽅法
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, fal);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, fal);
}
@Override
public Object getBean(String name, args) throws BeansException {
return doGetBean(name, null, args, fal);
}
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to u when creating a bean instance using explicit arguments
* (only applied when creating a new instance as oppod to retrieving an existing one)
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
public <T> T getBean(String name, @Nullable Class<T> requiredType, @ args)
throws BeansException {
return doGetBean(name, requiredType, args, fal);
}
......
}
其中涉及的流程可以从
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean(...)
这个⽅法开始,这个⽅法是个关键的⽅法,因为⾥⾯包含了创建Bean的流程,Spring在设计时,将createBean放到了getBean的流程⾥第⼀步我们看到第8⾏代码,
急切的检查⼿动注册单例的单例缓存,eager我们通常解释为饿汉式,也有点乐观的意思,这⾥就直接到单例缓存中去取,如果取到那肯定就是单例的,没取到就需要创建。这种套路我们进⾏实际编程时应该学到,是个很常见的编程模式。
这⾥的逻辑是直接从单例池中获取,如果获取到了就可以直接返回bean,如果没有获取到就需要创建,在创建的逻辑⾥再去判断是singleton还是prototype。
doGetBean()整个逻辑分为2个分⽀:
分⽀⼀:是从单例缓存中获取到了bean,此时处理后可以直接返回。
分⽀⼆:是没有从单例缓存中获取到bean,原因可能是还没有创建单例bean,也可能是因为scope是prototype的。
分⽀⼆的逻辑如下:
1、先判断是否是环形依赖导致的获取bean,这⾥可以看到26⾏抛出了⼀个异常,原因是这个bean是⼀个prototype的,⽽且发现这个bean已经被加⼊到了正在创建的bean队列中,只有⼀种可能就是,在创建他的时候,他被加⼊到正在创建队列中,他引⽤了别⼈,在创建别⼈时,别⼈引⽤了他,这种prototype的循环引⽤,Spring不提供解决⽅案,直接抛出异常,Spring希望这种情况下的循环引⽤由应⽤⾃⼰修改逻辑。
2、
下⾯我们可以看到82、100、118⾏就是真正的实例化bean的地
⽅,org.springframework.beans.factory.support.AbstractBeanFactory#createBean(),这个⽅法在AbstractBeanFactory中是抽象的空⽅法,交给了⼦类去实现,由于createBean中涉及了三级缓存相关的逻辑所以我们不得不在看看相关的源码。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
}
el {
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
el {
// Fail if we're already creating this bean instance:
// We're assumably within a circular referenc蒸带鱼的家常做法 e.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
el if (args != null) {
// Delegation to parent with explicit args.
return (T) Bean(nameToLookup, args);
}
el if (requiredType != null) {
// No args -> delegate to standard getBean method.
Bean(nameToLookup, requiredType);
}
el {
return (T) Bean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = DependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new ResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");    }
registerDependentBean(dep, beanName);
try {
getBean(dep);
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new ResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSin全字开头的成语 gleton()) {
sharedInstance = getSingleton(beanName, ()芦衣顺母的故事 -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put ther不停的打喷嚏 e
// 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);
}
el 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);
}
el {
String scopeName = Scope();
final Scope scope = (scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");    }
try {
Object scopedInstance = (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);
}
}
}
catch (BeansException ex) {
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, Class());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
}
throw new BeanNotOfRequiredTypeException(name, requiredType, Class());
}
}
return (T) bean;
}
如下就是createBean()⽅法的源码,⽼长了
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
很不幸,⽅法虽长,核⼼却被封装到了另⼀个⽅法doCreateBean()中,看看41⾏,我们⼜要去粘贴源码了.......

本文发布于:2023-05-04 17:01:49,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/856241.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:创建   缓存   单例
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图