Spring源码解析7——容器功能扩展

1、ApplicationContext.interface接口介绍

  在前面博客中,我们一直BeanFactory.interface接口的实现类XmlBeanFactory.java,Spring中可以通过这个class实现加载配置文件的功能。但是,Spring中还提供了另一个接口ApplicationContext.interface用于扩展BeanFactory.interface中现有的功能。简单一点说:ApplicationContext.interface包含了BeanFactory.interface中所有的功能,通常建议比BeanFactory.interface优先,除非在一些限制的场合,比如字节对内存有很大影响时(Applet)。绝大多数场景下,企业应用的是ApplicationContext.interface。
clipboard

  • 使用BeanFactory.interface方式加载XML
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-bean.xml"));
  • 使用ApplicationContext.interface方式加载XML
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-event.xml");

clipboard
  设置路径是必不可少的步骤, ClassPathXmlApplicationContext.java 中可以将配置文件路径以数组的方式传人, ClassPathXmlApplicationContext.java 可以对数组进行解析并进行加载。而对于解析及功能实现都在refresh() 中实现。

2、扩展功能

AbstractApplicationContext.java

@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.
      //初始化BeanFactory,并进行Xml文件读取
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      //对BeanFactory进行各种功能的填充
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         //子类覆盖方法做额外的处理
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //激活各种BeanFactory处理器
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean的时候
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //国际化处理(为上下文初始化Message源)
         initMessageSource();

         // Initialize event multicaster for this context.
         //初始化应用消息广播器,并放入"applicationEventMulticaster"bean中
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //留给子类来初始化其他的Bean
         onRefresh();

         // Check for listener beans and register them.
         //在所有注册的Bean中查找Listener Bean,注册到消息广播器中
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //初始化剩下的单实例(非惰性)
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         //完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
         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();
      }
   }
}

以上逻辑概要:
①、初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。
在某种情况下项目的使用需要读取某些系统变量, 而这个变量的设置很可能会影响着系统的正确性,那么ClassPathXmlApplicationContext 为我们提供的这个准备函数就显得非常必要,它可以在Spring 启动的时候提前对必需的变量进行存在性验证。
②、初始化BeanFactory , 并进行XML 文件读取。
之前有提到ClassPathXmlApplicationContext 包含着BeanFactory 所提供的一切特征,那么在这一步骤中将会复用BeanFactory 中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext 实际上
就已经包含了BeanFactory 所提供的功能,也就是可以进行bean 的提取等基础操作了。
③、对BeanFactory 进行各种功能填充。
④、子类覆盖方法做额外的处理。
Spring开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能,这种开放式的设计在Spring 中随处可见,例如在本例中就提供了一个空的函数实现postProcessBeanFactory()来方便程序员在业务上做进一步扩展。
⑤、激活各种BeanFactory 处理器。
⑥、注册拦截bean 创建的bean 处理器,这里只是注册, 真正的调用是在getBean() 时候。
⑦、国际化处理。
⑧、初始化应用消息广播器,并放入ApplicationEventMulticaster.java类型的实例中。
⑨、留给子类来初始化其他bean。
⑩、在所有注册的Bean中查找Listener Bean,注册到消息广播器中。
⑪、初始化剩下的单实例。
⑫、完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent 通知别人

2.1、环境准备

clipboard
上面代码中,蓝色框中的两句代码才是最为关键的,但initPropertySources() 是空的,没有任何逻辑,而getEnvironment().validateRequiredProperties() 也因为没有需要验证的属性而没有做任何处理。但是,当我们重写initPropertySources() 方法,并在方法中进行个性化的属性处理及设置后,假如:,工程在运行过程中用到的某个设置(例如VAR )是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程可能不会工作。这一要求可能会有各种各样的解决办法,我们这里说一种解决方案,对源码进行扩展:
clipboard
相应的,我们加载配置文件时,将原有的 ClassPathXmlApplicationContext.java替换为我们自定义的 MyClassPathXmlApplicationContext.java。

3、加载BeanFactory

  之前有说过, ApplicationContext是对BeanFactory 的功能上的扩展,不但包含了BeanFactory 的全部功能更在其基础上添加了大量的扩展应用,那么AbstractApplicaitionContext.java:obtainFreshBeanFactory() 正是实现BeanFactory 的地方,也就是经过了这个函数后ApplicationContext 就已经拥有了BeanFactory 的全部功能。
clipboard
clipboard
clipboard

详细分析上面的步骤:
①、创建DefaultListableBeanFactory.java类型的实例。
clipboard
②、指定序列化ID。
③、定制BeanFactory。
④、加载DefaultListableBeanFactory.java类型实例beanFactory。
⑤、使用全局变量记录DefaultListableBeanFactory.java类型实例。

