Spring后处理器

前言

        有一篇非常不错的文章:《Spring的BeanFactoryPostProcessor和BeanPostProcessor》,详细的讲解了Spring的两种处理器的用法和Spring源码实现,推荐大家阅读

目录

前言

一. 概念

1.  BeanPostProcessor

2.  BeanFactoryPostProcessor  容器后处理器

3. Spring已有的BeanFactoryPostProcessor  

1.  PropertyPlaceholderConfigurer  

2.  PropertyOverrideConfigurer

3.  CustomAutowireConfigurer

4.  AutowiredAnnotationBeanPostProcessor 

5.  CustomScopeConfigurer  



一. 概念

    Spring后处理器,是Spring定义的功能接口Interface,包括两种:

  • BeanPostProcessor   对容器中的Bean进行后处理,对Bean进行额外的加强
  • BeanFactoryPostProcessor  Spring容器本身进行后处理,增强容器的功能

        后处理器接口同ApplicationContextAware、InitializingBean等接口不同,它们并非直接加在需要处理的bean类上,而是重新编写一个后处理器类,implement后处理接口,实现其中的方法,然后再将此类在Spring容器中注册为Bean。容器启动或者有bean加载时,会自动调用实现了后处理器接口的方法,将bean作为参数传入,从而实现相应的功能。

        对初级开发者而言,用BeanPostProcessor比较多一些,认识Spring的后处理器也是从此开始的。就功能而言,个人感觉BeanFactoryPostProcessor的功能更加强大些,而且Spring框架本身编写了很多的实现了BeanFactoryPostProcessor接口的功能类,在spring容器启动时进行很多初始化操作。

1.  BeanPostProcessor

        此接口包括两个必须实现的方法:

    //before
    Object postProcessBeforeInitialization(Object bean, String name);
    //after
    Object postProcessAfterInitialization(Object bean, String name);

    其中:Object bean:即将记性后处理的bean实例;String name 该bean的配置;返回值是bean的Object。

        beforeafter是相对bean生命周期过程中,InitializingBean和<bean init="">来说的。spring会在Bean加载过程中,处理上面两个初始化步骤的前后时间点上,分别调用对应的方法,完成必要的初始化操作。有关bean生命周期的顺序,可以参考文档《Spring Bean的生命周期

每个bean加载时,spring都会调用所有实现了BeanPostProcessor接口的后处理类方法,因此:

  1. 方法内一般都是先判断bean的类型,筛选出所要处理的bean之后再进行后续操作
  2. BeanPostProcessor后处理器有处理一批bean的潜力,不是只能对单个bean生效

2.  BeanFactoryPostProcessor  容器后处理器

        容器后处理器负责处理容器本身,接口方法有一个

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

    对容器进行处理,没有返回值

Spring本身提供了几个实现了此接口的、非常有用的容器后处理器,下面可以看看

3. Spring已有的BeanFactoryPostProcessor  

  • PropertyPlaceholderConfigurer 属性占位符配置器
  • PropertyOverrideConfigurer 重写占位符配置器
  • CustomAutowireConfigurer 自定义自动装配的配置器
  • AutowiredAnnotationBeanPostProcessor 自动装配的配置器
  • CustomScopeConfigurer 自定义作用域的配置器

1.  PropertyPlaceholderConfigurer  

        PropertyPlaceholderConfigurer可以将上下文(配置文件)中的属性值放在另一个单独的标准java Properties文件中去。在XML文件中用${key}替换指定的properties文件中的值。这样的话,只需要对properties文件进行修改,而不用对xml配置文件进行修改。

<!-- 要使用@Value("${key}")方式配置property,则需要配置此BeanFactory后处理器 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="location">
       <value>jdbc.properties</value>
   </property>

    <property name="fileEncoding">
        <value>UTF-8</value>
    </property>
</bean>

2.  PropertyOverrideConfigurer

        与PropertyPlaceholderConfigurer类似但不同,PropertyOverrideConfigurer 是修改已有的属性。如果properties文件中有bean属性的内容,那么就用properties文件中的值来代替上下文中的 bean的属性值。

