Spring 源码阅读笔记(五)

297 阅读5分钟

Spring 源码阅读笔记(五)

前篇导航

Spring 源码阅读笔记(一)
Spring 源码阅读笔记(二)
Spring 源码阅读笔记(三)
Spring 源码阅读笔记(四)

前篇回顾

在上一篇章节中,由于后面的需要,我们穿插了一篇文章,来讲BeanDefinition的创建和Definition进入DefaultListableBeanFactory中。最终是把BeanDefinition放入了BeanDefinitionMap中。

在这里值得一提的是,BeanDefinition对象中,有一个属性,BeanClass,他是一个Object类型,在createBeanDefinition方法是设置的className属性,在内部实现中,他直接把String赋值给了BeanClass对象,在使用时会instanceof的。

正式开始

后面这篇文章正式开始,在这篇文章中会开始对prepareBeanFactory方法进行解读,在Refresh方法中,是第三个方法。

// Prepare the bean factory for use in this context.
// 准备 bean 工厂以在此上下文中使用。
prepareBeanFactory(beanFactory);

根据这个方法上面的注释,我产生一个疑问,不知道他在准备什么Bean工厂,因为在上篇文章中,他已经拿到了一个Bean工厂,并且还设置了BeanDefinition在里面。这个时候我带着问题向下看。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   // 告诉内部 bean 工厂使用上下文的类加载器等。
   beanFactory.setBeanClassLoader(getClassLoader());
   if (!shouldIgnoreSpel) {
      beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   }
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   // 使用上下文回调配置 bean 工厂。
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // BeanFactory 接口未在普通工厂中注册为可解析类型。
   // MessageSource registered (and found for autowiring) as a bean.
   // MessageSource 作为 bean 注册(并为自动装配找到)。
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   // 将用于检测内部 bean 的早期后处理器注册为 ApplicationListener。
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   // 检测 LoadTimeWeaver 并准备编织(如果找到)。
   if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      // 为类型匹配设置一个临时 ClassLoader。
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   // 注册默认环境 bean。
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
   if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
      beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
   }
}

在这个代码块中,可以发现的是代码注释很多,这意味着我们少了一些阅读困难

不过大致读了一下,心里只有一个反应这都是个啥,一堆设置信息,怪不得开头叫准备Bean工厂。读这一代码我们还是采取像之前的分段阅读模式。

第一段代码

beanFactory.setBeanClassLoader(getClassLoader());
if (!shouldIgnoreSpel) {
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

通过上方代码,先是给Beanfactory中设置了一个classloader,盲猜是用来创建Bean用的。

进入if,根据字面意思是,要不要忽略el表达式。,通过properties文件去查找spring.spel.ignore属性,我们没有设置,此处为false,判断去反,进入进入环节。设置了一个ExpressionResolver(表达式解析器)。StandardBeanExpressionResolver内部是SpelExpressionParser。

最后一行是向Bean工厂中添加了一个PropertyEditorRegister,具体做什么的目前不知道,这个类型是resourceEditorRegister。这里不知道是一个责任链还是一个观察者。看面看用到他的地方发吧,

第二段代码

// 使用上下文回调配置 bean 工厂。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

这一段代码除了第一行代码不一样,其他的基本一致

看到第一行代码,用过Spring应该都知道,BeanPostProcessor,这里就是向Bean工厂中添加了一个ApplicationContextAwareProcessor。这个类也很简单。我大致解读一下,我们之间可能有接触过的。

小插曲

private void invokeAwareInterfaces(Object bean) {
   // ... 一堆if
   if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
   }
}

我在写Spring项目的时候都遇到过要通过ApplicationContext来获取Bean,那么怎么获取ApplicationContext,我们大部分人用的就是创建一个类,实现ApplicationContextArare接口,然后就可以获取了。原因是什么呢,就是这里了。在Spring把ApplicationContextAware接口实例化后,会有一个PostProcessor去调用它里面的setApplicationContext方法。

回到正轨

在设置完ApplicationContextAwareProcessor后,调用了一堆ignoreDependencyInterface方法,传入方法的实体类都是ApplicationContextAwareProcessor中涉及到的接口,具体这个方法看实现只是向一个HashSet中添加值,这个属性后面遇到了再进行探讨。

第三段代码

// BeanFactory interface not registered as resolvable type in a plain factory.
// BeanFactory 接口未在普通工厂中注册为可解析类型。
// MessageSource registered (and found for autowiring) as a bean.
// MessageSource 作为 bean 注册(并为自动装配找到)。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

调用了一堆registerResolvableDependency方法,这里做记录,后面说不定用得到。可能作为容器使用。

第四段代码

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

这里又添加了一个BeanPostProcess,看New出来的类名,和在Refresh中的第一个方法中的观察者模式有关系。

第五段代码

if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
   beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
   // Set a temporary ClassLoader for type matching.
   // 为类型匹配设置一个临时 ClassLoader。
   beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

这段代码和loadTimeWeaver有关,至于loadTimeWeaver是什么可以自己去了解下,或者我我后面开篇文章来讲一下。这里由于我们没有设置,可以跳过。

第六段代码。

// Register default environment beans.
// 注册默认环境 bean。
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
   beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
   beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
   beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
   beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}

看这段代码很简单,我在疑惑containsLocalBean方法是什么意思。在这里要解释一下,BeanFactory他是有继承关系的。在Bean接口中他有如下的解释。

Return whether the local bean factory contains a bean of the given name, ignoring beans defined in ancestor contexts.

大概的意思就是,检查当前的facotry中有没有这个Bean,不考虑他的祖先工厂中是否存在。

那么这段代码就可以看明白了,如果当前工厂中不存在这些Bean的话,就以单例的形式,在当前的Bean Factory中重新注册一个。

告一段落

到这里这篇文章就结束了,那么正如方法开头的注释一样。

Prepare the bean factory for use in this context.
准备 bean 工厂以在此上下文中使用。

结束语

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