Spring BeanFactoryPostProcess 后置处理器
在Spring 中有两大后置处理器,BeanFactoryPostProcessor, BeanPostProcessor, 从Spring源码中我们知道,在初始ApplicationContext的时候就添加了一个BeanFactoryPostProcessor到容器了,那就是【ConfigurationClassPostProcessor】,这个PostProcessor可以说是整个Spring启动的核心,所有关于包扫描,配置文件加载,signleton实例化的工作都是由它作为引导实现的
图中我们能发现由几个重要的BeanFactoryPostProcessor
- CustomEditorConfigurer
- CustomAutoWireConfigurer
- CustomScopeConfigurer
- PropertyOverrideConfigurer
- PropertySourcesPlaceholderConfigurer
- ConfigurationClassPostProcessor
**CustomEditorConfigurer:**在容器中做数据转换使用,举个例子,我们自定义了一个后置处理器,用于做时间转换,将String类型的日期转换为Date类型
@Component
public class MyCustomPropertyEditorRegistrar extends CustomEditorConfigurer {
PropertyEditorRegistrar propertyEditorRegistrar = new PropertyEditorRegistrar() {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new PropertyEditorSupport(){
@Override
public String getAsText() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
Date date = (Date) getValue();
return simpleDateFormat.format(date);
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
Date date = null;
try{
date = simpleDateFormat.parse(text);
}catch (Exception e){
e.printStackTrace();
}
setValue(date);
}
});
}
};
/**
* PropertyEditorRegistrar 是一个自定义属性编辑器注入接口,通过这个接口可以将我们自定的
* PropertyEditor注入到spring,者需要我们自己实现
* 这里提供一个setter方法是使用策略模式
* 也是使用不同的实现,我们可以得到不同的效果,也就是使用不同的策略,得到不同的反向
* @param propertyEditorRegistrar
*/
public void setPropertyEditorRegistrar(PropertyEditorRegistrar propertyEditorRegistrar) {
this.propertyEditorRegistrar = propertyEditorRegistrar;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
super.setPropertyEditorRegistrars(new PropertyEditorRegistrar[]{propertyEditorRegistrar});
super.postProcessBeanFactory(beanFactory);
}
}
//
@Value("1992/12/12")
private Date date;
CustomAutoWireConfigurer:这是一个关于自定义自动装配的配置,我们知道可以使用@Autowire 进行属性装配,我们知道 @Autowire 首先会通过类型查找对应的属性,然后通过名称,如果找不到或者存在多个可选bean,就会抛出异常;当出现多个候选项时,我们可以通过**@Primary** 提供一个主要候选项,但是如果同时也存在多个 @Primary,那么这种方法也于事无补了,这个时候我们可以通过 @Resource 指定一个名称,或者 @Autowire 和@Quailifier结合使用
除了这几种方法,其实我们还可以使用自定的注解完成这项工作,而非使用 @Qualifier。CustomAutowireConfigurer就是用来完成这项工作的,看如下样例:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CustomQualifiter {
String value() default "";
}
//自定义一个CustomAutowireConfigurer
@Component
public class MyCustomAutowireConfigurer extends CustomAutowireConfigurer {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
super.setOrder(Ordered.LOWEST_PRECEDENCE);
//添加CoustomQuailifier到容器中
super.setCustomQualifierTypes(Collections.singleton(CustomQualifiter.class));
super.postProcessBeanFactory(beanFactory);
}
}
//QualifierAnnotationAutowireCandidateResolver构造方法
@SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() {
this.qualifierTypes.add(Qualifier.class);
try {
this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Qualifier",
QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
//其实内部正在做解析工作的是QualifierAnnotationAutowireCandidateResolver,而它也默认提供@Qualifier注解的支持
CustomScopeConfigurer:
关于Spring bean scope 官网描述:我们知道scope可以选择【singleton/ prototype/ request/ session/ websocket/ application】但是如果我们想自定义一个线程级别的scope命名为“theadScope”该怎么办了
Spring 为我们听过一个BeanFactoryPostProcessor, 那就是CustomScopConfigurer,我们可以可以通过这个类实现自定义Scope
@Component
public class MyCustomScopeConfigurer extends CustomScopeConfigurer {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, Object> map = new HashMap<>();
map.put("threadScope", new SimpleThreadScope());
super.setScopes(map);
super.postProcessBeanFactory(beanFactory);
}
}
@Component
@Scope("threadScope")
public class B {
@Autowired
// @CustomQualifiter("AOne")
@Qualifier("AOne")
private A a;
public void testQuailifter() {
System.out.println("xxxxx" + a);
}
}
Thread t1 = new Thread(()->{
System.out.println("thead1--first time : --> " + annotationConfigApplicationContext.getBean(B.class));
System.out.println("thead1--second time : --> " + annotationConfigApplicationContext.getBean(B.class));
});
Thread t2 = new Thread(()->{
System.out.println("thead2 -- first time : --> " + annotationConfigApplicationContext.getBean(B.class));
});
t1.start();
t2.start();
t1.join();
t2.join();
//输出结果
thead2 -- first time : --> com.mjlf.spring.addBeantoContext.inter.B@5cfbb49
thead1--first time : --> com.mjlf.spring.addBeantoContext.inter.B@332a1d5c
thead1--second time : --> com.mjlf.spring.addBeantoContext.inter.B@332a1d5c
PropertyOverrideConfigurer 与 PropertySourcesPlaceholderConfigurer
这两个都是有关于属性操作的,@Value对应的属性放到BeanDefinition中
@Component
public class MyPropertyOverriedConfigure extends PropertyOverrideConfigurer {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
super.setLocation(new ClassPathResource("propertyOverried.properties", MyPropertyOverriedConfigure.class.getClassLoader()));
super.postProcessBeanFactory(beanFactory);
}
}
@Component("over")
public class OverriedPropery {
@Value("${name}")
private String name;
@Value("${age}")
private String age;
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public void test(){
System.out.println("over Name : " + name);
}
}
//test code
OverriedPropery overriedPropery = (OverriedPropery)annotationConfigApplicationContext.getBean("over");
overriedPropery.test();
//propertyOverried.properties
over.name=whf
over.age=12
问题:这项BeanFactoryPostProcessors到底是什么时候执行的?
根据逻辑,这项标记@Compont或者@Bean注解的后置处理器需要执行正在的逻辑,那么就必须要在BeanDefinition被加载完成后才能实现,但是我们知道ConfigurationClassPostProcessor的postProcessBeanFactory就是处理包扫描,beanDefinition转换的呀,那不混乱了么?
其实不然,像最开始说的ConfigurationClassPostProcessor是在ApplicationContext实例化的时候就添加到容器中,所以它是一个特例,容器首先开始由它的postProcessBeanFactory方法开始执行,然后解析Configuration类,从而将所有的BeanDefinition都扫描出来,然后再找出这其中所有是BeanFactoryPostProcessor的BeanDefinition,最后调用这项BeanFactoryPostProcessor的postProcessBeanFactory()方法,当这项方法都执行完成后,spring才会做验证,然后再实例化其他单例非懒加载bean,最后才是执行BeanPostProcessor