5. 一些注意点

5. 一些注意点

一些关键字

BeanPostProcessor

如上接口声明所示,BeanPostProcessor接口有两个回调方法。当一个BeanPostProcessor的实现类注册到Spring IOC容器后,对于该Spring IOC容器所创建的每个bean实例在初始化方法(如afterPropertiesSet和任意已声明的init方法)调用前,将会调用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean实例初始化方法调用完成后,则会调用BeanPostProcessor中的postProcessAfterInitialization方法,整个调用顺序可以简单示意如下

–> Spring IOC容器实例化Bean –> 调用BeanPostProcessor的postProcessBeforeInitialization方法 –> 调用bean实例的初始化方法 –> 调用BeanPostProcessor的postProcessAfterInitialization方法

BeanPostProcessor是容器绑定的,即BeanPostProcessor只能对跟它属于同一个bean容器中的bean进行回调,即BeanPostProcessor不能对属于它父容器或子容器中的bean进行回调。

可以看到,Spring容器通过BeanPostProcessor给了我们一个机会对Spring管理的bean进行再加工。比如:我们可以修改bean的属性,可以给bean生成一个动态代理实例等等。一些Spring AOP的底层处理也是通过实现BeanPostProcessor来执行代理包装逻辑的。

具体可以参考博客:


BeanFactoryPostProcessor

BeanFactoryPostProcessor的核心作用是在bean在实例化前更改bean的配置信息。 这里我们可以从类的注释中清晰的发现:


/**
 * Allows for custom modification of an application context's bean definitions,
 * adapting the bean property values of the context's underlying bean factory.
 *
 * <p>Application contexts can auto-detect BeanFactoryPostProcessor beans in
 * their bean definitions and apply them before any other beans get created.
 *
 * <p>Useful for custom config files targeted at system administrators that
 * override bean properties configured in the application context.
 *
 * <p>See PropertyResourceConfigurer and its concrete implementations
 * for out-of-the-box solutions that address such configuration needs.
 *
 * <p>A BeanFactoryPostProcessor may interact with and modify bean
 * definitions, but never bean instances. Doing so may cause premature bean
 * instantiation, violating the container and causing unintended side-effects.
 * If bean instance interaction is required, consider implementing
 * {@link BeanPostProcessor} instead.
 */
@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

有几点比较关键:

  • Application contexts can auto-detect BeanFactoryPostProcessor beans in their bean definitions and apply them before any other beans get created.
  • A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. If bean instance interaction is required, consider implementing BeanPostProcessor instead.
  • All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for overriding or adding properties even to eager-initializing beans.

但是有一些副作用,可以参考博客:


容器初始化和销毁Bean

  • 第一种通过@PostConstruct和@PreDestroy方法实现初始化和销毁bean之前进行的操作
  • 第二种是通过在xml中定义init-method和destory-method方法
  • 第三种是通过bean实现InitializingBean和DisposableBean接口

他们是三种不同的方式去配置初始化Bean的方式。 也就是通过annotation,xml,config的方式。

  • 使用 @Bean(initMethod = "init")方式来定义回调。 这种方式是xml的一种annotation的过渡配置。

@Required

Spring依赖检查bean配置文件用于确定的特定类型(基本,集合或对象)的所有属性被设置。在大多数情况下,你只需要确保特定属性已经设置但不是所有属性。 对于这种情况,你需要@Required 注解。

简单地套用@Required注解不会强制执行该属性的检查,还需要注册一个RequiredAnnotationBeanPostProcessor以了解在bean配置文件@Required注解。 RequiredAnnotationBeanPostProcessor可以用两种方式来启用。

  • 使用 <context:annotation-config/>隐式地注册RequiredAnnotationBeanPostProcessor, 使@Required注解生效
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd"
             default-lazy-init="true">
    
          <context:annotation-config/>
          ...
      </beans>
  • 直接声明RequiredAnnotationBeanPostProcessor。
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd"
             default-lazy-init="true">
    
             <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
          ...
      </beans>

Spring框架中都用到了哪些设计模式?

代理模式:在AOP和remoting中被用的比较多。 单例模式:在spring配置文件中定义的bean默认为单例模式。 模板方法模式:用来解决代码重复的问题。 前端控制器模式:Spring提供了DispatcherServlet来对请求进行分发。 依赖注入模式:贯穿于BeanFactory / ApplicationContext接口的核心理念。 工厂模式:BeanFactory用来创建对象的实例。