3.1、定制DefaultListableBeanFactory.java类型实例
  • 这里已经开始了对BeanFactory 的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许循环依赖。
    clipboard

  • 对于允许覆盖和允许依赖的设置,这里只是判断了是否为空,如果不为空需要进行设置,但是并没有看到在哪里进行设置的。一般情况下,我们会使用子类覆盖customizeBeanFactory()函数
    clipboard

3.2、加载BeanDefinition.java类型实例

  在3.1中提到了将ClassPathXmlApplicationContext 与XmlBeanFactory 创建的对比,在实现配置文件的加载功能中除了我们在第一步中已经初始化的DefaultListableBeanFactory 外,还需要XmlBeanDefinitionReader 来读取XML。那么,我们这里就对XmlBeanDefinitionReader.java类型的实例进行初始化。
clipboard
clipboard
clipboard

  使用XmlBeanDefinitionReader.java 的loadBeanDefinitions() 方法进行配置文件的加载机注册相信大家已经不陌生,这完全就是开始BeanFactory 的套路。因为在XmlBeanDefinitionReader.java 中已经将之前初始化的DefaultListableBeanFactory.java类型的实例 注册进去了,所以XmlBeanDefinitionReader.java类型实例beanDefinitionReader 所读取的BeanDefinitionHolder 都会注册到DefaultListableBeanFactory.java类型实例beanFactory 中,也就是经过此步骤,类型DefaultListableBeanFactory.java 的实例beanFactory 已经包含了所有解析好的配置。

4、功能扩展

AbstractApplicationContext.java

/**
 * Configure the factory's standard context characteristics,
 * such as the context's ClassLoader and post-processors.
 * @param beanFactory the BeanFactory to configure
 */
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   //设置beanFactory的classLoader为当前context的classLoader
   beanFactory.setBeanClassLoader(getClassLoader());
   //设置beanFactory的表达式语言处理器,Spring3.0以后增加了表达式语言的支持
   //默认可以使用${bean.xxx}形式来调用相关的属性
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   //为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
   //添加BeanPostProcessor,增加对一些内置类,比如EnvironmentAware、MessageSourceAware 的信息注入。
   // Configure the bean factory with context callbacks.
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   //经过ApplicationContextAwareProcessor后,bean已经不是普通的bean了
   // Spring在做bean的依赖注入时需要:设置了几个忽略自动装配的接口
   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 interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   //设置了几个自动装配的特殊规则
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   //注册早期的后处理器:将内部bean检测为ApplicationListeners
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   //增加对AspectJ的支持
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   //添加默认的系统环境bean
   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());
   }
}

详细分析上面的步骤:
①、增加对SpEL语言的支持。
②、增加对属性编辑器的支持。
③、增加对一些内置类,比如EnvironmentAware、MessageSourceAware 的信息注入。
④、设直了依赖功能可忽略的接口。
⑤、注册一些固定依赖的属性。
⑥、增加AspectJ的支持(会在AOP中进行详细的讲解)。
⑦、将相关环境变量及属性注册以单例模式注册。

4.1、SpEL语言的支持

  Spring 表达式语言全称为Spring Expression Language ,缩写为SpEL,SpEL语言能在运行时构建复杂表达式、存取对象图属性、对象方法调用等,并且能与Spring 功能完美整合,比如能用来配置bean 定义。SpEL 是单独模块,只依赖于core模块, 不依赖于其他模块,可以单独使用。
  SpEL 使用 #{ ...} 作为定界符,所有在大框号中的字符都将被认为是SpEL ,使用格式如下:
clipboard

在源码中,通过代码:AbstractBeanFactory.java中定义了SpEL解析器

/** Resolution strategy for expressions in bean definition values */
@Nullable
private BeanExpressionResolver beanExpressionResolver;

AbstractApplicationContext.java::prepareBeanFactory()中注册了SpEL解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
注册了语言解析器,就可以对SpEL进行解析了。

clipboard
在注册解析器之后,spring需要(2个步骤):
①、Spring在bean进行初始化的时候会先解析SpEL语言。
clipboard
clipboard

②、然后填充到spring中的BeanWrapper.java类型的实例中。
clipboard
AbstractAutowireCapableBeanFactory.java

/**
 * Apply the given property values, resolving any runtime references
 * to other beans in this bean factory. Must use deep copy, so we
 * don't permanently modify this property.
 * @param beanName the bean name passed for better exception information
 * @param mbd the merged bean definition
 * @param bw the BeanWrapper wrapping the target object
 * @param pvs the new property values
 */
