文章目录
前言
本篇按照bean的声明周期顺序罗列出了其中所执行的回调方式,也是按照这个顺序进行排版的,有一些并不能作为我们开发所需要的就省略了,个别是因为同一个接口就整合到了一起,但并不影响。
BeanDefinitionRegistryPostProcessor
这个后置处理器是在bean工厂初始化准备后执行的,一般是进行内置的bean解析,用在了应用初始化器上,也就是SPI,由tomcat启动spring容器时使用,也有在监听器配置里,添加默认的后置处理器,也是spring所必须的后置处理器,所以我们一般是用不到的,可以作为了解,如果是说需要进行框架开发,可以深入了解。
BeanFactoryPostProcessor
bean工厂的后置处理,在上一个处理器之后执行,我们使用的@Component,@Import,@Configuration
等创建的bean就是在这里被扫描解析并注册的。
它的参数是bean工厂,所以它的权限范围较大,因为在这一层spring容器还未实例化bean,所以这里我们可以修改beanDefinition
,甚至自定义自己的beanDefinition
,又或者只是做一写简单操作,比如,根据校验我们自定义的规则校验benaDefinition
是否合法,或者是删除benaDefinition
。
定义一个 普通的类:
public class CustomTest {
private String name = "3";
private String tt;
private CustomConfig config;
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public void init() {
System.out.println("初始化方法");
}
public CustomConfig getConfig() {
return config;
}
public void setConfig(CustomConfig config) {
this.config = config;
}
@Override
public String toString() {
return "CustomTest{" +
"name='" + name + '\'' +
", config=" + config +
'}';
}
}
定义3个bean
@Component
public class CustomConfig {
}
@Component
public class CustomConfig2 {
}
@Component
public class CustomConfig3 {
}
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition customBean = new GenericBeanDefinition();
customBean.setBeanClassName(CustomTest.class.getName());
// 设置初始化方法
customBean.setInitMethodName("init");
// 设置自定义bean的class
customBean.setBeanClass(CustomTest.class);
// 设置自动注入
customBean.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("customTestBean", customBean);
// 提前实例化
Object customTestBean = beanFactory.getBean("customTestBean");
System.out.println("自定义bean:" + customTestBean);
// 判断某个bean是否存在
if (beanFactory.containsBean("customConfig")) {
System.out.println("包含bean[customConfig]");
}
// 移除某个bean
((BeanDefinitionRegistry) beanFactory).removeBeanDefinition("customConfig2");
// 提前实例一个bean
CustomConfig3 bean = beanFactory.getBean(CustomConfig3.class);
System.out.println("实例化:" + bean);
}
}
实现后置处理器,做几个操作:
- 自定义一个bean定义
- 提前实例化自定义的bean
- 判断
InstantiationAwareBeanPostProcessor
接口定义如下:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
}
postProcessBeforeInstantiation
如果我们实现这个接口并返回了一个bean的话,可以打断后面的执行动作,什么意思呢?
在spring初始化阶段,它有一个bean的生命周期,周期中bean实例化是其中一环,之后还有依赖注入,aware回调,实例化回调等的操作,如果我们这里返回了bean,那么那些操作将不会执行,这些操作包含aware回调,postConstruct,initMethod
定义一个测试bean,这里实现了InitializingBean
接口
@Component
public class CustomConfig4 implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("customConfig4 afterPropertiesSet");
}
}
实现实例化前的处理器方法,直接new一个对象
@Component
public class CustomInstantPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (Objects.equals(beanName, "customConfig4")) {
return new CustomConfig4();
}
return null;
}
}
需要注意的是: 这个操作执行后,在spring中的后续的一些回调方法不会执行,如InitializingBean.afterPropertiesSet
和aware
接口等,但是spring aop依然是生效的。
postProcessAfterInstantiation
当我们修改后,也就是实现了这个接口,默认返回true,返回true就表示,不在进行属性填充,也就是依赖注入不会发生。
postProcessProperties
这个处理器用做bean的属性填充,也就是我们@Autowired,@Resource
注解注入时,属性填充执行的地方;
这里能做的可能只有校验了,比如你在应用初始化时对应用监控时可能会用到。
@Component
public class CustomBeanPropertiesPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return pvs;
}
}
需要注意的是: 这里虽然参数有bean对象,但是这个bean对象只是一个副本,并不是容器上下文里使用的,所以直接修改是不会生效的。
Supplier
在实例化bean时,Spring还提供了一个Supplier
方法,用于实例创建的,如果没有的话,就会走spring默认的实例化逻辑,我们先看个例子
@Component
public class CustomSupplierPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition customBean = new GenericBeanDefinition();
customBean.setBeanClassName(CustomTest2.class.getName());
// 设置初始化方法
customBean.setInitMethodName("init");
// 设置自定义bean的class
customBean.setBeanClass(CustomTest2.class);
// 设置自动注入
customBean.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// supplier
customBean.setInstanceSupplier(()-> {
CustomTest2 temp = new CustomTest2();
temp.setConfig(beanFactory.getBean(CustomConfig.class));
temp.setName("0");
return temp;
});
((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("customTestBean2", customBean);
}
}
这里的实现就是依赖于beanFactory
后置处理器实现的,因为它需要操作beanDefinition
,也或者是实现接口BeanDefinitionRegistryPostProcessor
,这并不影响。
打印一下:
@Component
public class TestRunner implements ApplicationRunner {
@Autowired
private CustomConfig4 customConfig4;
@Autowired
private CustomTest2 customTest2;
@Override
public void run(ApplicationArguments args) throws Exception {
customConfig4.t();
System.out.println("customTest2:" + customTest2);
}
}
BeanPostProcessor
初始化bean的操作接口,只能修改bean里的内容。
@Component
public class CustomBeaPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return 我们修改的bean对象;
}
}
@Lookup
当我们打上注解@Component
时,被标注的类会生成单例bean,那么这个bean中的属性在非人为干扰的情况下就不会在变化,如下:
@Data
@Component
public class CustomTest3 {
@Autowired
public CustomTest4 customTest4;
public void print() {
System.out.println(customTest4());
}
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CustomTest4 {
}
当调用customTest3.print()
时,打印出的hashCode是不会变的。
那么如果说,有一个场景,需要customTest3
每次获取customTest4
都是一个新的bean对象,要怎么实现?
你可能会想到实现接口ApplicationContextAware
,如下:
@Data
@Component
public class CustomTest3 implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContext = applicationContext;
}
public void print() {
CustomTest4 bean = applicationContext.getBean(CustomTest4.class);
System.out.println(bean);
}
}
或者自己手动创建一个实例,这个过程稍微复杂了点,但是在spring中,只需要一个注解@Lookup
就能解决:
@Data
@Component
public class CustomTest3 {
@Lookup
public CustomTest4 customTest4(){return null;}
public void print() {
System.out.println(customTest4());
}
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CustomTest4 {
}
另外它也可以这样写:
@Component
public interface CustomTest33 {
@Lookup
CustomTest4 customTest4();
}
@Component
public abstract class CustomTest34 {
@Lookup
abstract CustomTest4 customTest4();
}
它的原理是由接口生成了代理类,所需可以不需要实现类。
需要注意的是:
- 它只能打在方法上
- 标注的方法可以是接口,但不能是
private
- 方法需是无参的
MergedBeanDefinitionPostProcessor
postProcessMergedBeanDefinition
提供我们修改beanDefinition
的功能,如下:
@Component
public class CustomMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (!Objects.equals(beanName, "customConfig5")) {
return;
}
beanDefinition.setInitMethodName("t");
}
}
@Component
public class CustomConfig5 {
public void t() {
System.out.println("customConfig5 init method.");
}
}
这里需要注意的是: 在这步之前,bean已经实例化了,所以在这里我们修改Bean class
是无效的。
而resetBeanDefinition
这个方法是重置元数据信息,我们已经提到过了,bean已经实例化了,所以只能重置bean内的元数据信息。
Aware接口
该接口定义为spring组件获取接口,比如:
BeanClassLoaderAware
设置beanClass类加载器BeanFactoryAware
设置beanFactoryApplicationContextAware
设置容器上下文
还有很多的接口,我们常用的可能是ApplicationContextAware
这一类,不过如果你有对这个spring初始化流程有过理解的话,你可能会发现一个问题,我常见到会有这样的用法:
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}
public <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
}
不管对不对,我们假设有一个类:
@Component
public class CustomConfig6 implements InitializingBean {
private CustomConfig config;
@Override
public void afterPropertiesSet() throws Exception {
config = SpringUtil.getBean(CustomConfig.class);
}
}
问:应用是否正常?
如果不正常,该怎么修改?
答案在本篇已经给出了
@PostConstruct/@PreDestroy
在xml配置bean的方式中
<bean id="xx" class="xxxxx" init-method="" destroy-method="">
在注解方式中,@PostConstruct
就是init-method
,@PreDestroy
是destroy-method
注意: 它是在bean初始化完后,InitializingBean
之前执行的;并且他们可以存在多个,执行顺序是:
@PostConstruct -> 父类内从先到后,子类内从先到后
@PreDestory -> 子类内从先到后,父类内从先到后
@Component
public class CustomConfig7 {
@PostConstruct
public void t() {
System.out.println("customConfig7 init");
}
@PostConstruct
public void t2() {
System.out.println("customConfig7 init2");
}
@PreDestroy
public void d() {
System.out.println("customConfig7 destroy");
}
@PreDestroy
public void d2() {
System.out.println("customConfig7 destroy2");
}
}
InitializingBean
这个接口也是常用的一个,一般是做数据缓存回调,或者其他的一些需要预先执行的操作。
@Component
public class CustomConfig4 implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("customConfig4 afterPropertiesSet");
}
}
注意: 它在初始化完bean后就会进行回调,这时的bean是完整的bean
FactoryBean
自定义bean的创建的工厂模式,执行时机在单例bean创建完成后,即当CustomFactoryBean
作为完整bean生成完后,进行FactoryBean
的判断,如果时属于,那么才执行getObject()
方法,创建bean
。
public class CustomTest5 {
private String name;
public CustomTest5(String name) {
this.name = name;
}
}
@Component
public class CustomFactoryBean implements FactoryBean<CustomTest5> {
@Override
public CustomTest5 getObject() throws Exception {
return new CustomTest5("0");
}
@Override
public Class<?> getObjectType() {
return CustomTest5.class;
}
}
这个接口和Supplier
是一样的功能,只是实现不一样。
SmartInitializingSingleton
注意: 这个接口是在所有bean实例并初始化完后执行的,我不知有什么场景使用。
ApplicationRunner
spring应用启动完后执行,表示应用已经是正常可以立即使用的状态,用于需要程序启动完成后才能执行的操作,比如通知其他系统,或程序。
@Component
public class TestRunner2 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
}
}
CommandLineRunner
spring应用启动完后执行,表示应用已经是正常可以立即使用的状态,用于需要程序启动完成后才能执行的操作,比如通知其他系统,或程序。
@Component
public class TestRunner3 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
}
}