<beans>
    <!-- 使用PropertyOverrideConfigurer修改属性 -->
    <!-- dog.properties配置:aHuang.color=blue,将阿黄的颜色修改为蓝色 -->
    <bean id="propertyConfigure" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations" value="classpath:dog.properties"/>
    </bean>

    <!-- bean狗:阿黄,颜色:黄色 -->
    <bean id="aHuang" class="org.leisu.Dog">
        <property name="name" value="aHuang"></property>
        <property name="color" value="yellow"></property>
    </bean>
</beans>

        可以看到,通过在dog.properties中配置:aHuang.color=blue,来修改bean:aHuang中已经配好的color=“yellow”,达到修改属性的作用

3.  CustomAutowireConfigurer

        要理解CustomAutowireConfigurer的作用,需要先知道@Qualifier的功能。

       @Qualifier相关知识可以阅读我另一篇文章《@Qualifier注解》学习

        @Qualifier可以实现自定义修饰注解的功能,例如:

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("Asian")         //使用@Qualifier自定义修饰注解Asian
public @interface Asian{ ... }

···············

//定义亚洲人
@Asian          //使用我们自定义的修饰注解
@Component
public class AsianMan extends Person {

}

为了避免对@Qualifier注解的任何依赖性,每个自定义注解上都用@Qualifier去修饰,可以在Spring中提供一个CustomAutowireConfigurer的bean定义,并直接注册所有自定义注解类型:

<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
   <property name="customQualifierTypes">
       <set>
           <value>org.leisu.Asian</value>
       </set>
   </property>
</bean>

        现在,自定义修饰符被显式声明了,就不再需要@Qualifier这个元注解符,也可以定义有qualifier特性的自定义注解了。

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
//不再使用@Qualifier自定义修饰注解Asian
public @interface Asian{ ... }

        相关知识也可以学习《注释驱动的 IoC 功能》,很不错的文章

4.  AutowiredAnnotationBeanPostProcessor 

     当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有@Autowired 注释时就找到和其匹配(默认按类型匹配)的 Bean并注入到修饰的变量中。这个用法很常见,上面的案例也用到了@Autowired

  @Qualifier通过配置可以省略,在”3. CustomAutowireConfigurer”中已经有过讨论。而使用AutowiredAnnotationBeanPostProcessor, 也可以通过配置,增加或替换类似@Autowired的注解

//首先创建一个我们的注解
public @interface MyInject {
}


将@MyInject注解放入 AutowiredAnnotationBeanPostProcessor中,生成和@Autowired同样的作用

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
   <!-- 增加自动注入的注解@MyInject -->
   <property name="autowiredAnnotationType" value="org.leisu.MyInject"/>
</bean>

编写controller和service,使用 @MyInject注入service

//定义Controller
@Controller		
public class MyController {

	@MyInject				//使用我们自己定义的注解去注入
	private MyService myService;
	
	@ResponseBody
	@RequestMapping(value="/myInjectTest",method=RequestMethod.GET)
	public String myInjectTest() {
		return myService.service();
	}
}

//定义service
@Service
public class MyService {
	
	public String service() {
		return "this is a inject test";
	}
}

结果:

     

上述方法暂时无法实现,以后再进行补充

5.  CustomScopeConfigurer  

        scope是控制bean作用域的属性,可参考我另一篇文章《Spring Bean作用域》。

        除了在bean上直接设置外,也可以自定义一个作用域scope:

1.实现Scope接口的方法;

2使用后处理器CustomScopeConfigurer注册。

示例如下:

public class MyScope implements Scope {
    private int index;
    private List objects = new LinkedList(); {
        objects.add(new TestBean());
        objects.add(new TestBean());
    }
    public String getConversationId() {
        return null;
    }
    public Object get(String name, ObjectFactory objectFactory) {
        if (index >= objects.size()) {
            index = 0;
        }
        return objects.get(index++);
    }
    public Object remove(String name) {
        throw new UnsupportedOperationException();
    }
    public void registerDestructionCallback(String name, Runnable callback) {
    }
}  
<bean id="myScope" class="MyScope"/>
<bean id="customerScope" class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="myScope">
                <bean class="myScope"/>
            </entry>
        </map>
    </property>
</bean>
<bean id="usesScope" class="org.springframework.beans.TestBean" scope="myScope"/>     

猜你喜欢

转载自blog.csdn.net/u010086122/article/details/81589889