//属性填充
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
   if (pvs.isEmpty()) {
      return;
   }

   if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
      ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
   }

   MutablePropertyValues mpvs = null;
   List<PropertyValue> original;

   if (pvs instanceof MutablePropertyValues) {
      mpvs = (MutablePropertyValues) pvs;
      //如果mpvs中的值已经被转换为对应的类型,那么可以直接设置到beanWapper中
      if (mpvs.isConverted()) {
         // Shortcut: use the pre-converted values as-is.
         try {
            bw.setPropertyValues(mpvs);
            return;
         }
         catch (BeansException ex) {
            throw new BeanCreationException(
                  mbd.getResourceDescription(), beanName, "Error setting property values", ex);
         }
      }
      original = mpvs.getPropertyValueList();
   }
   else {
      //如果pvs并不是使用MutablePropertyValues封装的类型,那么直接使用原始的属性获取方法。
      original = Arrays.asList(pvs.getPropertyValues());
   }

   TypeConverter converter = getCustomTypeConverter();
   if (converter == null) {
      converter = bw;
   }
   //获取对应的解析器
   BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

   // Create a deep copy, resolving any references for values.
   List<PropertyValue> deepCopy = new ArrayList<>(original.size());
   boolean resolveNecessary = false;
   //遍历属性,将属性转换为对应类的对应属性的类型
   for (PropertyValue pv : original) {
      if (pv.isConverted()) {
         deepCopy.add(pv);
      }
      else {
         String propertyName = pv.getName();
         Object originalValue = pv.getValue();
         Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
         Object convertedValue = resolvedValue;
         boolean convertible = bw.isWritableProperty(propertyName) &&
               !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
         if (convertible) {
            convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
         }
         // Possibly store converted value in merged bean definition,
         // in order to avoid re-conversion for every created bean instance.
         if (resolvedValue == originalValue) {
            if (convertible) {
               pv.setConvertedValue(convertedValue);
            }
            deepCopy.add(pv);
         }
         else if (convertible && originalValue instanceof TypedStringValue &&
               !((TypedStringValue) originalValue).isDynamic() &&
               !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
            pv.setConvertedValue(convertedValue);
            deepCopy.add(pv);
         }
         else {
            resolveNecessary = true;
            deepCopy.add(new PropertyValue(pv, convertedValue));
         }
      }
   }
   if (mpvs != null && !resolveNecessary) {
      mpvs.setConverted();
   }

   // Set our (possibly massaged) deep copy.
   try {
      bw.setPropertyValues(new MutablePropertyValues(deepCopy));
   }
   catch (BeansException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
   }
}
4.2、增加属性注册编辑器
4.3、添加了ApplicationContextAawareProcessor处理器

  通过AbstractApplicationContext.java::prepareBeanFactory()主线追踪到应用程序处理器,其主要的目的就是注册一个BeanPostProcessor.interface类型的实例:

//添加BeanPostProcessor,增加对一些内置类,比如EnvironmentAware、MessageSourceAware 的信息注入。
   // Configure the bean factory with context callbacks.
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

  而对于 ApplicationContextAwareProcessor.java类型实例的应用,可以对比XmlBeanFacoty.java在创建Bean实例的时候,进行的应用程序处理器。

4.3.1、XmlBeanFacoty.java中应用程序处理器

  之前说过内容中,在XmlBeanFacoty.java创建Bean实例的时候,也就是spring激活baen的init-method前后,会调用BeanPostProcessor.interface中定义的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法。
clipboard

4.3.2、ClassPathXmlApplicationContext.java中应用程序处理器

ApplicationContextAwareProcessor.java

@Override
@Nullable
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((PrivilegedAction<Object>) () -> {
         invokeAwareInterfaces(bean);
         return null;
      }, acc);
   }
   else {
      invokeAwareInterfaces(bean);
   }

   return bean;
}

//实现这些xxxAware接口的bean在被初始化之后,可以取得一些对应的资源
//经过该方法后,调用的Aware类已经不是普通的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);
      }
   }
}
4.4、设置忽略依赖

  当Spring 将ApplicationContextAwareProcessor 注册后,那么在4.3.2中invokeAwarelnterfaces() 函数中间接调用的Aware 类已经不是普通的bean 了,如ResourceLoaderAware 、ApplicationEventPublisherAware等,那么当然需要在Spring 做bean 的依赖注入的时候忽略它们。而ignoreDependencyInterface()的作用正是在此。
clipboard
clipboard

5、BeanFactory的后处理

  BeanFactory作为Spring中的容器功能的基础,用于存放所有已经加载的bean,为了保证程序的高可扩展性,Spring对BeanFactory做了大量的扩展,比如 BeanFactoryPostProcessor.interface 等都是在这里实现的。

