BeanFactoryPostProcessor
和BeanPostProcessor
,可以使我们的程序逻辑和Spring容器紧密合作,无缝插入到用户bean的生命周期中,发挥更强大的作用。相关知识
1.首先需要定义一套XML Schema来描述组件所提供的功能。schema中就需要描述我们期望用户提供的namespace以及namespace之间的排序等元数据。
2.除了XML Schema,我们还需要创建一个自定义的NamespaceHandler来负责解析用户在XML中的配置。
NamespaceHandlerSupport
,然后在init
方法中注册处理我们自定义节点的BeanDefinitionParserconfig
节点信息,记录用户的配置信息,为后面和Spring整合做好铺垫。3.注册Spring handler和Spring schema,让Spring解析xml配置文件的过程中识别我们的自定义节点,并且转交到我们的NamespaceHandler
处理。
从Spring 3.0开始,一种新的基于Java的配置方式出现了。
通过这种方式,我们在开发Spring项目的过程中再也不需要去配置繁琐的xml文件了,只需要在Configuration类中配置就可以了,大大的简化了Spring的使用。
另外,这也是Spring Boot默认的配置方式,所以建议也支持这一特性。
支持Java配置扩展的关键点就是@Import
注解,Spring 3.0提供了这个注解用来支持在Configuration类中引入其它的配置类,包括Configuration类, ImportSelector和ImportBeanDefinitionRegistrar的实现类。
我们可以通过这个注解来引入自定义的扩展Bean。
和基于XML配置类似的,我们需要提供给用户一个注解来配置需要注入到Spring Property Sources的namespaces和order。
ImportBeanDefinitionRegistrar
接口定义了registerBeanDefinitions
方法,从而允许我们向Spring注册必要的Bean。
Spring容器最常用的两个扩展点:BeanFactoryPostProcessor
和BeanPostProcessor
。
BeanFactoryPostProcessor
提供了一个方法:postProcessBeanFactory
。
这个方法会被Spring在容器初始化过程中调用,调用时机是所有bean的定义信息都已经初始化好,但是这些bean还没有实例化。
实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息,
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
System.out.println("属性值============" + bd.getPropertyValues().toString());
MutablePropertyValues pv = bd.getPropertyValues();
if (pv.contains("remark")) {
pv.addPropertyValue("remark", "把备注信息修改一下");
}
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
}
}
实际应用:
BeanPostProcessor
提供了两个方法:postProcessBeforeInitialization
和postProcessAfterInitialization
,主要针对bean初始化提供扩展。
postProcessBeforeInitialization
会在每一个bean实例化之后、初始化(如afterPropertiesSet方法)之前被调用。postProcessAfterInitialization
则在每一个bean初始化之后被调用。我们常用的@Autowired
注解就是通过postProcessBeforeInitialization
实现的(AutowiredAnnotationBeanPostProcessor)。
BeanFactoryPostProcessor在bean实例化之前执行,之后实例化bean(调用构造函数,并调用set方法注入属性值),然后在调用两个初始化方法前后,执行了BeanPostProcessor。初始化方法的执行顺序是,先执行afterPropertiesSet,再执行init-method。如下
public class MyJavaBean implements InitializingBean {
private String desc;
private String remark;
public MyJavaBean() {
System.out.println("MyJavaBean的构造函数被执行啦");
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
System.out.println("调用setDesc方法");
this.desc = desc;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
System.out.println("调用setRemark方法");
this.remark = remark;
}
public void afterPropertiesSet() throws Exception {
System.out.println("调用afterPropertiesSet方法");
this.desc = "在初始化方法中修改之后的描述信息";
}
public void initMethod() {
System.out.println("调用initMethod方法");
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[描述:").append(desc);
builder.append(", 备注:").append(remark).append("]");
return builder.toString();
}
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
MutablePropertyValues pv = bd.getPropertyValues();
if (pv.contains("remark")) {
pv.addPropertyValue("remark", "在BeanFactoryPostProcessor中修改之后的备忘信息");
}
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor,对象" + beanName + "调用初始化方法之前的数据: " + bean.toString());
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor,对象" + beanName + "调用初始化方法之后的数据:" + bean.toString());
return bean;
}
}
BeanPostProcessor的执行,取决于配置文件中bean的定义,如果定义的bean是singleton并且不是抽象类,也不延迟初始化,则BeanPostProcessor是在第11步中执行;而对于prototype的bean,BeanPostProcessor是在程序getBean的时候执行的。在第6步中,调用registerBeanPostProcessors方法,注册所有实现BeanPostProcessor接口的bean
参考
https://juejin.im/post/5ba45a94f265da0aa94a0d71
https://nobodyiam.com/2017/02/26/several-ways-to-extend-spring/
https://blog.csdn.net/qq_38182963/article/details/78795058
https://blog.csdn.net/caihaijiang/article/details/35552859