在Spring
启动的过程中, 会自动调用一些方法, 我们通过这些方法可以做一些特殊的操作. Spring
中提供了几个常用的Hook
类, 我们只需要实现这些类并覆盖其方法, 并注入到Spring
中, Spring
就会在恰当的时机调用我们定义的这些类. 下面就介绍几个常用的接口.
从名字上看, 它是BeanFactory
的后处理类, 我们先了解下BeanFactory
.
BeanFactory
的地位相当高, 它是各种Bean
的工厂, 提供了一系列的getBean
方法. 常用的ApplicationContext
就继承了它.
BeanFactoryPostProcessor
就是BeanFactory
的后处理类, 我们可以在BeanFactory
初始化之后做一些操作. 它提供了个postProcessBeanFactory()
方法, 这个方法被调用的时候, 所有的Bean
已经被创建, 但是还没有被初始化.
也就是说, 通过它我们可以在初始化任何Bean
之前, 做各种操作, 甚至读取并修改BeanDefinition
(bean定义的元数据).
这个接口继承了BeanFactoryPostProcessor
. 从名字上来看, 这个接口是BeanDefinitionRegistry
的后处理器, 我们先介绍下BeanDefinitionRegistry
.
BeanDefinitionRegistry
是用来注册BeanDefinition
的. BeanDefinition
就是Bean
的配置元数据或Bean
的描述信息, 比如Bean
的属性值, 构造方法的参数值等. 上面的BeanFactory
的BeanDefinition
也是由它注册的.
BeanDefinitionRegistryPostProcessor
是BeanFactoryPostProcessor
的扩展, 允许在BeanFactoryPostProcessor
被调用之前对BeanDefinition
做一些操作, 尤其是它可以注册BeanFactoryPostProcessor
的BeanDefinition
. 它提供了一个方法postProcessBeanDefinitionRegistry()
, 这个方法被调用的时候, 所有的BeanDefinition
已经被加载了, 但是所有的Bean
还没被创建.
注意:
Bean
生成都有个顺序: 定义 --> 创建 --> 初始化
.BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法在Bean
被定义
但还没被创建
的时候执行.BeanFactoryPostProcessor
的postProcessBeanFactory
方法在Bean
被创建
但还没被初始化
的时候执行从名字上来看, 这个接口是Bean
的后处理器, 通过它我们可以在Bean
初始化前后做一些操作. 它提供了两个方法:
postProcessBeforeInitialization
: 在Bean
初始化之 前 做一些操作postProcessAfterInitialization
: 在Bean
初始化之 后 做一些操作注意这两个方法都有两个参数: bean
和beanName
, 并需要返回一个对象. 所有的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
这个接口有一个方法:afterPropertiesSet
, 该方法在所有的属性都被赋值后调用. 属性被赋值是在初始化的时候做的, 与BeanPostProcessor
结合来看, afterPropertiesSet
方法将在postProcessBeforeInitialization
和postProcessAfterInitialization
之间被调用.
Spring
提供了很多Aware
接口, 比如BeanFactoryAware
、 ApplicationContextAware
、ResourceLoaderAware
、 ServletContextAware
等等. 这些接口一般都有个setXXX
来设置对应的组件. 如果我们的Bean
实现了这些Aware的时候
就可以获取对应的资源.
这跟Servlet
中的监听器一样, 采用了观察者模式. 监听器往往都是监听某些事件源, 下面是配合ApplicationContextAware
一起使用的例子.
我们定义一个事件, 在实现了ApplicationContextAware
的Bean
中触发事件, 在实现了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());
}
}
}