总流程 12 个方法
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
1. prepareRefresh
prepareRefresh:为上下文对象初始化一些状态与属性,为后面的工作做准备。会设置容器的启动时间,设置活跃状态为ture。设置关闭状态为false,获取Enviroment对象设置到容器中,准备监听器和时间的集合对象,默认为空。
- initPropertySources() :给用户重写扩展,可以初始化一些属性资源,springMVC对其进行了扩展
- validateRequiredProperties() :这个方法是对一些启动必须的属性的验证。
我们可以通过实现或者继承 ApplicationContext 来重写这两个方法,从而完成一些基本属性的校验。
2. obtainFreshBeanFactory
实现Context的BeanFactory功能,执行完这个函数后。Context才真正拥有了BeanFactory的功能
- 会首先创建一个
DefaultListableBeanFactory
工厂,设置序列化id - 将XML内容解析为BeanDefinitions
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 会首先创建一个`DefaultListableBeanFactory` 工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 为工厂设置序列化id,可以反序列化到工厂对象
beanFactory.setSerializationId(getId());
//定制工厂,是否允许覆盖同名不同定义的对象及循环依赖
customizeBeanFactory(beanFactory);
//将XML内容解析为BeanDefinitions
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
定制工厂,是否允许覆盖同名不同定义的对象及循环依赖:需要继承重写customizeBeanFactory方法,设置allowBeanDefinitionOverriding,allowCircularReferences
2.1 createBeanFactory
创建一个类型为DefaultListableBeanFactory的beanFactory
DefaultListableBeanFactory 是整个springbean加载的核心部分
之所以有这么多接口,大概是接口隔离原则,最小接口拆分
最顶层的三个接口
- BeanFactory:定义获取单个bean或其属性(getBean,isSingleton)
- SingletonBeanRegistry:定义对单例的注册及获取(registerSingleton)
- AliasRegistry:定义对alias的增删改查(registerAlias)
另外的一些接口
- HierarchicalBeanFactory:增加对parentBeanFactory的获取方法(getParentBeanFactory)ListableBeanFactory:增加根据各种条件获取BeanDefinition集合方法(getBeanNamesForType)
- ConfigurableBeanFactory:增加配置BeanFactory方法(setParentBeanFactory)
- AutowireCapableBeanFactory:增加创建Bean(createBean),自动注入(autowireBean),应用Bean的后置处理器(applyBeanPostProcessorsBeforeInitialization,applyBeanPostProcessorsAfterInitialization)
2.2 loadBeanDefinitions
创建XmlBeanDefinitionReader来读取XML配置文件变为BeanDefinition
-
获取XML文件转为Document实例对象。
-
解析标签之前也会先去对profile解析(这个可以让我们方便的进行开发,部署环境的切换)。
-
Spring中有两大类声明,一种是默认的(import bean等);另一个是自定的(aop,tx等)handler进行解析,自定义标签需要写入spring.handlers来查找自定义的handler,通过handler解析写入BeanDefinition。
spring.handlers内容如下,soring会加载配置文件并记载到map中,方便寻找handler。
BeanDefinition其实是XML bean的信息转化为容器的内部表示。BeanDefinition都以Map的结构存入BeanDefinitionRegistry(两部分注册,别名和beanName),后续crud都是通过这个类
- 配置文件bean标签有class,scope,lazy-init ; BeanDefinition中也同样有
- AbstractBeanDefinition是对公用信息的抽象
- 配置文件中bean标签可以配置子bean标签,父子关系,那么在BeanDefinition中父用RootBeanDefinition,子用ChildBeanDefinition,没有父就用RootBeanDefinition。
xsd来定义xml schenas的规范,所以在解析XML之前需要解析到需要的xsd,往往写xml时xsd地址是网络地址,这样断网就无法正常运行,会有一份本地的xsd存储在映射在引入的JAR中 MATA-INF有spring.schemas 下
<context:component-scan base-package=“org.hhh” annotation-config=“true”/> component-scan 标签的 annotation-config="true"会注入一下对象的beandefinition
解析代码如下
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
//默认标签解析
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
//自定义标签解析
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
3. prepareBeanFactory
创建出工厂后在此处设置工厂
- SPEL:可以使用#{…}作为定界符,构建复杂表达式,方法调用
- 属性编辑器: XML中< value >标签到spring是string类型,如果注入的对象是Date类型,就会报错。我们就可以继承PropertyEditorSupport重写setAsText来保证类型匹配,然后注入到spring中即刻
- ApplicationContextAwareProcessor:没有看懂此处
- ignoreDependencyInterface:忽略某些接口,当需要Spring注入时忽略依赖
4. postProcessBeanFactory
模板方法,子类重写
5. invokeBeanFactoryPostProcessors
在这里你可以对beandefinition进行处理,比如解析修改。
5.1 BeanFactoryPostProcessor的执行顺序
- 对于beanFactoryPostProcessor分两种情况进行,一个是对于BeanDefinitionRegistryostProcessor类的处理,另一种是对普通BeanFactoryPostProcessor类的处理
- 处理顺序是先处理外部定义的集合,之后是子类,最后是父类。遇到子类型会执行postProcessBeanDefinitionRegistry方法之后加入父类的集合,最后与父类一起执行postProcessorBeanFactory方法
- 子类和父类的集合每个元素的执行方法也有顺序,先处理继承PriorityOrdered的类,再处理继承Ordered的类,再处理没有之前两个接口的类
注:上面图示大致流程,有更多细节,最后完成了执行;PriorityOrdered,Ordered 也有权重所以需要sort
5.2 重要的两个BFPP
其中重要的两个BeanFactoryPostProcessor,
5.2.1 ConfigurationClassPostProcessor
首先我们要知道这个BFPP哪里加载进来的,在loadBeanDefinnation
<context:component-scan base-package="org.djh" annotation-config="true"/>
这个标签解析的时候放入了一个beanDefinition internalConfigurationAnnotationProcessor所对应实例为ConfigurationClassPostProcessor,这个继承了BeanDefinitionRegistryostProcessor,执行postProcessBeanDefinitionRegistry就开始解析
ConfigurationClassPostProcessor用于解析被注解(@Configuration @ComponentScan @Import @Bean等)修饰。
首先会拿到候选的beanDefinition,筛选出可以被ConfigurationClassParser处理的beanDefinition,筛选删选逻辑如下:
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
//含有Configuration且包含proxyBeanMethods属性为FULL
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//含有Configuration或者含有Component,ComponentScan,Import,ImportResource为LITE,否则就不处理
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
//否则不处理
else {
return false;
}
其中复杂的就是@Import ,就顺便说下springboot的装配过程
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
首先就是上面说的
internalConfigurationAnnotationProcessor所对应实例为ConfigurationClassPostProcessor生成解析@Import注解
getImports(sourceClass) 是一个递归调用 ,就会得到一个注册类的的集合(ImportSelector,ImportBeanDefinitionRegistar 这些注册BeanDefinition),所以得到Registrar 和 AutoConfigurationImportSelector两个类
得到之后,就能根据注册类集合,根据其中不同类型调用他用注册beanDefinition的方法,如下
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
...
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
...
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
...
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
...
}
}
调用方法之后就能将我们想要注册的注册进去
5.2.2 PlaceholderConfigurationSupport用于处理被${}修饰的beanDefinition
6. registerBeanPostProcessors
这里与invokeBeanFactoryPostProcessors类似,但是只是注册BeanPostProcessor,实际的调用再构造bean的步骤。
7 8 9 10 .
initMessageSource
initApplicationEventMulticaster
onRefresh
registerListeners
11. finishBeanFactoryInitialization
这里就是创建bean的过程,先尝试获取bean(getBean),获取不到createBean的流程如下
BeanFactoryPostProcessor是操作未实例化beanDefinition的,那么BeanPostProcessor化后的实例对象。
BeanPostProcessor会根据对象信息进行判断,看是否需要执行applyBeanPostProcessorsBeforeInitialization或者applyBeanPostProcessorsAfterInitialization比如
- AOP中AbstractAutoProxyCreator主要根据shouldSkip(bean.getClass(), beanName),这个方法主要根据所有advisor,根据切入表达式来计算切入的类是否与当前beanName一致,一旦有一个就说明需要执行
- ApplicationContextAwareProcessor,主要根据beanName会判断是否为某些aware(ApplicationContextAware,beanNameAware)就执行invokeAwareMethod
下面是springMVC中的一个重要应用,其中AbstractHandlerMethodMapping继承了ApplicationContextAware就会在实例化的时候执行对应方法,而它的效果会注册 url到controller的映射到handlerMap,这样在springMVC中为接受请求时url寻找controller时候就能直接找(不过这个类解决继承Controller和HTTPRequestHandler的Controller,不是解决有@Controller表明的Controller)