1 ClassPathXmlApplication
从关键类 ClassPathXmlApplication 入手,
ApplicationContext context = new ClassPathXmlApplicationContext(“classpath:spring-config.xml”);
1.1 继承关系
ClassPathXmlApplicationContex 兜兜转转到了ApplicationContext,与他有类似功能的还有FileSystemXmlApplicationContext、AnnotationconfigApplicationcontext。
ClassPathXmlApplicationContext 本质上是一个BeanFactory
继承关系中有几个比较重要的类
- ListableBeanFactory 可以获取多个Bean
- HierarchicalBeanFactory 可以设置父子关系
- 还有AutowireCapableBeanFactory 自动装配Bean使用的,ApplicationContext 虽然未继承,但可以通过组合关系
1.2 核心流程
ClassPathXmlApplication的构造方法
refresh()的核心流程
- 配置文件会被解析成一个一个beanDefinition, 保存到注册中心 本质上是一个Map(beanName, beanDefinition)
- 设置beanFactory 的类加载器
- Spring会负责调用postProcessBeanFactory,这里是提供给子类的扩展点,所有的Bean加载注册好,但还未初始化
- invokeBeanFactoryPostProcessors(beanFactory); 调用各个BeanFactoryPostProcess的实现类的postProcessBeanFactory(factory)方法。
- 注册BeanPostProcess的实现类,此接口有两个方法,一个是初始化之前postProcessBeforeInitialization,初始化之后postProcessAfterInitialization
- 初始化当前 ApplicationContext 的事件广播器
- 注册监听事件
- 初始换所有的Bean
- 广播事件
2 创建Bean容器 obtainFreshBeanFactory()
是非常重要的一个环节,这个环节初始化BeanFactory,加载Bean,注册Bean。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PH7abFee-1651216194769)(672130c8eb341d19aa7fa69b0cae7236.png)]
2.1 refreshBeanFactory()
refreshBeanFactory()方法,做了三件事情
- 关闭旧的BeanFactory
- 初始化一个DefaultListableBeanFActory
- 配置两个属性,是否允许覆盖,是否允许循环依赖
- 加载Bean到BeanFactory
至此,我们队ApplicationContext有了一个整体的认识,ApplicationContext虽然继承自BeanFactory,但是不应该被理解为实现了BeanFactory,知识他持有一个BeanFactory的实现类,DefaultListableBeanFactory
为什么要是实例化DefaultListAbleBeanFactory,因为他有一个实现类是ConfigurableListableBeanFactory,而且实现了AutowireCapableBeanFactory,根据ApplicationContext的继承关系图来看,他基本上就是最牛的BeanFactory了。
2.2 BeanDefinition 是什么
BeanDefinition本质上就是我们定义的Bean,他被转换成了BeanDefinition存在于Spring的BeanFactory,他保存了Bean信息,指向那个类,是否单例,依赖那些Bean,是否懒加载等
BeanDefinition的接口定义
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 默认提供 sington 和 prototype 两种,
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// 一句话就是:继承父 Bean 的配置信息而已
void setParentName(String parentName);
// 获取父 Bean
String getParentName();
// 设置 Bean 的类名称,将来是要通过反射来生成实例的
void setBeanClassName(String beanClassName);
// 获取 Bean 的类名称
String getBeanClassName();
// 设置 bean 的 scope
void setScope(String scope);
String getScope();
// 设置是否懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 设置该 Bean 依赖的所有的 Bean,注意,这里的依赖不是指属性依赖(如 @Autowire 标记的),
// 是 depends-on="" 属性设置的值。
void setDependsOn(String... dependsOn);
// 返回该 Bean 的所有依赖
String[] getDependsOn();
// 设置该 Bean 是否可以注入到其他 Bean 中,只对根据类型注入有效,
// 如果根据名称注入,即使这边设置了 false,也是可以的
void setAutowireCandidate(boolean autowireCandidate);
// 该 Bean 是否可以注入到其他 Bean 中
boolean isAutowireCandidate();
// 主要的。同一接口的多个实现,如果不指定名字的话,Spring 会优先选择设置 primary 为 true 的 bean
void setPrimary(boolean primary);
// 是否是 primary 的
boolean isPrimary();
// 如果该 Bean 采用工厂方法生成,指定工厂名称。对工厂不熟悉的读者,请参加附录
// 一句话就是:有些实例不是用反射生成的,而是用工厂模式生成的
void setFactoryBeanName(String factoryBeanName);
// 获取工厂名称
String getFactoryBeanName();
// 指定工厂类中的 工厂方法名称
void setFactoryMethodName(String factoryMethodName);
// 获取工厂类中的 工厂方法名称
String getFactoryMethodName();
// 构造器参数
ConstructorArgumentValues getConstructorArgumentValues();
// Bean 中的属性值,后面给 bean 注入属性值的时候会说到
MutablePropertyValues getPropertyValues();
// 是否 singleton
boolean isSingleton();
// 是否 prototype
boolean isPrototype();
// 如果这个 Bean 是被设置为 abstract,那么不能实例化,
// 常用于作为 父bean 用于继承,其实也很少用......
boolean isAbstract();
int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}
2.3 customizeBeanFactory(beanFactory)
customizeBeanFactory(beanFactory) 比较简单,就是配置是否允许 BeanDefinition 覆盖、是否允许循环引用。
2.4 加载Bean
2.4.1 loadBeanDefinitions(beanFactory)
loadBeanDefinitions(beanFactory) ,这个方法将根据配置,加载各个Bean到BeanFactory中
- new XmlBeanDefinitionReader(beanFactory) 将BeanFactory实例化成一个XmlBeanDefinitionReader;
- initBeanDefinitionReader(beanDefinitionReader);初始化BeanDefinitionReader
- loadBeanDefinitions(beanDefinitionReader) ,加载XML配置文件转换成一个DOM树
一路点进去,找到 doRegisterBeanDefinitions 中的解析标签方法 parseDefaultElement(ele, delegate) ,重点关注一下 标签
2.4.2 标签解析
标签的内容
继续往下看怎么解析之前,我们先看下 标签中可以定义哪些属性:
属性 | |
---|---|
class | 全限定名 |
name | BeanName |
scope | 作用域 |
constructor arguments | 构造参数 |
properties | 属性值 |
autowiring mode | 注入模式 |
lazy-initialization mode | 是否懒加载 |
nitialization method | 初始化方法 |
destruction method | 销毁会调用的方法 |
2.4.5 processBeanDefinition()
重点关注org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition()方法
- 注册Bean
- 发送事件
总结一下,到这里已经初始化了 Bean 容器, 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。
参考资料
[1] Spring IOC 容器源码分析