AbstractApplicationContext类refresh()方法中的第三个调用方法prepareBeanFactory()的跟踪。
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {...// Prepare the bean factory for use in this context.// 准备在上下文中bean factory的使用prepareBeanFactory(beanFactory);···}
- 为工厂设置类的加载器、表达式解析器、属性编辑器注册器等
- 为工厂添加后处理器、要忽略的依赖接口
- 在工厂中注册可解析的依赖
- 在工厂中提前注册一些单例Bean ```java /**
- Configure the factory’s standard context characteristics,
- such as the context’s ClassLoader and post-processors. *
配置工厂的标准上下文特征,比如上下文的ClassLoader和post-processors */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //告知内部的bean工厂,使用上下文的类加载器 beanFactory.setBeanClassLoader(getClassLoader());
//设置bean表达式解析器, //StandardBeanExpressionResolver内部expressionParser属性默认SpelExpressionParser类型 //spel = spring el表达式 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//将ResourceEditorRegistrar实例添加到工厂的propertyEditorRegistrars属性中, //propertyEditorRegistrars是一个LinkedHashSet,里面的元素将会应用到工厂bean中 //ResourceEditorRegistrar持有上下文和environment的引用 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 使用上下文回调配置bean 工厂 //在工厂的beanPostProcessor属性中添加处理器,beanPostProcessor是一个ArrayList beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//在工厂的ignoredDependencyInterfaces属性中添加Aware系列接口, //ignoredDependencyInterfaces是一个HashSet beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean.
// 在普通的工厂中,BeanFactory接口并没有按照resolvable类型进行注册 // MessageSource被注册成一个Bean(并被自动注入)
//BeanFactory.class为key,beanFactory为value放入到了beanFactory的resolvableDependencies属性中 //resolvableDependencies是一个ConcurrentHashMap,映射依赖类型和对应的被注入的value //这样的话BeanFactory/ApplicationContext虽然没有以bean的方式被定义在工厂中, //但是也能够支持自动注入,因为他处于resolvableDependencies属性中 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
//再将上下文的一些接口与上下文本身做映射,一一放入到resolvableDependencies中 beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Detect a LoadTimeWeaver and prepare for weaving, if found. // 检测LoadTimeWeaver,如果有就准备织入 //1.跟踪进入,浅看下containsBean方法 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
//如果有LoadTimeWeaver,加入bean后处理器beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.// 为匹配类型设置一个临时的ClassLoaderbeanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans. // 注册默认的environment beans
// 判断目前这个bean工厂中是否包含指定name的bean,忽略父工厂 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
//虽然XmlWebApplicationContext中持有默认实现的StandardServletEnvironment//但是没有注册到beanFactory中,通过getEnvironment方法拿到持有的引用//2.注册environment单例beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
} if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
//注册systemProperties单例beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
} if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
//注册systemEnvironment单例beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
} }
<a name="IVQEs"></a>## 一、 增加SPEL语言的支持Spring 表达式语言全称为 “Spring Expression Language”,缩写为 “SpEL”,类似于Struts 2x 中使用的OGNL表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等, 并且能与Spring功能完美整合,比如能用 来配置bean定义。SpEL是单独模块,只依赖于core 模块,不依赖于其他模块,可以单独使用。<br />SpEL使用#{...}为定界符,所有在花括号中的字符都将被认为是SpEL,使用格式如下:```xml<bean id = "saxophone" value = "com.xxx.xxx.Xxx"/><bean ><property name="instrument" value="#{saxophone}"/><bean/>
相当于:
<bean id = "saxophone" value = "com.xxx.xxx.Xxx"/><bean ><property name="instrument" ref="saxophone"/><bean/>
当然,上面只是列举了其中最简单的使用方式,SPEL功能非常强大,使用好可以大大提高开发效率,这里只为唤起读者的记忆来帮助我们理解源码,有兴趣的读者可以进一步深入研究。
在源码中通过代码beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注册语言解析器,就可以对SPEL进行解析了,那么在注册解析器后 Spring 又是在什么时候调用这个解析器进行解析呢?
之前我们讲解过 Spring 在 bean 进行初始化的时候会有属性填充的一步,而在这一步中 Spring 会调用AbstractAutowireCapableBeanFactory类的 applyPropertyValues 函数来完成功能。就在这个函数中,会通过构造 BeanDefinitionValueResolver类型实例 valueResolver 来进行属性值的解析。同时,也是在这个步骤中一般通过 AbstractBeanFactory中的evaluateBeanDefinitionString 方法去完成 SPEL 的解析。
二、增加属性注册编辑器
JavaBean API 中提供了这样一个接口:java.beans.PropertyEditor,该接口提供了将字符串值(String类型)映射为非String类型的方法。它便是传说中的属性编辑器。通过实现该接口,用户可以编写自定义属性编辑器,以将spring配置文件中的字符串转换成相应的对象注入。
但该接口有12个方法,如果用户要实现该接口编写自定义的属性编辑器会比较麻烦。幸运的是有一个好用的这个接口的实现类:`java.beans.PropertyEditorSupport`,我们可以继承这个实现类,覆写其中的`setAsText(String value)`方法,来实现我们的自定义属性编辑器。[
](https://blog.51cto.com/xiannenglin/435814)
配置属性自定义转换器可以参考:
10-Spring-配置属性自定义转换
Spring提供了一个配置类CustomEditorConfigurer,可以将自定义的属性编辑器注入到Spring中。此类实现了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor可以在Bean实例化之前,往Spring容器中注入其他Bean。
从上面的CustomEditorConfigurer继承关系图可以看出,CustomEditorConfigurer实现了BeanFactoryPostProcessor接口。BeanFactoryPostProcessor是BeanFactory的后置处理器(BeanFactoryPostProcessor能定制和修改BeanFactory的内容,如覆盖或添加属性)。在BeanFactory标准初始化之后调用,这时所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建(即在Spring源码中refresh方法中的**invokeBeanFactoryPostProcessors**_**(**_**beanFactory**_**)**_**;**这个方法处理的是 实现BeanFactoryPostProcessor 接口的 Bean)。
理清楚BeanFactoryPostProcessor的功能作用后,下面进行分析CustomEditorConfigurer的工作原理。
@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if (this.propertyEditorRegistrars != null) {for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);}}if (this.customEditors != null) {this.customEditors.forEach(beanFactory::registerCustomEditor);}}
CustomEditorConfigurer,它是一个特殊的BeanFactoryPostProcessor,可以将自定义的PropertyEditor或者PropertyEditorRegistrar实现存入其内部的customEditors和propertyEditorRegistrars属性中,启动项目之后,它的postProcessBeanFactory方法会在所有普通bean实例化和初始化之前(创建BeanWrapper之前)调用beanFactory来将这些PropertyEditor和propertyEditorRegistrars注册到AbstractBeanFactory的customEditors和propertyEditorRegistrars缓存。
基于以上的配置,在Spring bean对应的BeanWrapper初始化时,会自动从AbstractBeanFactory的customEditors和propertyEditorRegistrars缓存中将自定义的PropertyEditor注册到自己内部(位于AbstractBeanFactory#initBeanWrapper方法中),之后被BeanWrapper用于创建和填充 Bean 实例的类型转换。
但是请注意,这种配置不适用于Spring MVC的数据绑定,因为DataBinder默认不会查找这里注册到AbstractBeanFactory中的customEditors和propertyEditorRegistrars缓存,数据绑定时需要的自定义Editor必须在org.springframework.validation.DataBinder中手动注册(通过Spring MVC的@InitBinder方法)。
三、 添加 ApplicationContextAwareProcessor 处理器
了解了属性编辑器的使用后,接下来我们继续通过AbstractApplicationContext的 prepareBeanFactory 方法的主线来进行函数跟踪。对于 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))其实主要目的就是注册个 BeanPostProcessor,而真正的逻辑还是在ApplicationContextAwareProcessor中。ApplicationContextAwareProcessor 实现BeanPostProcessor 接口,我们回顾下之前讲过的内容,在bean实例化的时候,也就是Spring激活bean的init-method的前后,会调用BeanPostProcessor的 postProcessBeforelnitialization 方法和postProcessAfterlnitialization 方法。问样,对于ApplicationContextAwareProcessor我们也关心这两个方法。对于postProcessAfterlnitialization方法,在ApplicationContextAwareProcessor中并没有做过多逻辑处理。
@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}
那么,我们重点看一下postProcessBeforelnitialization 方法。
@Override@Nullablepublic Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {AccessControlContext acc = null;// 省略代码....else {// 在postProcessBeforeInitialization调用invokeAware接口invokeAwareInterfaces(bean);}return bean;}private void invokeAwareInterfaces(Object bean) {if (bean instanceof Aware) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}}}
四. 设置忽略依赖
当Spring 将ApplicationContextAwareProcessor注册后,那么在invokeAwarelnterfaces方法中间接调用的 Aware 类已经不是普通的 bean 了,如 ResourceLoaderAware、ApplicationEventPublisher Aware等,那么当然需要在Spring做bean的依赖注入的时候忽略它们。而ignoreDependencylnterfece的作用正是在此。prepareBeanFactory方法中就有如下代码来禁止Environment或者ApplicationContext通过Autowired等方式获取
