本文是IOC相关基本概念。
文章目录
一、Bean与BeanDefinition
Bean
Bean是Spring的一等公民,初看Bean就是普通的Java类,但是没有携带任何框架基因的设计,决定了Spring可以自由迁入迁出,这就是Spring的低侵入性。
BeanDefinition
定义了Bean的生命周期、依赖关系之类的信息。
并且可以根据配置和注解决定作用范围(@Scope),懒加载(@Lazy),优先实现类(@Primary),是否是工厂bean(@Configuration),是否是工厂方法(@Bean)
实现类
AbstractBeanDefinition
BeanDefinition接口的实现基类,下边三个实现类都是此类的子类。
RootBeanDefinition
可以作为普通BeanDefinition,也可以作为其他BeanDefinition的父类,但是不可以当作其他BeanDefinition的子类。
GentricBeanDefinition
设计用于取代前后两种BeanDefinition,上边的还会有用到,下边那个已经完全没用了。
ChildBeanDefinition
没用了。。
二、容器
IOC的理解是要从两方面入手的,一方面是控制反转的设计思想,另一方面就是作为Bean的容器,维护Bean的生命周期。
1.BeanFactory
简单容器,完成了Bean的基本的生命周期管理。但是基本不会手动使用的,在Spring使用过程中是高级容器的组成部分,使用的是实现类DefaultListableBeanFactory。
要特别注意两点。
第一,DefaultListableBeanFactory中,有一个名为beanDefinitionMap的ConcurrentHashMap,不用猜都能想到,这是用来存放<BeanDefinitionName, BeanDefinition>映射的。
第二,DefaultListableBeanFactory经过一系列继承最后会追踪到DefaultSingletonBeanRegistry,大名鼎鼎的三级缓存都在这个类里。
2.ApplicationContext
高级容器,相比于BeanFactory,增加了大量的功能。
ApplicationContext有两种使用方法,注解和XML。
对应的实现也有个两个实现类AnnotationConfigApplicationContext和FileSystemXmlApplicationContext。
3.BeanFactory与FactoryBean区别
这时一个常考问题,这里做个最简单的区分,更详细的解释,留到考点部分吧。BeanFactory是容器,而FactoryBean是一个用于生产Bean的Bean。可以通过“&BeanName”(加&前缀)来获取该Bean,也可以通过“BeanName”获得一个其他类型的Bean。
三、Resource
这部分主要用于解析XML文件,如果读者从注解入手,这部分后边看到相关内容,是可以掠过的。
Resource是对底层资源的封装,将不同来源的资源抽象成URL,并提供一系列资源属性的访问接口。
如果是从XML入手,那么作者的另一篇博文(Resource、ResourceLoader、ResourcePatternResolver、容器的关系)可能对读者有些许作用。
Resource会被BeanDefinitionReader解析成BeanDefinition。
XML的BeanDefinitionReader实现类是XmlBeanDefinitionReader。
注解的BeanDefinitionReader实现类是AnnotatedBeanDefinitionReader。
解析成BeanDefinition的过程至少会写一篇注解的解析源码详解。
四、后置处理器
1.BeanFactoryPostProcessor
最常见的实现类是BeanDefinitionRegistryPostProcessor,用于实现对BeanDefinition的自定义注册。例如在整合Mybatis时,就是用这种形式将Mybatis的类注入。
2.BeanPostProcessor
从不严谨的角度讲,前者用于对BeanDefinition进行操作,后者用于对bean进行操作。AOP就是基于这个思路实现的。
总结
IOC,控制反转,核心无非是对Java类(在Spring中就是Java Bean)的管理。所以引入了BeanFactory的概念,简单的容器,已经可以完成Bean的创建。但是Java开发是XML和注解并存的,从单一职责的角度考虑,引入ApplicationContext,高级容器,将Java类的元数据解析成BeanDefinition再交给BeanFactory去创建Bean。当然,ApplicationContext还做了一些其他工作,比如国际化,这些不在主线上,初学者应当忽略。解析BeanDefinition的过程中,需要Resource屏蔽底层文件读写差异。获得BeanDefinition之后,在注入之前,可以使用BeanFactoryPostProcessor对BeanDefinition做修改,也可以在获取Bean的时候使用BeanPostProcessor对Bean做修改或替换。