Spring的扩展点



Spring启动的过程中, 会自动调用一些方法, 我们通过这些方法可以做一些特殊的操作. Spring中提供了几个常用的Hook类, 我们只需要实现这些类并覆盖其方法, 并注入到Spring中, Spring就会在恰当的时机调用我们定义的这些类. 下面就介绍几个常用的接口.

BeanFactoryPostProcessor

从名字上看, 它是BeanFactory的后处理类, 我们先了解下BeanFactory.

BeanFactory的地位相当高, 它是各种Bean的工厂, 提供了一系列的getBean方法. 常用的ApplicationContext就继承了它.

BeanFactoryPostProcessor就是BeanFactory的后处理类, 我们可以在BeanFactory初始化之后做一些操作. 它提供了个postProcessBeanFactory()方法, 这个方法被调用的时候, 所有的Bean已经被创建, 但是还没有被初始化. 也就是说, 通过它我们可以在初始化任何Bean之前, 做各种操作, 甚至读取并修改BeanDefinition(bean定义的元数据).

BeanDefinitionRegistryPostProcessor

这个接口继承了BeanFactoryPostProcessor. 从名字上来看, 这个接口是BeanDefinitionRegistry的后处理器, 我们先介绍下BeanDefinitionRegistry.

BeanDefinitionRegistry是用来注册BeanDefinition的. BeanDefinition就是Bean的配置元数据或Bean的描述信息, 比如Bean的属性值, 构造方法的参数值等. 上面的BeanFactoryBeanDefinition也是由它注册的.

BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的扩展, 允许在BeanFactoryPostProcessor被调用之前对BeanDefinition做一些操作, 尤其是它可以注册BeanFactoryPostProcessorBeanDefinition. 它提供了一个方法postProcessBeanDefinitionRegistry(), 这个方法被调用的时候, 所有的BeanDefinition已经被加载了, 但是所有的Bean还没被创建.

注意:

  • 所有的Bean生成都有个顺序: 定义 --> 创建 --> 初始化.
  • BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry方法在Bean定义但还没被创建的时候执行.
  • BeanFactoryPostProcessorpostProcessBeanFactory方法在Bean创建但还没被初始化的时候执行

BeanPostProcessor

从名字上来看, 这个接口是Bean的后处理器, 通过它我们可以在Bean初始化前后做一些操作. 它提供了两个方法:

  • postProcessBeforeInitialization: 在Bean初始化之 做一些操作
  • postProcessAfterInitialization: 在Bean初始化之 做一些操作

注意这两个方法都有两个参数: beanbeanName, 并需要返回一个对象. 所有的Bean在被初始化前后都会调用这两个方法, 我们可以过滤出所关心的Bean对其进行一些操作, 比如把某个Bean替换成代理对象等.

另外, 在Bean中可以通过@PostConstruct注解来指定在被Construct之后紧接着做一些初始化操作, 上面的postProcessAfterInitialization方法是在@PostConstruct之后被调用的.

一些例子

我们通过一些简单例子来熟悉下上面的几个接口:

// 一个普通的 Bean
@Component
public class TestA {
    @PostConstruct
    public void init() {
        System.out.println("TestA PostConstruct");
    }
    @Resource
    private TestB testB;
}
// 另一个普通的 Bean. 没看错, 就是循环依赖.
@Component
public class TestB {
    @PostConstruct
    public void init() {
        System.out.println("TestB PostConstruct");
    }
    @Resource
    private TestA testA;
}
// 后处理器
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    // 这个方法来自 BeanDefinitionRegistryPostProcessor
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("postProcessBeanDefinitionRegistry");
    }
    // 这个方法来自 BeanFactoryPostProcessor
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("postProcessBeanFactory");
    }
}
// Bean后处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TestA || bean instanceof  TestB) {
            System.out.println("beforeInitialization");
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TestA || bean instanceof  TestB) {
            System.out.println("afterInitialization");
        }
        return bean;
    }
}

用法就类似于上面, 那几条数据语句的顺序如下:

postProcessBeanDefinitionRegistry
postProcessBeanFactory
beforeInitialization
TestB PostConstruct
afterInitialization
beforeInitialization
TestA PostConstruct
afterInitialization

InitializingBean

这个接口有一个方法:afterPropertiesSet, 该方法在所有的属性都被赋值后调用. 属性被赋值是在初始化的时候做的, 与BeanPostProcessor结合来看, afterPropertiesSet方法将在postProcessBeforeInitializationpostProcessAfterInitialization之间被调用.

ApplicationContextAware

Spring提供了很多Aware接口, 比如BeanFactoryAwareApplicationContextAwareResourceLoaderAwareServletContextAware等等. 这些接口一般都有个setXXX来设置对应的组件. 如果我们的Bean实现了这些Aware的时候就可以获取对应的资源.

ApplicationListener

这跟Servlet中的监听器一样, 采用了观察者模式. 监听器往往都是监听某些事件源, 下面是配合ApplicationContextAware一起使用的例子.

我们定义一个事件, 在实现了ApplicationContextAwareBean中触发事件, 在实现了ApplicationListener的类中对事件做出反应.

// 自定义事件
public class MyEvent extends ApplicationEvent {
    public MyEvent(Object source) {
        super(source);
    }
}
// 自定义 Bean 实现 ApplicationContextAware 接口
@Component
public class HelloBean implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private String name;
    public void setApplicationContext(ApplicationContext context) {
        this.applicationContext = context;
    }
    // 当调用 setName 时, 触发事件
    public void setName(String name) {
        this.name = name;
        applicationContext.publishEvent(new MyEvent(this));  // 这行代码执行完会立即被监听到
    }
    public String getName() {
        return name;
    }
}
// 自定义监听器, 监听上面的事件
@Component
public class MyApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof MyEvent) {
            System.out.println(((HelloBean)event.getSource()).getName());
        }
    }
}