我们接着上次的说,上次还剩下AnnotationConfigApplicationContex这个类的构造方法里调用的refresh();没有说,我们今天来看看这个重点方法:refresh();
目录
1、Refresh()方法之 prepareRefresh()
2、refresh()方法之obtainFreshBeanFactory()
AbstractApplicationContext
refresh(); 在AbstractApplicationContext 类中。关系如下:
AnnotationConfigApplicationContext继承了GenericApplicationContext,而
GenericApplicationContext又继承了AbstractApplicationContext。所以说refresh()方法的执行流程是在父类AbstractApplicationContext的方法里。我们来进一步看看这个方法里都执行了什么。
refresh()方法解析
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//1、 Prepare this context for refreshing.
//准备刷新容器,刷新前的处理
prepareRefresh();
//2、 Tell the subclass to refresh the internal bean factory.
//得到一个新的beanFactory
//告诉子类刷新内部bean工厂。 用来保存 bean 的容器 相当于IOC容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3、 Prepare the bean factory for use in this context.
//内容:准备bean工厂以供在此上下文中使用。一般在这里完成 BeanFactory 的创建,下一个方法是扩展
prepareBeanFactory(beanFactory);
try {
//4、 Allows post-processing of the bean factory in context subclasses.
// spring暂时没有接口实现,可能是后期spring会自己完善这个接口
postProcessBeanFactory(beanFactory);
//================以上是 BeanFactory 的创建及预准备工作(标准初始化)============================
//5、 Invoke factory processors registered as beans in the context.
// 调用上下文中注册为bean的工厂处理器。 执行BeanFactoryPostProcessors();
// BeanFactory的后置处理器。在BeanFactory标准初始化后执行的,标准初始化就是前面的4步
invokeBeanFactoryPostProcessors(beanFactory);
//6、 Register bean processors that intercept bean creation.
//注册bean后置处理器
// 注册 BeanPostProcessor的实现类,注意看和BeanFactoryPostProcessor的区别
// 此接口两个方法 1、postProcessBeforeInitialization 2、postProcessAfterInitialization
// 两个方法分别在Bean初始化之前和初始化之后得到执行。注意:到这里bean还没初始化
registerBeanPostProcessors(beanFactory);
//7、 Initialize message source for this context.
//做国际化功能:消息绑定,消息解析
// 初始化当前applicationContext的MessageSource
initMessageSource();
//8、 Initialize event multicaster for this context. 初始化事件派发器
initApplicationEventMulticaster();
//9、 Initialize other special beans in specific context subclasses.
//子类重写这个方法,在容器刷新的时候可以自定义逻辑
onRefresh();
//10、 Check for listener beans and register them.
// 给容器中 将所有项目里面 ApplicationListener 注册进来,并且发布早期事件
//注册事件监听器,监听器需要实现ApplicationListener接口
registerListeners();
//11、 Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有剩下的单实例 Bean
//重点 重点 重点
//初始化所有的 singleton beans
// (lazy-init的除外)
finishBeanFactoryInitialization(beanFactory);
//12、 Last step: publish corresponding event.
//最后一步:发布相应的事件。完成 beanFactory 的初始化创建工作;
finishRefresh();
}
}
}
可以看到refresh()方法里一共进行了十二的操作。我们一步一步的解析
1、Refresh()方法之 prepareRefresh()
其实这个方法主要内容就是记录下容器启动时间,标记容器为活动状态,并执行初始化的属性源
protected void prepareRefresh() {
// Switch to active. 切换到活动状态
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
//在上下文环境中初始化任何占位符属性源。(由子容器去实现)
// 目前没有子类去实现的,
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 检验属性的合法 等
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
//将本地应用程序监听器重置为预刷新状态。
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 允许收集早期的ApplicationEvents,
// 一旦多播机可用,就会发布…
// 保存容器中一些早期的事件 是ApplicationEvent类型
// this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
this.earlyApplicationEvents = new LinkedHashSet<>();
}
2、refresh()方法之obtainFreshBeanFactory()
刷新beanFactory 抽象方法,由子类实现。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
refreshBeanFactory()方法有两个实现类
如果你用的是javaConfig技术,那么你应该看GenericApplicationContext这个实现,如果你用的是XML这种形式的,那么你应该看AbstractRefreshableApplicationContext。我们先看GenericApplicationContext这个类做了什么:
可以看到,在这个方法里,仅仅是设置了beanFactory的序列化ID。我们返回
obtainFreshBeanFactory这个方法:
接着说:getBeanFactory()方法,点开这个方法,发现是一个抽象方法:
我们接着看GenericApplicationContext类的实现:
就是把已经创建好的beanFactory返回。至此注解版的这个方法就结束了,下面来说说以XML形式的方式。让我们重新看refreshBeanFactory()这个方法,抽象方法,需要看子类的实现:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
...
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
...
}
而实际执行的方法是在AbstractRefreshableApplicationContext抽象类里执行的。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
...
protected final void refreshBeanFactory() throws BeansException {
// 如果ApplicationContext中已经加载过BeanFactory了,销毁虽有的Bean,关闭BeanFactory
//注意:应用中BeanFactory本来就可以多个的,这里不是说应用全局是否有BeanFactory,
// 而是当前ApplicationContext是否有BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置BeanFactory的两个配置属性:是否允许Bean覆盖,是否允许循环引用
customizeBeanFactory(beanFactory);
// 加载bean 到BeanFactory中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
...
}
在这个方法里,先判断已经存在beanFactory,如果已经存在则进行销毁,而后创建一个新的BeanFactory,设置唯一ID,设置是否允许Bean覆盖与Bean的循环引用,加载bean到BeanFactory中。
我们先看 createBeanFactory()这个方法;
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
......
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
......
}
然后点开DefaultListableBeanFactory()这个创建Bean工厂的这个构造方法。
我们接着往里看:
在这个有参构造器里调用了无惨的构造方法:
我们看一下无惨构造方法里做了什么操作:
这里做了这样的操作:忽略了指定接口的自动装配,具体可以看注释。
再来看:customizeBeanFactory(beanFactory);beanFactory.setxxx()是一个布尔值,所以说,如果有人问你,Spring中的循环依赖能否关闭,你这就拿下面这段代码回答了。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
// 是否允许bean定义覆盖
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
// 是否允许循环引用 A依赖B B依赖A 形成闭环
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
我们回到refreshBeanFactory()方法里,看loadBeanDefinitions(beanFactory);这个方法
这个抽象方法,有四个类进行了重写,我们分析AnnotationConfigWebApplicationContext,这个类
具体如下:
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {
...
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// 生成bean的名字生成器
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
// 注册到容器里
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
// scoope的解析器
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.componentClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering component classes: [" +
StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
}
// 若是指定的Bean,就交给reder中的doRegisterBean去解析每一个 Config Bean
reader.register(ClassUtils.toClassArray(this.componentClasses));
}
// 扫描配置文件的Bean
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// 这里很重要 spring提供的包扫描功能
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
}
...
}
1、先获取AnnotatedBeanDefinitionReader bean的读取器。如何获取这个读取器的呢?
直接new 了一个读取器,我们接着往里看。在这个方法里调用了
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
熟悉不熟悉,我在上一篇文章中说过这个方法,这里就不在重复讲解了,清楚的可以看我上篇文章:https://mp-new.csdn.net/mp_blog/creation/editor/117809214
这里结束之后,我们的BeanFactory就不在孤单了,里面注册了几个特殊的Bean,这些特殊的Bean都非常重要,我们后续说,这里你要重点记住一个叫做:
internalConfigurationAnnotationProcessor的bean,这里先不多说,读者只需要记住有这么一个bean就可以了。
现在我们回到 AnnotationConfigWebApplicationContext-->loadBeanDefinitions 方法里:
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {
...
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// 生成bean的名字生成器
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
// 注册到容器里
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
// scoope的解析器
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.componentClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering component classes: [" +
StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
}
// 若是指定的Bean,就交给reder中的doRegisterBean去解析每一个 Config Bean
reader.register(ClassUtils.toClassArray(this.componentClasses));
}
// 扫描配置文件的Bean
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// 这里很重要 spring提供的包扫描功能
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
}
...
}
下面这个方法我就不说了吧,我在第一篇文章里已经说过了并带有完成了图例解析:
主要是Config Bean
reader.register(Class<?>... componentClasses),会循环遍历这些类,将Class转换成一个
BeanDefinition,而后解析作用域,处理通用注解(@Lazy,@Primary,@DependsOn,@Role,@Description),最后注册到BeanFactory当中。
if (!this.componentClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering component classes: [" +
StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
}
// 若是指定的Bean,就交给reder中的doRegisterBean去解析每一个 Config Bean
reader.register(ClassUtils.toClassArray(this.componentClasses));
}
我们继续往下看:
// 扫描配置文件的Bean
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// 这里很重要 spring提供的包扫描功能
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
点开scanner.scan()方法,
这里重点看 doScan()方法。遍历basePackages,然后获取page下的所有的Class转换为
BeanDefinition,而后解析Bean的作用于,一些通过注解,最后将Bean注册到DefaultListableBeanFactory里的Map<String, BeanDefinition> beanDefinitionMap当中。
至此,将扫描包下所有的类都注册到map当中了。
到此为止,我们这个刷新工厂类就说完了。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
......
protected final void refreshBeanFactory() throws BeansException {
// 如果ApplicationContext中已经加载过BeanFactory了,销毁虽有的Bean,关闭BeanFactory
//注意:应用中BeanFactory本来就可以多个的,这里不是说应用全局是否有BeanFactory,
// 而是当前ApplicationContext是否有BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置BeanFactory的两个配置属性:是否允许Bean覆盖,是否允许循环引用
customizeBeanFactory(beanFactory);
// 加载bean 到BeanFactory中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
......
}
我们现在返回到obtainFreshBeanFactory()方法,refreshBeanFactory()我们已经说过,还剩下一个getBeanFactory();
getBeanFactory()是一个抽象方法,我们进去看:
这里就是把BeanFactory返回。
到此:我们整个obtainFreshBeanFactory()方法就说完了。
我们来总结一下:refresh()方法的前两步:
第一:标记容器为启动状态并记录启动时间,执行初始化属性源操作
第二:得到一个新的beanFactory工厂,用来保存bean容器 等同于 IOC容器,然后采用模板方法加载所有的Bean配置信息。