写点什么

Spring 系列之 IOC 容器实例化过程六

作者:王威07325
  • 2023-05-29
    上海
  • 本文字数:5594 字

    阅读完需:约 18 分钟

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 的资源加载器覆盖。它没有任何其他特定的依赖关系。

发布于: 刚刚阅读数: 6
用户头像

王威07325

关注

还未添加个人签名 2021-12-29 加入

还未添加个人简介

评论

发布
暂无评论
Spring系列之IOC容器实例化过程六_spring ioc_王威07325_InfoQ写作社区