IOC容器的实现
容器的设计
什么是依赖反转?为什么需要依赖反转?
依赖对象的获得被反转了
如果这个获取过程要靠自身实现,那么这将导致代码高度耦合并且难以维护和调试。
什么是容器?什么是 BeanDefinition?他们是什么关系?
IOC容器是实现依赖反转的载体
BeanDefinition 是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构,依赖反转功能都是围绕着这个 BeanDefinition 的处理来完成的。
BeanDefinition和Bean的联系和区别?
按照 BeanDefinition 规则,对 pojo 对象进行装配,管理,并赋予生命后得到的最终的对象才是Bean
为什么要设计各种容器?
BeanFactory 定义了容器最基本的功能(获取bean),同时,为了简化使用者的使用和开发,实现了各种不同功能的子容器,这些子容器能适用于各种不同的场景。
容器的设计体系:
路线一:
- BeanFactory:定义了容器的基本功能(getBean)
- HierarchivalBeanFactory:使容器具有继承管理(getParentBeanFactory)
- ConfigurableBeanFactory:使容器具有可配置功能(setParentBeanFactory,addBeanPostProcessor)
路线二:
ListableBeanFactory:使容器具有枚举bean的功能,不然工厂中到底有多少bean无法得知(只能采用穷举法一个个的去尝试)
ApplicationContext:继承 HierarchivalBeanFactory 和 ListableBeanFactory,使其拥有容器的功能,同时扩展了很多的高级特性。
容器的初始化
如何采用线路一使用容器?
在Spring中,提供了 DefaultListableBeanFactory 类,这个类基本实现了容器所有的功能,因此委托这个类,就可以进行简单的容器开发使用。
除外我们还需要做的额外操作:将 BeanDefinition 注册到 DefaultListableBeanFactory 中(因为DefaultListableBeanFactory 实现了 BeanDefinitionRegistry 接口),这一步操作的意义是为了告诉DefaultListableBeanFactory 如何进行bean装配、管理:
1 | //BeanDefinition 资源定位,使用 Resource 抽象,可以使用 ResourceLoader 进行 Resource 的定位 |
注意到我们这里为了使用 DefaultListableBeanFactory,其实是做了额外的三步:
- BeanDefinition 资源定位
- BeanDefinition 资源加载
- BeanDefinition 资源注册
ApplicationContext扩展了哪些容器的高级特性?
- MessageSource:支持国际化,为开发多语言的程序提供支持
- ResourceLoader:支持 Resource 多方面获取
- ApplicationContextPublisher:支持应用事件处理
- BeanPostProcesser管理
如何采用线路二使用容器?
spring 中 AbstractApplicationContext 为我们实现了这些扩展的高级特性的基本功能,但是为了使用它,我们还需要实现他的三个方法:
1 | //ApplicationContext 采用委托其它容器来支持它自身的容器功能,并且完成对容器的增强 |
spring 中 AbstractRefreshableApplicationContext 继承了 AbstractApplicationContext 类,它使用DefaultListableBeanFactory 作为委托容器,为我们做了上面的工作,但为了使用AbstractRefreshableApplicationContext,我们还需要实现它的一个方法:
1 | //之前说过,这里就是为了告诉DefaultListableBeanFactory如何进行bean装配、管理 |
线路二案例:
这里使用 AbstractRefreshableConfigApplicationContext 的一个子类 AbstractXmlApplicationContext 来说明:
BeanDefinition 资源定位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){
//BeanDefinition资源加载器定义,入参是一个BeanDefinitionRegistry,这里表明是一个XML
//BeanDefinition资源可以是很多其他的形式
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//配置beanDefinitionReader,关键是配置ResourceLoader
//ResourceLoader的功能是可以定位BeanDefinition
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//加载BeanDefinition资源
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
/**
* getConfigResources() 和 getConfigLocations() 用于定位资源
* 后者在reader中需要调用loader对stringPath的进行定位
* @see DefaultResourceLoader#getResourceByPath(String path)
*/
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader){
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}BeanDefinition载入
哪个类主要用来实现BeanDefinition载入细节?里面主要的方法是什么?
在 DefaultBeanDefinitionDocumentReader.processBeanDefinition 中解析 Document
委托 BeanDefinitionParserDelegate.parseBeanDefinitionElement 来实现载入
BeanDefinitionParserDelegate 的作用是什么?
实现 BeanDefinition 嵌套载入
BeanDefinition注册
解析完成后回调 BeanDefinitionRegistry.registerBeanDefinition() 进行注册(DefaultListableBeanFactory 实现了BeanDefinitionRegistry)
依赖注入
依赖注入发生的时机?
发生在第一次向容器索要 Bean 的时候,也就是调用 getBean 的时候
AbstractBeanFactory 实现了 getBean 的功能,因此下面着重分析 AbstractBeanFactory
AbstractBeanFactory源码分析:
1 | doGetBean(...){ |
从上诉代码可以看到,关键的方法是 createBean,该方法由子类实现。
正好,spring 中 AbstractAutowireCapableBeanFactory 帮我们准备了上述方法的实现
下面将对这个类进行分析:
1 | protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){ |
1 | protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args){ |
主要的两个方法是 createBeanInstance 和 populateBean :
1 | protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { |
1 | protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { |
1 | public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { |
再看依赖注入 populateBean:
1 | protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw){ |
1 | protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { |
BeanWapper分析:
PropertyAccessor:提供通过属性名访问属性功能(是否可读,是否可写,get,set),支持普通的java对象和spring的Bean对象
TypeConverter:提供类型转换的功能(convertIfNecessary),比如注入的属性值是String型,而属性类型是对象类型,则提供转换的功能
TypeConverterSupport 继承了 PropertyEditorRegistrySupport,持有各种类型的 PropertyEditor,
TypeConverterSupport 委托 PropertyEditor 或者 ConversionService 来处理实际的值转换
ConfigurablePropertyAccessor:提供 PropertyAccessor 的相关配置(setConversionService)
- AbstractPropertyAccessor:实现 ConfigurablePropertyAccessor
- 实现了各种可重构的方法,把关键的方法(如何访问属性)留给子类实现
- 继承 TypeConverterSupport,具有类型转换功能
- AbstractNestablePropertyAccessor:拓展了嵌套属性的访问功能,同样“如何访问”需要子类实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51public class MyBeanPropertyAccessor extends AbstractNestablePropertyAccessor {
@Override
protected PropertyHandler getLocalPropertyHandler(String propertyName) {
//如何访问属性,并且抽象成PropertyHandler
return MyProxyHandler;
}
@Override
protected AbstractNestablePropertyAccessor newNestedPropertyAccessor(Object object, String nestedPath) {
//提供子属性访问器
return null;
}
@Override
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
//定义异常,附加额外的异常处理
return null;
}
class MyProxyHandler extends PropertyHandler{
public MyProxyHandler(Class<?> propertyType, boolean readable, boolean writable) {
super(propertyType, readable, writable);
}
@Override
public TypeDescriptor toTypeDescriptor() {
return null;
}
@Override
public ResolvableType getResolvableType() {
return null;
}
@Override
public TypeDescriptor nested(int level) {
return null;
}
@Override
public Object getValue() throws Exception {
return null;
}
@Override
public void setValue(Object value) throws Exception {
}
}
}- AbstractPropertyAccessor:实现 ConfigurablePropertyAccessor
BeanWrapper:提供分析和操作JavaBean的方法
BeanWrapperImpl:
- 使用JavaBean的内省机制实现属性的访问
- 具有类型转换功能
- 具有通过属性名嵌套访问属性的功能
其他特性实现
容器的准备
容器的准备发生在 AbstractApplicationContext#prepareBeanFactory() 中:
1 | public abstract class AbstractApplicationContext{ |
容器的销毁
发生在 AbstractApplicationContext#doClose() 中:
1 | public abstract class AbstractApplicationContext{ |
Bean初始化
发生在 AbstractAutowireCapableBeanFactory#initializeBean 中
1 | public abstract class AbstractAutowireCapableBeanFactory{ |
Bean销毁
最终会走到 DisposableBeanAdapter#destroy 中:
1 | class DisposableBeanAdapter { |
lazy-init属性和预实例化
lazy-init属性有何用?
决定执行bean的实例化:是在容器初始化完成时还是第一个请求获取bean时
相关逻辑在 DefaultListableBeanFactory#preInstantiateSingletons 中
1 | class DefaultListableBeanFactory{ |
FactoryBean
FactoryBean的相关逻辑在 AbstractBeanFactory#getObjectForBeanInstance中
1 | class AbstractBeanFactory{ |
autowiring自动装配
相关逻辑在 AbstractAutowireCapableBeanFactory#populateBean 中
1 | class AbstractAutowireCapableBeanFactory { |
Bean对IOC容器的感知
通过 ApplicationContextAwareProcessor 来实现
1 | class ApplicationContextAwareProcessor implements BeanPostProcessor { |