Spring源码学习笔记(五、Spring启动流程解析:准备BeanFactory)

目录:

  • 解析Bean表达式:BeanExpressionResolve
  • 属性编辑器:PropertyEditor
  • Aware感知
  • 忽略自动转配
  • BeanPostProcessor

还是和之前一样,我先把主流程的代码贴出来,方便你查阅。

 1 @Override
 2 public void refresh() throws BeansException, IllegalStateException {
 3     // 方法加锁避免多线程同时刷新Spring上下文
 4     synchronized (this.startupShutdownMonitor) {
 5         // 准备上下文刷新
 6         prepareRefresh();
 7 
 8         // 告诉子类刷新内部的beanFactory返回新的BeanFactory
 9         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
10 
11         // 在当前上下文中准备要beanFactory
12         prepareBeanFactory(beanFactory);
13 
14         try {
15             // 允许在上下文子类中对beanFactory进行后置处理
16             postProcessBeanFactory(beanFactory);
17 
18             // 在上下文中将BeanFactory处理器注册为Bean
19             invokeBeanFactoryPostProcessors(beanFactory);
20 
21             // 注册Bean处理器用于拦截Bean的创建
22             registerBeanPostProcessors(beanFactory);
23 
24             // 在上下文中初始化国际化信息
25             initMessageSource();
26 
27             // 在上下文中初始化event multicaster(事件多播器)
28             initApplicationEventMulticaster();
29 
30             // 在指定的上下文子类中初始化其他指定的beans
31             onRefresh();
32 
33             // 检查并注册事件监听
34             registerListeners();
35 
36             // 实例化所有剩余的(非延迟初始化)单例
37             finishBeanFactoryInitialization(beanFactory);
38 
39             // 最后一步:发布相应的事件
40             finishRefresh();
41         }
42 
43         catch (BeansException ex) {
44             if (logger.isWarnEnabled()) {
45                 logger.warn("Exception encountered during context initialization - " +
46                         "cancelling refresh attempt: " + ex);
47             }
48 
49             // 如果出现异常则销毁已创建的单例
50             destroyBeans();
51 
52             // 重置活动标志
53             cancelRefresh(ex);
54 
55             // 将异常传递给调用者
56             throw ex;
57         }
58 
59         finally {
60             // Reset common introspection caches in Spring's core, since we
61             // might not ever need metadata for singleton beans anymore...
62             resetCommonCaches();
63         }
64     }
65 }

prepareBeanFactory源码如下:

 1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 2     // 设置上下文类加载器
 3     beanFactory.setBeanClassLoader(getClassLoader());
 4     // 设置BeanExpressionResolver,用于解析属性占位符
 5     beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
 6     // 设置PropertyEditor,用于对象与字符串之间的转换
 7     beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
 8 
 9     // 配置BeanFactory的Context上下文回调
10     beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
11     // 忽略各种依赖接口
12     beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
13     beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
14     beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
15     beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
16     beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
17     beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
18 
19     // BeanFactory接口不在普通工厂中注册为可解析类型
20     // MessageSource注册(找到并自动装配)为一个Bean
21     beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
22     beanFactory.registerResolvableDependency(ResourceLoader.class, this);
23     beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
24     beanFactory.registerResolvableDependency(ApplicationContext.class, this);
25 
26     // MessageSource 注册(找到并自动装配)为一个Bean
27     beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
28 
29     // 如果发现LoadTimeWeaver,则准备植入
30     if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
31         beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
32         // 给类型匹配设置一个临时的ClassLoader
33         beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
34     }
35 
36     // Register default environment beans.
37     if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
38         beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
39     }
40     if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
41         beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
42     }
43     if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
44         beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
45     }
46 }

首先类加载器没什么可说的,就是获取一些上下文的资源。

———————————————————————————————————————————————————————

BeanExpressionResolve

我们直接看第5行的setBeanExpressionResolver

BeanExpressionResolve其实就是用来解析Bean表达式的,默认前后缀分别是“#{”和“}”,当然你也可以自定义前后缀,如下:

 1 // 表达式默认前缀 >>> "#{"
 2 public static final String DEFAULT_EXPRESSION_PREFIX = "#{";
 3 
 4 // 表达式默认后缀 >>> "}"
 5 public static final String DEFAULT_EXPRESSION_SUFFIX = "}";
 6 
 7 public void setExpressionPrefix(String expressionPrefix) {
 8     Assert.hasText(expressionPrefix, "Expression prefix must not be empty");
 9     this.expressionPrefix = expressionPrefix;
10 }
11 
12 public void setExpressionSuffix(String expressionSuffix) {
13     Assert.hasText(expressionSuffix, "Expression suffix must not be empty");
14     this.expressionSuffix = expressionSuffix;
15 }

———————————————————————————————————————————————————————

PropertyEditor

之后就是添加属性编辑器,PropertyEditor。

它是用于对象与字符串之间的转换,如“2020-05-04”就可以解析成日期对象。

