《Spring技术内幕》读书笔记——IoC源码

Inversion of Control,控制反转,又称Dependency Inversion Principle,依赖倒置,由容器来管理Bean。

1、BeanFactory继承体系

Spring定义BeanDefinition抽象Bean的定义,来管理对象和对象的依赖关系。

从BeanFactory到HierarchicalBeanFactory,到ConfigurableBeanFactory,是一条设计路线,除了BeanFactory的基本方法之外,增加了getParentBeanFactory()方法,具备了双亲IoC容器管理的功能。ConfigurableBeanFactory还定义了setParentBeanFactory(),addBeanPostProcessor()配置Bean后置处理器等。

第二条设计路线是BeanFactory到ListableBeanFactory,到ApplicationContext,细化了BeanFactory接口的功能。MessageSource支持不同的信息源(国际化),ResourcePatternResolver支持不同的资源,ApplicationEventPublisher支持事件机制。DefaultListableBeanFactory提供Bean的创建、注入、初始化(AbstractAutowireCapableBeanFactory提供),可以枚举Bean,查看Bean的个数(ListableBeanFactory提供),可以分析、修改、预实例化Bean(ConfigurableListableBeanFactory提供),注册Bean(BeanDefinitionRegistry提供),DefaultListableBeanFactory包含了IOC容器的重要功能,是一个基本产品。

以XmlBeanFactory为例,初始化了一个XmlBeanDefinitionReader对象,可以读取XML资源,用这个Reader来进入BeanDefinition的加载,reader.loadBeanDefinitions(resource)。Resource是Spring用来封装IO操作的类。在其他容器比如ApplicationContext中,和XmlBeanFactory一样,也是通过持有或扩展DefaultListableBeanFactory来获得容器功能的。

实例化山下文时,启动容器的refresh()过程,不同类型的容器定制了一些模板方法的不同实现,例如getResourceByPath(String path),loadBeanDefinitions(resource),等。

 

2、容器初始化(refresh())

refresh()方法标志着容器的启动,包括BeanDefinition的Resource定位、载入(loadBeanDefinitions)和注册三个过程,需要使用相应的ResourceLoader、BeanDefinitionReader。此时依赖注入还未发生,依赖注入发生在应用第一次getBean时,如果设置了lazyinit = false,则在容器初始化的时候会进行依赖注入

(1)BeanDefinition的Resource定位

以Resource来定位容器使用的BeanDefinition,例如ClassPathResource res = new ClassPathResource("beans.xml");此时还不能直接使用,需要通过BeanDefinitionReader来处理。在ApplicationContext中配置了一系列reader,而DefaultlListableBeanFactory这种更底层的容器,可以自定义reader。

以FileSystemXmlApplicationContext为例,继承AbstractApplicationContext具备了ResouceLoader读入以Resource定义的BeanDefinition的能力,因为AbstractApplicationContext的基类是DefaultResourceLoader,XML文件形式的BeanDefinition都能得到处理。在容器初始化时,调用refreshBeanFactory()  —> loadBeanDefinitions —> getResourceByPath(),通过不同的ResourceLoader,调用resourceLoader.getResource(String location)或者getResourceByPath()最终得到了Resource。

(2)BeanDefinition的载入和解析

将BeanDefinition转化为Spring内部数据结构,通过一个beanName —> beanDefinition的ConcurrentHashMap来维护。

如下是refresh()方法,容器初始化过程,在refreshBeanFactory()中调用抽象方法loadBeanDefinitions()来载入和解析。

以FileSystemXmlApplicationContext为例,调用链为refresh -> refreshBeanFactory() -> loadBeanDefinitions(DefaultListableBeanFactory beanFactory) -> loadBeanDefinitions(XmlBeanDefinitionReader reader) -> loadBeanDefinitions(Resource[] resources) -> loadBeanDefinitions(Resource resource) 这里得到XML文件,得到IO的InputSource准备读取 -> doLoadBeanDefinitions(InputSource inputSource, Resource resource) 这里取得XML文件的Document对象,解析过程由documentLoader完成 -> registerBeanDefinitions(Document doc, Resource resource),最终进行BeanDefinition的注册,还进行了数量统计。

BeanDefinition的载入首先调用XML的解析器得到Document对象,再利用documentReader,按照Spring的Bean规则进行解析,默认是DefaultBeanDefinitionDocumentReader,处理BeanDefinition,处理结果由BeanDefinitionHolder持有,除了BeanDefinition之外,还持有Bean的名字、别名集合等。BeanDefinitionHolder的生成是通过解析Document文档树完成,由BeanDefinitionParserDelegate实现,如下,获取docReader -> 解析XML -> 注册BeanDefinition -> 发送消息。

