本文介绍spring应用上下文的refresh方法。
我们以AnnotationConfigApplicationContext为例。
前言 在介绍 refresh() 方法之前,简单看下 AnnotationConfigApplicationContext 的构造函数:
1 2 3 4 5 6 7 public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { public AnnotationConfigApplicationContext (String... basePackages) { this (); scan(basePackages); refresh(); } }
##refresh方法总览
refresh方法的左右: 在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。因此refresh类似于对IoC容器的重启。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { destroyBeans(); cancelRefresh(ex); throw ex; } } } }
初始化 refresh 的上下文环境 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected void prepareRefresh () { this .startupDate = System.currentTimeMillis(); this .closed.set(false ); this .active.set(true ); initPropertySources(); getEnvironment().validateRequiredProperties(); if (this .earlyApplicationListeners == null ) { this .earlyApplicationListeners = new LinkedHashSet<>(this .applicationListeners); } else { this .applicationListeners.clear(); this .applicationListeners.addAll(this .earlyApplicationListeners); } this .earlyApplicationEvents = new LinkedHashSet<>(); }
添加的监听器样例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0 = {ConditionEvaluationReportLoggingListener$ConditionEvaluationReportListener@3109} 1 = {ServerPortInfoApplicationContextInitializer@3110} 2 = {BootstrapApplicationListener@3111} 3 = {LoggingSystemShutdownListener@3112} 4 = {ConfigFileApplicationListener@3113} 5 = {AnsiOutputApplicationListener@3114} 6 = {LoggingApplicationListener@3115} 7 = {BackgroundPreinitializer@3116} 8 = {ClasspathLoggingApplicationListener@3117} 9 = {RestartListener@3118} 10 = {DelegatingApplicationListener@3119} 11 = {ParentContextCloserApplicationListener@3120} 12 = {ClearCachesApplicationListener@3121} 13 = {FileEncodingApplicationListener@3122} 14 = {LiquibaseServiceLocatorApplicationListener@3123} 15 = {EnableEncryptablePropertiesBeanFactoryPostProcessor@3124}
初始化 BeanFactory 1 2 3 4 5 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); return getBeanFactory(); }
1 2 3 4 5 6 7 8 @Override protected final void refreshBeanFactory () throws IllegalStateException { if (!this .refreshed.compareAndSet(false , true )) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once" ); } this .beanFactory.setSerializationId(getId()); }
对 BeanFactory 进行功能增强 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 protected void prepareBeanFactory (ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this , getEnvironment())); 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.registerResolvableDependency(BeanFactory.class , beanFactory ) ; beanFactory.registerResolvableDependency(ResourceLoader.class , this ) ; beanFactory.registerResolvableDependency(ApplicationEventPublisher.class , this ) ; beanFactory.registerResolvableDependency(ApplicationContext.class , this ) ; beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this )); if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } 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()); } }
在配置 bean 的时候,如果我们希望对某一类型的属性执行一些处理,可以通过自定义属性编辑器来实现,典型的应用场景就是对时间类型属性的转换,假设我们的 bean 存在 LocalDate 类型的属性,这个时候我们直接以字符串配置进行注入是会出现异常的,这个时候我们可以自定义属性编辑器来实现类型的转换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MyDatePropertyEditor extends PropertyEditorSupport implements InitializingBean { private String format = "yyyy-MM-dd" ; private DateTimeFormatter dtf; @Override public void afterPropertiesSet () throws Exception { dtf = DateTimeFormatter.ofPattern(format); } @Override public void setAsText (String text) throws IllegalArgumentException { if (!StringUtils.hasText(text)) { this .setValue(null ); return ; } this .setValue(LocalDate.parse(text)); } public MyDatePropertyEditor setFormat (String format) { this .format = format; return this ; } }
1 2 3 4 5 6 7 8 9 10 11 12 <bean class ="org.springframework.beans.factory.config.CustomEditorConfigurer" > <property name ="customEditors" > <map > <entry key ="java.time.LocalDate" > <bean class ="org.zhenchao.editor.MyDatePropertyEditor" > <property name ="format" value ="yyyy-MM-dd" /> </bean > </entry > </map > </property > </bean >
我们自定义的属性编辑器 MyDatePropertyEditor 通过时间格式化工具对指定模式的字符串格式日期执行转换和注入,而上述转换只能在我们以 ApplicationContext 的方式加载 bean 的前提下才生效,如果我们以 BeanFactory 的方式加载 bean,还是会抛出异常,毕竟这属于高级容器中增强的功能。
当我们定义的 bean 实现了 Aware 接口的时候,这些 bean 可以比一般的 bean 多拿到一些资源,而此处对于 beanFactory 的扩展也增加了对一些 Aware 类自动装配的支持。ApplicationContextAwareProcessor 实现了 BeanPostProcessor 接口,并主要实现了 postProcessBeforeInitialization 逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public Object postProcessBeforeInitialization (final Object bean, String beanName) throws BeansException { AccessControlContext acc = null ; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this .applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null ) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run () { invokeAwareInterfaces(bean); return null ; } }, acc); } else { this .invokeAwareInterfaces(bean); } return bean; }
上述方法的核心在于 invokeAwareInterfaces 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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); } } }
整个方法的逻辑很直观,判断当前类所实现的 Aware 接口,然后将相应的资源给到该 bean
在 4.3.x 版本中增加了对实现了 ApplicationListener 接口的探测,ApplicationListenerDetector 实现了 MergedBeanDefinitionPostProcessor 和 DestructionAwareBeanPostProcessor 后置处理接口,并相应实现了这些后置处理器定义的模板方法,其中核心的方法 postProcessAfterInitialization 逻辑如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public Object postProcessAfterInitialization (Object bean, String beanName) { if (this .applicationContext != null && bean instanceof ApplicationListener) { Boolean flag = this .singletonNames.get(beanName); if (Boolean.TRUE.equals(flag)) { this .applicationContext.addApplicationListener((ApplicationListener<?>) bean); } else if (Boolean.FALSE.equals(flag)) { if (logger.isWarnEnabled() && !this .applicationContext.containsBean(beanName)) { logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface but is not reachable for event multicasting by its containing ApplicationContext " + "because it does not have singleton scope. Only top-level listener beans are allowed to be of non-singleton scope." ); } this .singletonNames.remove(beanName); } } return bean; }
该方法针对实现了 ApplicationListener 接口的单例对象,统一注册到监听器集合中监听事件,而方法中的 singletonNames 变量则是在 postProcessMergedBeanDefinition 方法中进行构建:
1 2 3 4 5 public void postProcessMergedBeanDefinition (RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { if (this .applicationContext != null ) { this .singletonNames.put(beanName, beanDefinition.isSingleton()); } }
由此我们可以知道 singletonNames 中存放了 beanName,以及对应的 bean 是否是单例的关联关系。
后置处理器 BeanFactory 该方法的实现逻辑交由子类,用于增强 Spring 框架的可扩展性。
##调用已注册的 BeanFactoryPostProcessor 后置处理器
BeanFactoryPostProcessor 用于对 BeanFactory 实例进行后置处理,而 BeanPostProcessor 用于对 bean 实例进行后置处理。
1 2 3 4 5 6 7 8 9 10 protected void invokeBeanFactoryPostProcessors (ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this .getBeanFactoryPostProcessors()); if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
以下代码为 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 public static void invokeBeanFactoryPostProcessors ( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { Set<String> processedBeans = new HashSet<String>(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>(); List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryPostProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryPostProcessor.postProcessBeanDefinitionRegistry(registry); registryPostProcessors.add(registryPostProcessor); } else { regularPostProcessors.add(postProcessor); } } String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class , true , false ) ; List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class )) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class )) ; processedBeans.add(ppName); } } sortPostProcessors(beanFactory, priorityOrderedPostProcessors); registryPostProcessors.addAll(priorityOrderedPostProcessors); invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry); postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class , true , false ) ; List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>(); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class )) { orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class )) ; processedBeans.add(ppName); } } sortPostProcessors(beanFactory, orderedPostProcessors); registryPostProcessors.addAll(orderedPostProcessors); invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry); boolean reiterate = true ; while (reiterate) { reiterate = false ; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class , true , false ) ; for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class ) ; registryPostProcessors.add(pp); processedBeans.add(ppName); pp.postProcessBeanDefinitionRegistry(registry); reiterate = true ; } } } invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class , true , false ) ; List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); List<String> orderedPostProcessorNames = new ArrayList<String>(); List<String> nonOrderedPostProcessorNames = new ArrayList<String>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class )) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class )) ; } else if (beanFactory.isTypeMatch(ppName, Ordered.class )) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } sortPostProcessors(beanFactory, priorityOrderedPostProcessors); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class )) ; } sortPostProcessors(beanFactory, orderedPostProcessors); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class )) ; } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); beanFactory.clearMetadataCache(); }
我们可以看到针对编码注册和以配置方式注册的 BeanFactoryPostProcessor,Spring 的获取方式是不一样的,前者都是注册到之前提到的 beanFactoryPostProcessors 集合中,而后者都是通过 BeanFactory 的 getBeanNamesForType 方法获取到的。
上述方法先判断 BeanFactory 是不是 BeanDefinitionRegistry 类型,如果是的话则专门处理,这样设计是因为继承自 BeanFactoryPostProcessor 的 BeanDefinitionRegistryPostProcessor 需要专门处理这种类型:
1 2 3 4 5 public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) throws BeansException ; }
并且针对配置的 BeanFactoryPostProcessor 而言,因为获取顺序的不确定性,所以 Spring 支持对其配置优先级,上述方法的逻辑也可以看出 Spring 会依次处理 PriorityOrdered、Ordered,以及其他类型,并会针对各类型进行按照比较器进行排序处理。
##注册 BeanPostProcessor 后置处理器
不同于 BeanFactoryPostProcessor 的调用,这里仅仅是对 BeanPostProcessor 的注册,因为 BeanPostProcessor 作用于 bean 实例之上,而当前还没有开始创建 bean 实例。之前讲解 getBean 过程的文章中我们应该有所记忆,BeanPostProcessor 的调用是发生在 getBean 过程中,具体来说应该是围绕 bean 实例化过程的前后。如下为 BeanPostProcessor 接口源码
1 2 3 4 5 6 7 public interface BeanPostProcessor { Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException ; Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException ; }
注册过程本质上是将配置的 BeanPostProcessor 添加到 beanPostProcessors 集合的过程,我们在简单容器中需要通过调用 addBeanPostProcessor 编码注册我们实现的 BeanPostProcessor,实际上两者本质上是一样的,只是高级容器支持以配置的方式来完成简单容器中需要编码才能完成的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public static void registerBeanPostProcessors ( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class , true , false ) ; int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>(); List<String> orderedPostProcessorNames = new ArrayList<String>(); List<String> nonOrderedPostProcessorNames = new ArrayList<String>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class )) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class ) ; priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class )) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } sortPostProcessors(beanFactory, priorityOrderedPostProcessors); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>(); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class ) ; orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(beanFactory, orderedPostProcessors); registerBeanPostProcessors(beanFactory, orderedPostProcessors); List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>(); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class ) ; nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); sortPostProcessors(beanFactory, internalPostProcessors); registerBeanPostProcessors(beanFactory, internalPostProcessors); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }
BeanPostProcessor 与 BeanFactoryPostProcessor 一样,同样支持优先级的配置。
##初始化国际化资源
笔者目前所负责的几个项目都需要考虑国际化支持,有的直接基于 jdk 原生的 ResourceBundle,有的则基于 Spring 提供的 MessageSource,在具体分析 MessageSource 的初始化过程之前,我们先来了解一下 Spring 国际化支持的设计与简单使用。
MessageSource 的设计与简单使用 Spring MessageSource 支持本质上也是对 ResourceBundle 的封装,MessageSource 接口的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public interface MessageSource { String getMessage (String code, Object[] args, String defaultMessage, Locale locale) ; String getMessage (String code, Object[] args, Locale locale) throws NoSuchMessageException ; String getMessage (MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException ; }
Spring MessageSource 相关类的继承关系如下:
其中 HierarchicalMessageSource 的设计为 MessageSource 提供了层次支持,建立了父子层级结构。 ResourceBundleMessageSource 和 ReloadableResourceBundleMessageSource 是我们常用的两个类,均可以看做是对 jdk 原生国际化支持的封装,只不过后者相对于前者提供了定时更新资源文件的支持,从而不需要重启系统。 StaticMessageSource 为编码式资源注册提供了支持, DelegatingMessageSource 则可以看做是 MessageSource 的一个代理,必要时对 MessageSource 进行封装。
下面我们演示一下 MessageSource 的简单使用,首先我们定义好国际化资源 resource.properties:
resource.properties
spring=Spring framework is a good design, the latest version is {0}
resource_zh.properties
spring=Spring 框架設計精良,當前最新版本是 {0}
resource_zh_CN.properties
spring=Spring 框架设计精良,当前最新版本是 {0}
需要注意的是,如果资源文件包含了非 ASCII 字符,则需要将文本内容转换成 Unicode 编码,jdk 自带的 native2ascii 工具可以达到目的,操作如下:
native2ascii -encoding utf-8 resource_zh.properties resource_zh_tmp.properties
然后我们在配置文件中进行如下配置:
1 2 3 4 5 6 7 8 <bean id ="messageResource" class ="org.springframework.context.support.ResourceBundleMessageSource" > <property name ="basenames" > <list > <value > i18n/resource</value > </list > </property > </bean >
调用方式如下:
1 2 3 4 5 ApplicationContext context = new ClassPathXmlApplicationContext("spring-core.xml" ); Object[] params = {"4.3.8.RELEASE" }; System.out.println(context.getMessage("spring" , params, Locale.ENGLISH)); System.out.println(context.getMessage("spring" , params, Locale.TRADITIONAL_CHINESE)); System.out.println(context.getMessage("spring" , params, Locale.SIMPLIFIED_CHINESE));
因为 ApplicationContext 同样实现了 MessageSource 接口,所以可以直接调用,但是这样调用的前提是配置中的 id 必须设置为 messageResource。输出如下:
1 2 3 Spring framework is a good design, the latest version is 4.3.8.RELEASE Spring 框架設計精良,當前最新版本是 4.3.8.RELEASE Spring 框架设计精良,当前最新版本是 4.3.8.RELEASE
###MessageSource 的初始化过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected void initMessageSource () { ConfigurableListableBeanFactory beanFactory = this .getBeanFactory(); if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { this .messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class ) ; if (this .parent != null && this .messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms = (HierarchicalMessageSource) this .messageSource; if (hms.getParentMessageSource() == null ) { hms.setParentMessageSource(this .getInternalParentMessageSource()); } } } else { DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(this .getInternalParentMessageSource()); this .messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this .messageSource); } }
前面我们在配置时推荐将 id 配置为 messageSource 是有原因的,通过阅读源码一目了然,代码中硬编码要求我们的配置 messageSource 作为 bean 的名称,否则不执行初始化,而是创建一个默认的代理,如果我们利用 ApplicationContext 对象去获取对应的资源则会出现异常,否则我们就需要手动指定 getBean 时候的名称,但是这样做是不推荐的,既然框架以约定的方式提供了相应的实现,还是推荐以 messageSource 作为 id 进行配置。
##初始化事件广播器
事件广播和监听机制是典型的观察者模式的实现,而 ApplicationEventMulticaster 也是观察者模式中主题角色的典型实现。 在 Spring 中,如果我们希望监听事件广播器广播的事件,则需要定义一个实现了 ApplicationListener 接口的监听器,Spring 支持监听器的编码注册和自动扫描注册,这个我们在后面小节中细说,我们先来看一下这里广播器的初始化过程:
1 2 3 4 5 6 7 8 9 10 11 protected void initApplicationEventMulticaster () { ConfigurableListableBeanFactory beanFactory = this .getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this .applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class ) ; } } else { this .applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this .applicationEventMulticaster); } }
逻辑很清晰,如果我们以约定的方式配置了自己的事件广播器,则初始化该广播器实例, 否则容器会创建并注册一个默认的 SimpleApplicationEventMulticaster,进入该广播器的实现我们会发现如下逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public void multicastEvent (final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : this .getApplicationListeners(event, type)) { Executor executor = this .getTaskExecutor(); if (executor != null ) { executor.execute(new Runnable() { @Override public void run () { invokeListener(listener, event); } }); } else { this .invokeListener(listener, event); } } } protected void invokeListener (ApplicationListener listener, ApplicationEvent event) { ErrorHandler errorHandler = this .getErrorHandler(); if (errorHandler != null ) { try { listener.onApplicationEvent(event); } catch (Throwable err) { errorHandler.handleError(err); } } else { try { listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || msg.startsWith(event.getClass().getName())) { Log logger = LogFactory.getLog(getClass()); if (logger.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } } }
典型的回调观察者监听方法的逻辑,如果对于观察者模式了解的话,这里的逻辑会比较好理解。
初始化其他特定的bean 提供一个模版方法 onRefresh(),子类可以实现该方法,用于初始化某些特定的bean。
##注册事件监听器
既然有被观察者,就应该有观察者,事件监听器就是我们的观察者,我们需要将其注册来监听事件消息,针对事件监听器的注册,我们可以以编码的方式进行注册,如果我们将其配置到配置文件中,容器也会自动扫描进行注册:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected void registerListeners () { for (ApplicationListener<?> listener : this .getApplicationListeners()) { this .getApplicationEventMulticaster().addApplicationListener(listener); } String[] listenerBeanNames = this .getBeanNamesForType(ApplicationListener.class , true , false ) ; for (String listenerBeanName : listenerBeanNames) { this .getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } Set<ApplicationEvent> earlyEventsToProcess = this .earlyApplicationEvents; this .earlyApplicationEvents = null ; if (earlyEventsToProcess != null ) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { this .getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
##实例化所有非延迟加载的单例
记得最开始学习 Spring 框架的时候,就看到说 BeanFactory 和 ApplicationContext 有一个很大的区别就是 BeanFactory 在初始化容器时不会实例化 bean,而 ApplicationContext 则会实例化所有非延迟加载的单例 bean,而这个加载过程就在这里发生。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 protected void finishBeanFactoryInitialization (ConfigurableListableBeanFactory beanFactory) { if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class )) { beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class )) ; } if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(new StringValueResolver() { @Override public String resolveStringValue (String strVal) { return getEnvironment().resolvePlaceholders(strVal); } }); } String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class , false , false ) ; for (String weaverAwareName : weaverAwareNames) { this .getBean(weaverAwareName); } beanFactory.setTempClassLoader(null ); beanFactory.freezeConfiguration(); beanFactory.preInstantiateSingletons(); }
由上述逻辑可以看到在执行实例化操作之前,容器会先校验一些必要的工具实例,如果之前没有注册则会创建一个默认的代替,然后会冻结所有的 bean 定义,毕竟即将开始实例化,后续的更改也不会再生效。在一些准备工作完毕之后,容器即开始实例化所有满足条件(非abstract && 单例 && 非延迟加载)的 bean。
Spring 4.1 增加了 SmartInitializingSingleton,实现了该接口的单例可以感知所有单例实例化完成的事件,而接口中声明的方法 afterSingletonsInstantiated 也在这里被回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public void preInstantiateSingletons () throws BeansException { List<String> beanNames = new ArrayList<String>(this .beanDefinitionNames); for (String beanName : beanNames) { RootBeanDefinition bd = this .getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (this .isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run () { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { this .getBean(beanName); } } else { this .getBean(beanName); } } } for (String beanName : beanNames) { Object singletonInstance = this .getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null ) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run () { smartSingleton.afterSingletonsInstantiated(); return null ; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
##完成刷新过程,发布应用事件
Spring 很早就提供了 Lifecycle 接口,实现了该接口的 bean 可以感知到容器的启动和关闭状态,对应着接口的 start 和 stop 方法,而 start 方法的回调则位于这个时候发生:
1 2 3 4 5 6 7 8 9 10 11 12 13 protected void finishRefresh () { this .initLifecycleProcessor(); this .getLifecycleProcessor().onRefresh(); this .publishEvent(new ContextRefreshedEvent(this )); LiveBeansView.registerApplicationContext(this ); }
Lifecycle 对应方法的执行需要依赖于 LifecycleProcessor,我们可以自定义 LifecycleProcessor,否则容器会创建一个默认的 DefaultLifecycleProcessor,然后基于定义的 LifecycleProcessor 来调用满足条件 bean 的 start 方法。在完成了这一操作之后,容器的初始化过程基本上完成,这个时候容器可以将容器刷新完毕事件通知到对应的监听器。
来源 https://my.oschina.net/wangzhenchao/blog/918627