Spring提供了很多内置的PropertyEditor,它们都位于org.springframework.beans.propertyeditors包中。默认情况下,大多数由BeanWrapperImpl注册

  • CustomBooleanEditor:布尔属性编辑器。默认情况下由BeanWrapperImpl注册,但是可以通过将其自定义实例注册为自定义编辑器来覆盖。
  • CustomCollectionEditor:集合属性编辑器,可将任何源集合转换为给定的目标集合类型。
  • CustomDateEditor:Date自定义属性编辑器,支持自定义DateFormat。
  • CustomNumberEditor:Number自定义属性编辑器。可用于任何Number子类,如Integer,Long,Float,Double。默认情况下由BeanWrapperI。
  • PropertiesEditor:将字符串转换为Properties对象。默认情况下由BeanWrapperImpl注册。

当然你也可以自定义,我们来模仿CustomDateEditor,写一个日期的转换。

通过查看CustomDateEditor源码,发现其继承自PropertiesEditor,所以我们也同样继承PropertiesEditor,具体实现如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5 
 6     <!-- PropertyEditor方式,和PropertyEditorRegistrar方式二选一 -->
 7     <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
 8         <property name="customEditors">
 9             <map>
10                 <entry key="java.util.Date" value="com.jdr.spring.propertyeditor.CustomEditor"/>
11             </map>
12         </property>
13     </bean>
14 
15     <!-- PropertyEditorRegistrar方式,和PropertyEditor方式方式二选一 -->
16     <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
17         <property name="propertyEditorRegistrars">
18             <list>
19                 <bean class="com.jdr.spring.propertyeditor.CustomEditorRegistrar"/>
20             </list>
21         </property>
22     </bean>
23 
24     <bean class="com.jdr.spring.propertyeditor.PropertyEditorBean" name="propertyEditorBean">
25         <property name="date" value="2020-05-24 22:00:00"/>
26     </bean>
27 
28 </beans>
 1 public class PropertyEditorBean {
 2 
 3     private Date date;
 4 
 5     public Date getDate() {
 6         return date;
 7     }
 8 
 9     public void setDate(Date date) {
10         this.date = date;
11     }
12 }
 1 public class CustomEditor extends PropertyEditorSupport {
 2 
 3     @Override
 4     public String getAsText() {
 5         return super.getAsText();
 6     }
 7 
 8     @Override
 9     public void setAsText(String text) throws IllegalArgumentException {
10         try {
11             DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
12             Date parse = format.parse(text);
13             setValue(parse);
14         } catch (ParseException e) {
15             e.printStackTrace();
16         }
17     }
18 }
1 public class CustomEditorRegistrar implements PropertyEditorRegistrar {
2 
3     @Override
4     public void registerCustomEditors(PropertyEditorRegistry registry) {
5         registry.registerCustomEditor(Date.class, new CustomEditor());
6     }
7 }
1 public class Test {
2 
3     public static void main(String[] args) {
4         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("propertyEditor.xml");
5         PropertyEditorBean propertyEditorBean = (PropertyEditorBean) ctx.getBean("propertyEditorBean");
6         System.out.println(propertyEditorBean.getDate());
7     }
8 }

———————————————————————————————————————————————————————

Aware感知

我们可以prepareBeanFactory的12-17行看到有很多的Aware,那Aware究竟是做什么的呢。

如果在某个Bean里面想要使用Spring框架提供的功能,可以通过Aware接口来实现

通过实现Aware接口,Spring可以在启动时,调用接口定义的方法,并将Spring底层的一些组件注入到自定义的Bean中。

  • ApplicationContextAware:当ApplicationContext创建实现ApplicationContextAware接口的Bean实例时,将为该Bean实例提供对该ApplicationContext的引用。
  • ApplicationEventPublisherAware:为Bean实例提供对ApplicationEventPublisherAware的引用。
  • BeanFactoryAware:为Bean实例提供对BeanFactory的引用。
  • BeanNameAware:获取Bean在BeanFactory中配置的名字。
  • MessageSourceAware:为Bean实例提供对MessageSource的引用。
  • EnvironmentAware:获得Environment支持,这样可以获取环境变量。
  • ResourceLoaderAware:获得资源加载器以获得外部资源文件。
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
5 
6     <bean id="awareBean" class="ai.yunxi.aware.AwareBean"/>
7 </beans>
 1 public class AwareBean implements ApplicationContextAware, BeanNameAware {
 2     @Override
 3     public void setBeanName(String name) {
 4         System.out.println("=====>" + name);
 5     }
 6 
 7     @Override
 8     public void setApplicationContext(ApplicationContext ctx)
 9             throws BeansException {
10         System.out.println("=====>" + ctx.getBean("awareBean"));
11     }
12 }

———————————————————————————————————————————————————————

忽略自动转配:

Spring在ConfigurableListableBeanFactory接口中提供了2个可以忽略自动装配的方法:

1 // 自动装配时忽略指定接口或类的依赖注入
2 void ignoreDependencyType(Class<?> type);
3 
4 // 忽略接口实现类中存在依赖外部的Bean注入
5 void ignoreDependencyInterface(Class<?> ifc);

忽略自动装配的做法使得一些基础组件(如:ApplicationContext或BeanFactory)依赖在自动装配时被忽略,而由框架统一设置依赖。如ApplicationContextAware接口的设置会在ApplicationContextAwareProcessor类中完成。

BeanPostProcessor

如果想在Spring容器中完成Bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理,就需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

posted @ 2020-05-25 17:57  被猪附身的人  阅读(279)  评论(0编辑  收藏  举报