Spring BeanFactoryPostProcess 后置处理器

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值