BeanDefinitionParserDelegate通过parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)处理对Bean元素的定义,先获得Bean的id,name,alias,再触发parseBeanDefinitionElement(ele, beanName, containingBean)。BeanDefinition还包括init-method, destroy-method, factory-method, beanClass, description, lazyinit等属性。最终在parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType)中,根据Element的类型,触发对应的解析方法,例如parseIdRefElement(ele), parseArrayElement(ele)等。

(3)BeanDefinition注册

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

通过HashMap持有beanDefinition。在DefaultListableBeanFactory中实现了BeanDefinitionRegistry接口,调用registerBeanDefinitions(String beanName, BeanDefinition beanDefinition)完成了向容器的注册,就是塞到HashMap里去。

完成了定位、载入和解析、注册,容器初始化之后,还没有完成依赖注入。

 

3、依赖注入

依赖注入在用户第一次通过getBean(String name)向容器索取Bean时发生(lazy-init = true的会在实际使用到时,调用getBean完成注入)。

getBean(String name) -> doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 。

getBean是依赖注入的起点,后续调用createBean,在AbstractAutowireCapableBeanFactory中实现,生成需要的Bean,并进行处理,init-method、BeanPostProcessor等。下图是AbstractAutowireCapableBeanFactory中的createBean,createBeanInstance创建Bean;earlySingletonExposure用来判断是否允许提前暴露,判断是否已经创建过;populateBean填充参数;initializeBean初始化Bean,下面依次来分析。

createBeanInstance生成Bean,默认的实例化策略是CglibSubclassingInstantiationStrategy(策略模式),即默认使用CGLIB实例化Bean。还有SimpleInstantiationStrategy,通过反射或CGLIB生成对象,通过BeanUtils中调用newInstance(args)实例化,或者CGLIB实例化。

createBeanInstance之后,populateBean设置对象的属性值,设置好依赖关系,完成整个依赖注入。populateBean中先处理autowire的注入,byName or byType,然后调用applyPropertyValues对属性进行注入。在applyPropertyValues

方法中,调用valueResolver.resolveValueIfNessary(PropertyValue pv, Object originValue),包含了对所有注入类型的处理,判断value类型进行解析,获取了属性值之后,再调用BeanWrapper.setPropertyValues注入,具体的完成是在BeanWrapperImpl中。根据属性值不同的类型,取得注入属性的set方法,反射注入

Bean的创建和依赖注入的过程中,有几个递归调用,查找需要的Bean(无则去父容器查找)、创建Bean、依赖注入时递归getBean

Spring通过三级缓存解决参数(setter)循环依赖,Constructor循环依赖无法解决https://blog.csdn.net/u010853261/article/details/77940767

Nap<String, Object> singletonObjects, beanName -> beanDefinition
Map<String, Object> earlySingletonObjects, 二级缓存,如果一二级缓存中取不到,通过factory取得Bean并加入二级缓存
Map<String, ObjectFactory<?>> singletonFactories, 三级缓存,factory

 

4、初始化、预实例化、其他

(1)初始化

Bean的生命周期:实例化(createBeanInstance) —— 将值和bean引用注入到bean对应的属性中 (populateBean)—— BeanNameAware.setBeanName —— BeanFactoryAware.setBeanFactory —— BeanPostProcessor.postProcessBeforeInitailization —— InitialzingBean.afterPropertiesSet() —— init-methd —— BeanPostProcessor.postProcessAfterInitailization —— 准备就绪,可以使用 —— Disposable.destroy() —— detroy-method

其中从setBeanName到postProcessAfterInitailization方法,均在initializeBean方法里,如下,其中invokeInitMethods中调用了InitialzingBean.afterPropertiesSet()和反射调用init-method,bean销毁过程类似。

(2)预实例化、FactoryBean、autowiring

预实例化过程在refresh()中的finishBeanFactoryInitialization(BeanFactoy beanFactory)中,判断beanDefinition是否是单例、是否lazy -init = false,满足条件调用getBean()预实例化

关于FactoryBean,用户可以实例化FactoryBean接口,重写getObject()方法定制Bean,FactoryBean有 T getObject(), Class<T> getObjectType(), boolean isSingleton()三个方法。

autowiring在populateBean中被处理,根据name或者type调用getBean。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值