Spring 源码阅读笔记(二)

Spring 源码阅读笔记(二)

前景回顾

在上一章节中,我们读了super()和setConfigLocations()还记得他们是做什么的么。

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) { // 第一次启动,上一个构造函数传的为true
      refresh();
   }
}
复制代码

先回顾一下方法调用流程图和在上一章节中,最后的类图。

2022-03-17-17-11-02-image.png image.png

上一章节中我们讲到setConfigLocations方法,最终得知,比较重要的两个点。

  1. 设置 AbstractApplication中的environment
  2. 在environment中设置了一个property集合

refresh()

根据开头的方法调用流程图中,Spring的关键都在refresh中。一共有12个方法,我们一个一个来看。

prepareRefresh()

刚追进refresh方法中,马上引入眼帘的第一个方法prepareRefresh,根据官方的注释解释,为上下文准备刷新。大概率是做一些准备操作,按道理这个是可以跳过的,但是作为学习的姿态,我们一个都不能漏过。

/**
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 * 准备此上下文以进行刷新,设置其启动日期和活动标志,以及执行属性源的任何初始化。
 */
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
   // 验证所有标记为必需的属性是否可解析:请参阅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,在Multicast可用后发布。。。
   this.earlyApplicationEvents = new LinkedHashSet<>();
}
复制代码

将代码中原有的注释翻译,可以对这个方法有一个大致的了解,但是具体是什么意思呢,我也不知道,此代码我觉得可以分段阅读进行归类。

第一段代码

this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

// 根据debug状态记录一些日志
if (logger.isDebugEnabled()) {
   if (logger.isTraceEnabled()) {
      logger.trace("Refreshing " + this);
   }
   else {
      logger.debug("Refreshing " + getDisplayName());
   }
}
复制代码

这一段代码很简单,设置了一下项目启动的时间,做了一些状态为的管理,打印了一些日志,没什么好看的。

第二段代码

initPropertySources();

protected void initPropertySources() {
   // For subclasses: do nothing by default.
}
复制代码

很明显这是一个模版方法,在上一篇文章中我们也遇到这个设计模式,简单看一下他的子类有哪些扩展吧。

image.png 查看这个方法的实现子类后,发现都是在web包下的,这不是我们这一系列要讲的,我们先跳过。知道这里spring留了一个配置就好了。

第三段代码

getEnvironment().validateRequiredProperties();

@Override
public void validateRequiredProperties() {
   MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
   for (String key : this.requiredProperties) {
      if (this.getProperty(key) == null) {
         ex.addMissingRequiredProperty(key);
      }
   }
   if (!ex.getMissingRequiredProperties().isEmpty()) {
      throw ex;
   }
}
复制代码

getEnvironment这个方法还记得吧,这个方法最终返回了一个StandardEnvironment,AbstractEnvironment和AbstractPropertyResolver都有实现validateRequiredProperties方法,最终调用的事AbstractPropertyResolver类中的validateRequiredProperties方法。
这个方法用来校验必填的属性,由于我没有设置,此处的requiredProperties的size为0,for不会执行,此方法结束

第四段代码

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,在Multicast可用后发布。。。
this.earlyApplicationEvents = new LinkedHashSet<>();
复制代码

这个代码块中,发现了几个观察者模式的监听器,至于监听器是做什么的,目前不知道,先跳过,记录一下这里有几个监听器即可。

prepareRefresh方法到这里就结束了,总结一下,这个方法只是做了一些准备动作,没有什么太大的意义。

obtainFreshBeanFactory()

看obtainFreshBeanFactory方法的字面意思,是获取一个BeanFactory。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   return getBeanFactory();
}

@Override
protected final void refreshBeanFactory() throws BeansException {
    // 第一次进入,此处为false
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // 创建一个Bean工厂
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      this.beanFactory = beanFactory;
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}
复制代码

refreshBeanFactory方法实现自AbstractRefreshableApplicationContext,接下来一层一层的看。

createBeanFactory()

protected DefaultListableBeanFactory createBeanFactory() {
   return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}


protected BeanFactory getInternalParentBeanFactory() {
   return (getParent() instanceof ConfigurableApplicationContext ?
         ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
}
复制代码

这里new了一个DefaultListableBeanFactory对象,构造中传入了一个方法,此方法放回了一个BeanFactory,由于此处我们的getParent为null,所以此处返回null值,继续往下看。

public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   super(parentBeanFactory);
}


public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   this();
   setParentBeanFactory(parentBeanFactory);
}

public AbstractAutowireCapableBeanFactory() {
   super();
   ignoreDependencyInterface(BeanNameAware.class);
   ignoreDependencyInterface(BeanFactoryAware.class);
   ignoreDependencyInterface(BeanClassLoaderAware.class);
   if (NativeDetector.inNativeImage()) {
      this.instantiationStrategy = new SimpleInstantiationStrategy();
   }
   else {
      this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
   }
}

@Override
public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
      throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
   }
   if (this == parentBeanFactory) {
      throw new IllegalStateException("Cannot set parent bean factory to self");
   }
   this.parentBeanFactory = parentBeanFactory;
}
复制代码

这里好像似曾相识,和前一章节中的构造很像,看一下他的实现吧。
他的无参构造中的ignoreDependencyInterface方法根据字面意思解释忽略依赖接口,看解释是在依赖项检查和autowire时要忽略的接口,具体什么意思还没领略到,后面再看,先记录。
下面的判断,由于我们没有进行特殊的配置,Spring使用Cglib的策略来实例化对象。 到这里实例化Bean工厂时的步骤就结束了,得出一些结论\

  1. 实例化的是DefaultListableBeanFactory
  2. 实例化策略使用的是Cglib

customizeBeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   if (this.allowBeanDefinitionOverriding != null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   if (this.allowCircularReferences != null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
}
复制代码

根据ApplicationContext的自身的值,来赋值给刚刚创建出来的Bean工厂中,由于此处我们的ApplicationContext都为空,这里都不会走进去
字面意思理解这两个变量

  1. AllowBeanDefinitionOverriding 允许Bean定义重写
  2. allowCircularReferences 允许循环引用

后续看这两个值是在注册中是如何使用的。有看到循环引用的字样,比较重要。

loadBeanDefinitions

看方法字面意思是加载Bean定义,小激动了一把,终于看到和Bean相关的信息了。

protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
      throws BeansException, IOException;
复制代码

点入方法看到是一个抽象方法,查看他有哪些实现方法。

image.png 我们使用的XML的方式加载ApplicationContext,所以这里我们查看这个实现类的实现方法。

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}
复制代码

告一段落

凌晨2点了,此篇文章先到这吧,我明天再更。
现在接着写作状态不太对,先休息下,到目前为止,我们的类关系图我在下面贴出。

image.png

结束语

写文章的目的是为了帮助自己巩固知识,如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。

image.png

Supongo que te gusta

Origin juejin.im/post/7076494497332346910
Recomendado
Clasificación