8.1 两种后处理器
Spring
框架提供了很好的扩展性,除了可以与各种第三方框架良好整合外,其IoC
容器也允许开发者进行扩展,这种扩展甚至无须实现BeanFactory
或ApplicationContext
接口,而是允许通过两个后处理器对loC
容器进行扩展。 Spring
提供了两种常用的后处理器。
Bean
后处理器:这种后处理器会对容器中的Bean
进行后处理,对Bean
进行额外加强。
- 容器后处理器:这种后处理器对
IoC
容器进行后处理,用于增强容器功能。
下面将介绍这两种常用的后处理器,以及两种后处理器
的相关知识。
8.1.1 Bean后处理器
Bean
后处理器是一种特殊的Bean
,这种特殊的Bean
并不对外提供服务,它甚至无须id
属性,它主要负责对容器中的其他Bean
执行后处理
,例如为容器中的目标Bean
生成代理等,这种Bean
被称为Bean
后处理器.
Bean
后处理器会在Bean
实例创建成功之后,对Bean
实例进行进一步的增强处理。
Bean
后处理器必须实现BeanPostProcessor
接口, BeanPostProcessor
接口包含如下两个方法。
BeanPostProcessor 接口方法 |
描述 |
Object postProcessBeforelnitialization(Object bean, String name) throws Beans Exception |
在目标Bean 初始化之前,对容器中的Bean 实例进行增强处理。该方法的第一个参数是系统即将进行后处理的Bean 实例,第二个参数是该Bean 的配置id 。 |
Object postProcessAfterInitialization(Object bean,String name) throws Beans Exception |
在目标Bean 初始化之后,对容器中的Bean 实例进行增强处理。该方法的第一个参数是系统即将进行后处理的Bean 实例,第二个参数是该Bean 的配置id . |
实现该接口的Bean
后处理器必须实现这两个方法。
Bean
后处理器是对loC
容器一种极好的扩展,Bean
后处理器可以对容器中的Bean
进行后处理,而到底要对Bean
进行怎样的后处理则完全取决于开发者。 Spring
容器负责把各Bean
创建出来,而开发者提供的Bean
后处理器可以依次对每个Bean
进行某种修改、増强,从而可以对容器中的Bean
集中増加某种功能.
程序示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\BeanPostProcessor └─src\ ├─beans.xml ├─lee\ │ └─BeanTest.java └─org\ └─crazyit\ └─app\ ├─service\ │ ├─Axe.java │ ├─impl\ │ │ ├─Chinese.java │ │ └─SteelAxe.java │ └─Person.java └─util\ └─MyBeanPostProcessor.java
|
下面将定义一个简单的Bean
后处理器,该Bean
后处理器将对容器中的其他Bean
进行后处理。Bean
后处理器的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package org.crazyit.app.util;
import java.lang.reflect.Field; import org.crazyit.app.service.impl.Chinese; import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("Bean后处理器在初始化 之前 对" + beanName + "进行增强处理..."); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("Bean后处理器在初始化 之后 对" + beanName + "进行增强处理..."); if (bean instanceof Chinese) { try { Class<?> clazz = bean.getClass(); Field f = clazz.getDeclaredField("name"); f.setAccessible(true); f.set(bean, "FKJAVA:" + f.get(bean)); } catch (Exception ex) { ex.printStackTrace(); } } return bean; } }
|
上面程序中实现了对Bean
进行增强处理的逻辑,当Spring
容器实例化Bean
实例之后,就会依次调用Bean
后处理器的两个方法对Bean
实例进行增强处理。
下面是Chinese Bean
类的代码,该类实现了InitializingBean
接口(并实现了该接口包含的afterPropertiesSet()
方法),还额外提供了一个初始化方法(init()
方法),这两个方法都用于定制该Bean
实例的生命周期行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package org.crazyit.app.service.impl;
import org.crazyit.app.service.Axe; import org.crazyit.app.service.Person; import org.springframework.beans.factory.InitializingBean;
public class Chinese implements Person, InitializingBean { private Axe axe; private String name; public Chinese() { System.out.println("Spring实例化主调bean:Chinese实例..."); } public void setAxe(Axe axe) { this.axe = axe; } public void setName(String name) { System.out.println("Spring执行setName()方法注入依赖关系..."); this.name = name; } public void useAxe() { System.out.println(name + axe.chop()); } public void init() { System.out.println("正在执行初始化方法 init..."); } public void afterPropertiesSet() throws Exception { System.out.println("正在执行初始化方法 afterPropertiesSet..."); } }
|
在配置文件中配置Bean
后处理器和配置普通Bean
完全一样,但有一点需要指出,通常程序无须主动获取Bean
后处理器,因此配置文件可以无须为Bean
后处理器指定id
属性。下面的配置文件因为需要手动注册Bean
后处理器,所以配置文件依然为Bean
后处理器指定了id
属性。配置文件如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe" /> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese" init-method="init" p:axe-ref="steelAxe" p:name="依赖注入的值" /> <bean id="bp" class="org.crazyit.app.util.MyBeanPostProcessor" /> </beans>
|
上面文件的粗体字代码配置了一个Bean
后处理器,这个Bean
后处理器将会对容器中的所有Bean
实例进行后处理。为了更好地观察到Bean
后处理器的后处理方法的执行时机,程序还为chinese bean
指定了如下两个初始化方法。
init-method
指定初始化方法
- 实现
InitializingBean
接口,提供了afterPropertiesSet
初始化方法。
该示例的主程序如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package lee;
import org.crazyit.app.service.Person; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanTest { public static void main(String[] args) throws Exception { @SuppressWarnings("resource") ApplicationContext ctx = new ClassPathXmlApplicationContext( "beans.xml"); Person p = (Person) ctx.getBean("chinese"); p.useAxe(); } }
|
ApplicationContext作为Spring容器时会自动注册Bean后处理器
从上面代码可以看出,该程序根本看不到任何关于Bean
后处理器的代码,这是因为:如果使用ApplicationContext
作为Spring
容器, Spring
容器会自动检测容器中的所有Bean
,如果发现某个Bean
类实现了BeanPostProcessor
接口, ApplicationContext
会自动将其注册为Bean
后处理器。
运行上面的程序,可以看到如下运行结果:
1 2 3 4 5 6 7 8 9 10
| Spring实例化依赖bean:SteelAxe实例... Bean后处理器在初始化 之前 对steelAxe进行增强处理... Bean后处理器在初始化 之后 对steelAxe进行增强处理... Spring实例化主调bean:Chinese实例... Spring执行setName()方法注入依赖关系... Bean后处理器在初始化 之前 对chinese进行增强处理... 正在执行初始化方法 afterPropertiesSet... 正在执行初始化方法 init... Bean后处理器在初始化 之后 对chinese进行增强处理... FKJAVA:依赖注入的值钢斧砍柴真快
|
从上面的执行结果可以看出,虽然配置文件中指定chinese
这个Bean
的name
为”依赖注入的值”,但该chinese
这个Bean
的name
成员变量的值被修改了,增加了"FKJAVA:"
前缀——这就是Bean
后处理器的作用。
容器中一旦注册了Bean
后处理器,Bean
后处理器就会自动启动,在容器中每个Bean
创建时自动工作,加入Bean
后处理器需要完成的工作。从上面的执行过程可以看出,Bean
后处理器两个方法的回调时机如图8.1所示。
实现BeanPostProcessor
接口的Bean
后处理器可对Bean
进行任何操作,包括完全忽略这个回调。BeanPostprocessor
通常用来检查标记接口,或者做如将Bean
包装成一个Proxy
的事情, Spring
的很多工具类就是通过Bean
后处理器完成的。
BeanFactory作为Spring容器时必须手动注册Bean
如果使用BeanFactory
作为Spring
容器,则必须手动注册Bean
后处理器,程序必须获取Bean
后处理器实例,然后手动注册。在这种需求下,程序可能需要在配置文件中为Bean
处理器指定id
属性,这样才能让Spring
容器先获取Bean
后处理器,然后注册它。因此,如果使用BeanFactory
作为Spring
容器,则需要将主程序改为如下形式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package lee;
import org.crazyit.app.service.Person; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;
public class BeanTest { public static void main(String[] args) throws Exception { Resource isr = new ClassPathResource("beans.xml"); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(isr); BeanPostProcessor bp = (BeanPostProcessor) beanFactory.getBean("bp"); beanFactory.addBeanPostProcessor(bp); Person p = (Person) beanFactory.getBean("chinese"); p.useAxe(); } }
|
正如从上面粗体字代码所看到的,程序中bp
就是Bean
后处理器配置id
,一旦程序获取了Bean
后处理器,即可调用BeanFactory
的addBeanPostProcessor()
方法来注册该Bean
后处理器。
原文链接: 8.1 两种后处理器 8.1.1 Bean后处理器