refresh 中的 registerBeanPostProcessors initMessageSource 方法
永远不要放弃你心中的热爱,哪怕那很难!!
一个星期过去了,新的篇章又开始了,最近一直在思考一个问题,“业务重要,还是技术重要?”,这个问题也是很多技术开发的朋友也思考过,将自己的一些想法说一下:这个应该因人而异,对于个人来说,我更偏向于技术,但是对于社会发展来说,一般都是业务,或者说需求推动着技术的发展。
好了,闲谈也扯完了,开始正题!
registerBeanPostProcessors
先贴上代码:
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh();
// Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory);
try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. initMessageSource();
// Initialize event multicaster for this context. initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. onRefresh();
// Check for listener beans and register them. registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. finishRefresh(); }
catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); }
// Destroy already created singletons to avoid dangling resources. destroyBeans();
// Reset 'active' flag. cancelRefresh(ex);
// Propagate exception to caller. throw ex; }
finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
复制代码
/** * Instantiate and invoke all registered BeanPostProcessor beans, * respecting explicit order if given. * <p>Must be called before any instantiation of application beans. */ protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); }
复制代码
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, and the rest. 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); } }
// First, register the BeanPostProcessors that implement PriorityOrdered. sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered. 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(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors. 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);
// Finally, re-register all internal BeanPostProcessors. sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners, // moving it to the end of the processor chain (for picking up proxies etc). beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }
复制代码
此部分实质上是在 BeanDefinition 中寻找 BeanPostProcessor,之后调用 BeanFactory.addBeanPostProcessor 方法保存在一个 List 中,需要注意的是在添加的时候有一个优先级的概念,优先级高的在后面。
initMessageSource
国际化也称作 i18n,其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数。
代码:
/** * Initialize the MessageSource. * Use parent's if none defined in this context. */ protected void initMessageSource() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); // Make MessageSource aware of parent MessageSource. if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() == null) { // Only set parent context as parent MessageSource if no parent MessageSource // registered already. hms.setParentMessageSource(getInternalParentMessageSource()); } } if (logger.isDebugEnabled()) { logger.debug("Using MessageSource [" + this.messageSource + "]"); } } else { // Use empty MessageSource to be able to accept getMessage calls. DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); if (logger.isDebugEnabled()) { logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME + "': using default [" + this.messageSource + "]"); } } }
复制代码
AbstractApplicationContext 的 initMessageSource()方法就是在 BeanFactory 中查找 MessageSource 的 bean,如果配置了此 bean,那么调用 getBean 方法完成其初始化并将其保存在 AbstractApplicationContext 内部 messageSource 成员变量中,用以处理 ApplicationContext 的 getMessage 调用,因为从继承体系上来看,ApplicationContext 是 MessageSource 的子类,此处是委托模式的体现。如果没有配置此 bean,那么初始化一个 DelegatingMessageSource 对象,此类是一个空实现,同样用以处理 getMessage 调用请求。
MessageSource 此接口用以支持 Spring 国际化。继承体系如下
spring 配置国际化配置文件
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <!-- 国际化信息所在的文件名 --> <property name="basename" value="messages/message" /> <!-- 如果在国际化资源文件中找不到对应代码的信息,就用这个代码作为名称 --> <property name="useCodeAsDefaultMessage" value="true" /> </bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
复制代码
ResourceBundleMessageSource:
messagesource 实现,使用指定的 basename 访问资源包。这个类依赖于底层 JDK 的 ResourceBundle 实现,并结合了由 MessageFormat 提供的 JDK 标准消息解析。 这个 MessageSource 缓存访问的 ResourceBundle 实例和为每个消息生成的 MessageFormats。它还实现了在不使用 MessageFormat 的情况下呈现无参数消息,正如 AbstractMessageSource 基类所支持的那样。这个 MessageSource 提供的缓存要比 java.util.ResourceBundle 类的内置缓存快得多。 这些基名遵循 ResourceBundle 的约定:本质上是一个完全限定的类路径位置。如果它不包含包限定符(比如 org.mypackage),它将从类路径根解析。请注意,JDK 的标准 ResourceBundle 将点作为包分隔符:这意味着“test。“主题”实际上等同于“测试/主题”。
ReloadableResourceBundleMessageSource:
特定于 Spring 的 org.springframework.context. messagesource 实现,它使用指定的 basename 访问资源包,参与 Spring 的 org.springframework.context。加载 ApplicationContext 的资源。 与基于 jdk 的 ResourceBundleMessageSource 相比,这个类使用 Properties 实例作为消息的自定义数据结构,通过 Spring Resource 句柄中的 PropertiesPersister 策略加载它们。这种策略不仅能够根据时间戳的变化重新加载文件,而且还能够使用特定的字符编码加载属性文件。它还将检测 XML 属性文件。 注意,设置为“basenames”属性的 basenames 的处理方式与 ResourceBundleMessageSource 的“basenames”属性略有不同。它遵循 ResourceBundle 的基本规则,即不指定文件扩展名或语言代码,但是可以引用任何 Spring 资源位置(而不是被限制为类路径资源)。有了"classpath:"前缀,资源仍然可以从类路径加载,但是除了"-1"(永远缓存)之外的" cachesecseconds "值在这种情况下可能不可靠。 对于一个典型的 web 应用程序,消息文件可以放在 web - inf 中:例如,一个“web - inf /messages”的 basename 会找到一个“web - inf /messages”。属性”、“web - inf / messages_en。属性等安排以及“WEB-INF/messages.xml”,“WEB-INF/messages_en.xml”等。注意,由于顺序查找,前一个资源包中的消息定义将覆盖后一个资源包中的消息定义。 这个 MessageSource 可以很容易地在 org.springframework.context.ApplicationContext 之外使用:它将使用 DefaultResourceLoader 作为默认值,如果在一个 context 中运行,它只会被 ApplicationContext 的资源加载器覆盖。它没有任何其他特定的依赖关系。
评论