Spring的后处理器
Spring的后处理器
源码
Spring 主要的两种后处理器
BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池SingletonObjects之前执行;
BeanFactoryPostProcessor 向 BeanDefinitionMap 中进行注册、修改操作
xml 文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.kaiming.processor.MyBeanFactoryPostProcessor"></bean><bean id="userDao" class="com.kaiming.dao.impl.UserDaoImpl"></bean><!-- userService中注入userDao--><bean id="userService" class="com.kaiming.service.impl.UserServiceImpl"></bean>
</beans>
注册
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("beanDefinitionMap填充完成后回调该方法"); // 注册RootBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.kaiming.dao.impl.PersonDaoImpl");DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;defaultListableBeanFactory.registerBeanDefinition("personDao", beanDefinition);}
}
test 获取 personDao
public class ApplicationContextTest {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("beans.xml");Object personDao = beanFactory.getBean("personDao");System.out.println(personDao);}
}
beanDefinitionMap填充完成后回调该方法
com.kaiming.dao.impl.PersonDaoImpl@1e67a849
修改
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("beanDefinitionMap填充完成后回调该方法");BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");beanDefinition.setBeanClassName("com.kaiming.dao.impl.UserDaoImpl");}
}
test
public class ApplicationContextTest {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("beans.xml"); Object userService = beanFactory.getBean("userService");System.out.println(userService);}
}
beanDefinitionMap填充完成后回调该方法
com.kaiming.dao.impl.UserDaoImpl@448ff1a8
BeanFactoryPostProcessor 的子接口
源码
主要用于
BeanDefinition注册
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}
一般注册 BeanDefinition 使用这个接口,不用针对 ConfigurableListableBeanFactory 进行强转
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {RootBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.kaiming.dao.impl.PersonDaoImpl");beanDefinitionRegistry.registerBeanDefinition("personDao", beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}
}
xml 文件配置 MyBeanDefinitionRegistryPostProcessor
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.kaiming.processor.MyBeanFactoryPostProcessor"></bean><bean class="com.kaiming.processor.MyBeanDefinitionRegistryPostProcessor"></bean><bean id="userDao" class="com.kaiming.dao.impl.UserDaoImpl"></bean><!-- userService中注入userDao--><bean id="userService" class="com.kaiming.service.impl.UserServiceImpl"></bean></beans>
test
public class ApplicationContextTest {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("beans.xml");Object personDao = beanFactory.getBean("personDao");System.out.println(personDao);}
}
实现了 去实现 BeanFactoryPostProcessor 接口达到同样的效果
com.kaiming.dao.impl.PersonDaoImpl@41ee392b
关于实现了
BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor执行顺序
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("MyBeanFactoryPostProcessor的postProcessBeanFactory方法");}
}
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {System.out.println("MyBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法");RootBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.kaiming.dao.impl.PersonDaoImpl");beanDefinitionRegistry.registerBeanDefinition("personDao", beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {System.out.println("MyBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法");}
}
MyBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
MyBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
MyBeanFactoryPostProcessor的postProcessBeanFactory方法
BeanPostProcessor
Bean 被实例化后,到最终缓存到 SingletonObjects 单例池前,中间会经过 Bean 的初始化过程,例如:属性的填充,初始化 init 的执行等,其中有一个对外进行扩展的点 BeanPostProcessor ,称之为 Bean 后处理器。与 Bean 工厂后处理器相似,也是一个接口,实现了该接口并被容器管理的 BeanPostProcessor ,会在流程节点上被 Spring 自动调用。
// BeanPostProcessor 源码
public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
创建一个 MyBeanPostProcessor 类实现 BeanPostProcessor 接口
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization");return bean;}
}
xml 文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.kaiming.processor.MyBeanPostProcessor"></bean><bean id="userDao" class="com.kaiming.dao.impl.UserDaoImpl"></bean></beans>
test
public class ApplicationContextTest {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("beans.xml");Object userDao = beanFactory.getBean("userDao");}
}
postProcessBeforeInitialization
postProcessAfterInitialization
com.kaiming.dao.impl.UserDaoImpl@3c0a50da
我们为 UserDaoImpl 添加无参构造器,init 方法,afterPropertiesSet 方法(实现 InitializingBean 接口),观察执行顺序;
public class UserDaoImpl implements UserDao, InitializingBean {private String username;public void setName(String userName) {this.username = userName;}public UserDaoImpl() {System.out.println("userDao实例化");}public void init() {System.out.println("init初始化方法执行");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("属性设置之后执行");}
}
xml 文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.kaiming.processor.MyBeanPostProcessor"></bean><bean id="userDao" class="com.kaiming.dao.impl.UserDaoImpl" init-method="init"></bean></beans>
test 测试
public class ApplicationContextTest {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("beans.xml");Object userDao = beanFactory.getBean("userDao");System.out.println(userDao);}
}
userDao实例化
postProcessBeforeInitialization
属性设置之后执行
init初始化方法执行
postProcessAfterInitialization
com.kaiming.dao.impl.UserDaoImpl@797badd3
案例
对 Bean 方法进行执行时间日志增强
要求:
Bean的方法执行前控制台打印当前时间;Bean的方法执行后控制台打印当前时间;
分析:
- 对方法进行增强主要采用代理和包装设计模式;
- 由于
Bean方法不确定,所以使用动态代理在运行期间执行增强操作; - 在
Bean实例创建完成后,进入单例池前,使用Proxy代替真正的目标Bean;
TimeLogBeanPostProcessor 实现 BeanPostProcessor
public class TimeLogBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 使用动态代理对目标bean进行增强,返回Proxy对象,进而存储到SingletonObjects中Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(proxy, method, args) -> {// 输出开始时间System.out.println("方法: " + method.getName() + "-开始时间: " + LocalDateTime.now());// 执行目标方法Object results = method.invoke(bean, args);// 输出结束时间System.out.println("方法: " + method.getName() + "-结束时间: " + LocalDateTime.now());return results;});return beanProxy;}
}
xml 文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.kaiming.processor.TimeLogBeanPostProcessor"></bean><bean id="userDao" class="com.kaiming.dao.impl.UserDaoImpl"></bean></beans>
userDao 接口 抽象方法
public interface UserDao { void show();
}
userDaoImpl 实现 userDao 接口
public class UserDaoImpl implements UserDao {@Overridepublic void show() {System.out.println("show()...");}
}
test 测试
public class ApplicationContextTest {public static void main(String[] args) {BeanFactory beanFactory = new ClassPathXmlApplicationContext("beans.xml");UserDao userDao = (UserDao) beanFactory.getBean("userDao");userDao.show();}
}
方法: show-开始时间: 2025-10-25T12:00:57.305161400
show()...
方法: show-结束时间: 2025-10-25T12:00:57.306161200
