Spring——Bean的加载及初始化

过去的,未来的
2020-05-21 / 0 评论 / 0 点赞 / 666 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2020-05-21,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

容器启动时

容器启动的时候就会预实例化单例Bean,prototype bean则不会。例如下面这个行初始化容器的代码

ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

其中的bean.xml配置为

    <bean id="person" class="com.young.bean.Person" init-method="init">
        <property name="id" value="10"/>
        <property name="name" value="测试"/>
    </bean>

debug发现,初始化BeanFactory时,对于单例Bean,会执行到AbstractBeanFactory中的一个核心方法doGetBean()去创建一个单例bean,

即容器初始化时就会创建单例Bean(lazy-init除外),新创建的单例Bean将被放入Map中,由Spring容器维护其生命周期。

从容器中获取Bean时

即下面这行代码

Person person = context.getBean("person", Person.class);

同样会进入AbstractBeanFactory中的一个核心方法doGetBean()方法,此时也要分Singleton还是prototype (其他scope类型的Bean略)进行不同的处理,

对于单例,会取缓存数据(取出的可能是一个为完全实例化的bean——因为要解决循环依赖),而prototype bean则每次都新创建bean。 这个过程无论singleton还是prototype bean,都会在这个方法中有一些共同的处理流程。

那么doGetBean()这个方法到底做了什么事情呢?

加载Bean的核心方法 doGetBean()

这个方法主要做了以下工作:

1、转换对应beanName: 例如别名转为实名
2、尝试从缓存加载单例:这里加载出来的可能只是一个没有完全实例化的singleton bean (为了解决循环依赖问题)
3、转化工厂Bean取出来的代理bean为真正的bean,单例bean到这一步就可以返回了。【注:无论是缓存中取出的bean还是后续创建的bean,都有可能是通过工厂Bean(FactoryBean)创建的代理对象,还不是真正需要的bean,需要执行一个重要的方法getObjectForBeanInstance()才能获取真正的bean。这个方法出现频率很高,很多地方都需要用到,因为spring中有很多FactoryBean(注意区分BeanFactory)】
4、后处理器入口。即上面的getObjectForBeanInstance() 不仅仅是完成了FactoryBean()获取bean的工作,对于由FactoryBean创建的prototy bean还会执行用户定义的postProcessObjectFromFactoryBean()中的操作,这也是个非常重要的spring扩展接口。
5、检查protorype模式下是否存在循环依赖,是则抛异常 (只有单例模式允许循环依赖)
6、如果缓存没有数据就转到父类工厂去加载(就是扩大搜索范围)
7、将存储XML中配置信息的GernericBeanDefinition转为RootBeanDefinition供后续处理
8、加载依赖的bean:这是个递归调用。 Spring在初始化bean前,总是先初始化依赖的bean
9、通过Java反射的方式,开始按scope类别创建bean (默认singleton,可配置prototype, request之类)
10、上面的创建bean之前,处理bean中override-method属性,即针对 lookup-method和replace-method做的处理,动态地为当前bean生成代理并使用对应拦截器为bean做增强处理。
11、对BeanDefinigitionz中的属性做前置处理。也就是InstantiationAwareBeanPostProcessor中的postProcessBeforeInstantiation()和postProcessAfterInitialization()在此处生效。经过后处理器后可能已经不是原来的bean,而是代理bean了。
12、实例化bean前先检查是否需要使用cglib动态增强,即是否要对lookup或者replace-method做处理,是的话返回的就是代理对象。
13、检查是否要将正在实例化的bean提前曝光(解决单例循环依赖),是则加入
14、属性注入。注入方式有 antowireByName(按bean name在容器中查找并注入), autowireByType
15、调用BeanPostProcessor的后处理器(在客户调用客户自定义初始化方法前后,都会执行BeanPostProcessor中的方法)增强bean
16、若bean实现了Initializing接口,此时会调用其中重写的afterPropertiesSet方法。
17、调用自定义 init-method方法。
18、注册DisposableBean,即销毁bean方法的扩展。至此,已经实例化bean,即create的过程结束
19、类型转换,上面的doGetBean()会传入一个要求转换的类型,一般为Class<?>

经过以上步骤,bean加载就完成了,后面就可以使用这个bean了

来源:https://my.oschina.net/u/3300976/blog/3026555

0

评论区