5.1、BeanFactoryPostProcessor.interface和BeanPostProcessor.interface

  BeanFactoryPostProcessor.interface和BeanPostProcessor.interface接口类似,可以对bean的定义(配置元数据)进行处理。也就是说,SpringIOC容器允许BeanFactoryPostProcessor在BeanFactory容器实际实例化任何其他bean之前读取配置元数据,并有可能修改它。还能通过设置“order”属性来控制BeanFactoryPostProcessor的执行次序(仅当实现了BeanFactoryPostProcessorinterface接口的class同时实现Order接口时,才可以设置此属性)
  如果想改变实际的bean实例(例如从配置元数据创建的对象),那么最好实现BeanPostProcessor.interface接口。同样的,BeanFactoryPostProcessor的作用范围是容器级别的,它只和所使用的容器有关。如果在容器中定义一个BeanFactoryPostProcessor,它仅对容器中的bean做后置处理,BeanFactoryPostProcessor不会对定义在另一个容器中的bean进行后置处理,即使两个容器是在同一层次上。在Spring中对于BeanFactoryPostProcessor的典型应用就是PropertyPlaceholderConfigurer。

5.1.1、PropertyPlaceholderConfigurer

  有时候在阅读Spring的Bean描述文件时,也许会遇到类似如下的一些配置:

<bean id="message" class="distConfig HelloMessage">
    <property name="mes">
        <value>${bean.message}</value>
    </property>
</bean>

  其中竟然出现了变量引用:${ bean.message} 。这就是Spring 的分散配置,可以在另外的配置文件中为bean.message 指定值。如在bean.property 配置如下定义:

bean.message=Hi,can you find me?

  当访问名为message 的bean 时, mes 属性就会被置为字符串“ Hi,can you find me?”,但Spring 框架是怎么知道存在这样的配置文件呢? 这就要靠PropertyPlaceholderConfigurer 这个类的bean:

<bean id="mesHandler" class="org.Springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>config/bean.properties</value>
        </list>
    </property>
</bean>

  PropertyPlaceholderConfigurer.class 间接继承了BeanFactoryPostProcessor.interface,这是一个很特别的接口,当Spring 加载任何实现了这个接口的bean 的配置时, 都会在bean 工厂载入所有bean 的配置之后执行postProcessBeanFactory() 方法。在PropertyResourceConfigurer.class 中实现了postProcessBeanFactory() 方法,在方法中先后调用了mergeProperties() 、convertProperties() 、processProperties() 这3 个方法, 分别得到配置, 将得到的配置转换为合适的类型, 最后将配置内容告知BeanFactory 。
clipboard

5.1.2、使用自定义的class实现BeanFactoryPostProcessor.interface
  • 配置文件BeanFactory.xml
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="bfpp" class="xxx.xxx.beanfactory.ObscenityRemovingBeanFactoryPostProcessor">
      <property name="obscenties">
         <set>
            <value>bollocks</value>
            <value>winky</value>
            <value>bum</value>
            <value>Microsoft</value>
         </set>
      </property>
   </bean>

   <bean id="simpleBean" class="xxx.xxx.beanfactory.SimplePostProcessor">
      <property name="connectionString" value="bollocks"/>
      <property name="password" value="imaginecup"/>
      <property name="username" value="Microsoft"/>
   </bean>
   
</beans>
  • ObscenityRemovingBeanFactoryPostProcessor.java
package xxx.xxx.beanfactory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.util.StringValueResolver;
import java.util.HashSet;
import java.util.Set;

public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   private Set<String> obscenties;

   public ObscenityRemovingBeanFactoryPostProcessor() {
      this.obscenties = new HashSet<String>();
   }

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      String[] beanNames = beanFactory.getBeanDefinitionNames();
      for (String beanName : beanNames) {
         BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
         StringValueResolver valueResolver = new StringValueResolver() {
            @Override
            public String resolveStringValue(String strVal) {
               if (isObscene(strVal)) return "****";
               return strVal;
            }
         };

         BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
         visitor.visitBeanDefinition(bd);
      }
   }

   private boolean isObscene(Object value) {
      String potentiaObscenity = value.toString().toUpperCase();
      return this.obscenties.contains(potentiaObscenity);
   }

   public void setObscenties(Set<String> obscenties){
      this.obscenties.clear();
      for (String obscenity : obscenties) {
         this.obscenties.add(obscenity.toUpperCase());
      }
   }
}
  • 执行类
package xxx.xxx.beanfactory;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class testMain {
   public static void main(String[] args) {
      ConfigurableListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring-beanfactory.xml"));
      BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)bf.getBean("bfpp");
      bfpp.postProcessBeanFactory(bf);
      System.out.println(bf.getBean("simpleBean"));

   }
}

运行结果如下:
image

5.1.3、激活

posted @ 2025-12-27 11:03  Carey_ccl  阅读(2)  评论(0)    收藏  举报