Spring的BeanFactoryPostProcessor
BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入,是不是很神奇? 本文将通过简单的例子,展现BeanFactoryPostProcessor的扩展能力。
一、bean生命周期简述
Spring Bean生命周期比较复杂,在此简化一下,如下图。
步骤1、 豆子工厂(BeanFactory)从xml文件、java配置或注解配置中读取“各种豆子的生产方法说明(BeanDefinition)”。
步骤2、 这些豆子分为“特殊豆子(实现spring指定的某些接口)”和“普通豆子”, 豆子工厂先生产出这些特殊豆子。
步骤3和4、 特殊豆子调用特定接口(例如BeanFactoryPostProcessor接口),可以对豆子工厂(BeanFactory)进行修改,或添加一些新豆子生产方法(即注册新的BeanDefinition到BeanFactory中)。
步骤5、豆子工厂(BeanFactory)执行getBean方法生产其他的普通裸豆子。(调用类的构造方法,或FactoryBean的getObject方法,以及@Bean注解的方法)
步骤6、设置豆子的依赖关系以及属性值。
步骤7、调用豆子的@PostConstruct指定的方法
步骤8、调用豆子的InitializingBean接口方法
步骤9、调用豆子的initMethod指定的方法。
总结上述过程, 我们可以得到以下执行顺序 : BeanFactoryPostProcessor ---> 普通Bean构造方法 ---> 设置依赖或属性 ---> @PostConstruct ---> InitializingBean ---> initMethod 。
二、BeanFactoryPostProcessor 代码例子
BenzCar类(奔驰汽车类)有成员属性Engine(发动机), Engine是接口,无具体的实现类。本代码例子,通过BeanFactoryPostProcessor ,FactoryBean,动态代理三项技术实现给BenzCar装配上Engine。
项目结构如下:
AppConfig类如下:
com.kaigejava.spring.beanlife.configcom.kaigejava.spring.beanlife.bean.BenzCarcom.kaigejava.spring.beanlife.bean.specialbean.SpecialBeanForEnginecom.kaigejava.spring.beanlife.service.Engineorg.springframework.context.annotation.org.springframework.context.annotation.AppConfig {
SpecialBeanForEngine (){
SpecialBeanForEngine()}
(initMethod=)
BenzCar (Engine engine){
BenzCar car = BenzCar()car.= enginecar }
}
从@Bean benzCar,我们可以看出,car需要一个engine对象。
以下是BenzCar 代码:
package com.kaigejava.spring.beanlife.bean;
import com.kaigejava.spring.beanlife.service.Engine;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
/**
* @author 凯哥Java
* @description
* @company
* @since 2022/11/10 15:03
*/
public class BenzCar implements InitializingBean {
public Engine engine;
public BenzCar(){
System.out.println(" BenzCar 无参构造器....");
if(engine == null){
System.out.println(" engine not setting ~~~~");
}else{
System.out.println(" engine 已经初始化");
}
}
void startCar(){
System.out.println(" BeanzCar start ====");
engine.fire();
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("BenzCar afterPropertiesSet method ... ");
if(engine == null){
System.out.println(" afterPropertiesSet engine not setting ~~~~");
}else{
System.out.println(" afterPropertiesSet engine 已经初始化");
engine.fire();
}
}
@PostConstruct
public void postConstruct(){
System.out.println(" BenzCar postConstruct....");
if(engine == null){
System.out.println(" postConstruct => engine not setting ~~~~");
}else{
System.out.println(" postConstruct => engine 已经初始化");
}
}
}
BenzCar 实现类 InitializingBean 类,重写了afterPorpertiesSet方法。有一个Engine对象成员, 在start方法中调用Engine的fire方法。
Engine接口代码如下:
com.kaigejava.spring.beanlife.serviceEngine {
()}
Engine是一个接口,一般情况下,需要在App类中配置一个Engine的实现类bean才行,否则因为缺少Engine实例,spring启动时会报错。通过FactoryBean和动态代理,可以生成Engine接口的代理对象;结合BeanFactoryPostProcessor 接口,将FactoryBean动态添加到BeanFactory中,即可以给BenzCar配置上Engine接口代理对象。
为此新增一个 SpecialBeanForEngine类, 代码如下:
com.kaigejava.spring.beanlife.bean.specialbeancom.kaigejava.spring.beanlife.factory.EngineFactoryorg.springframework.beans.BeansExceptionorg.springframework.beans.factory.BeanNameAwareorg.springframework.beans.factory.config.BeanDefinitionorg.springframework.beans.factory.config.BeanFactoryPostProcessororg.springframework.beans.factory.config.ConfigurableListableBeanFactoryorg.springframework.beans.factory.support.BeanDefinitionRegistryorg.springframework.beans.factory.support.GenericBeanDefinitionSpecialBeanForEngine BeanFactoryPostProcessorBeanNameAware {
String (String name) {
.= name}
(ConfigurableListableBeanFactory configurableListableBeanFactory) BeansException {
BeanDefinitionRegistry bdr = (BeanDefinitionRegistry) configurableListableBeanFactoryGenericBeanDefinition gbd = GenericBeanDefinition()gbd.setBeanClass(EngineFactory.)gbd.setScope(BeanDefinition.)gbd.setAutowireCandidate()bdr.registerBeanDefinition(gbd)}
}
在postProcessBeanFactory方法中添加了 EngineFactory.class类的Bean。 EngineFactory 是一个FactoryBean,代码21-24行在getObject()方法中,使用动态代理生产Engine接口的代理对象。
启动类:
com.kaigejava.spring.beanlifecom.kaigejava.spring.beanlife.config.AppConfigorg.springframework.context.annotation.AnnotationConfigApplicationContextMainApplication {
(String[] args) {
AnnotationConfigApplicationContext context = AnnotationConfigApplicationContext()context.register(AppConfig.)context.refresh()}
}
执行后结果:
源码:https://gitee.com/kaigejava/kaigejavastudy
相关文章
- Spring 全家桶之 Spring Boot 2.6.4(四)- Data Access(Part C JPA)
- 详解Java中高级程序员必须要掌握的Spring Aop(上篇)
- 【说站】mysql spring事务的特性
- Spring Boot 中文参考指南(二)-Web
- Spring Cloud Security实现微服务间的安全通信示例
- Spring Cloud Data Flow 的作用和使用场景
- 【深入浅出Spring原理及实战】「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常
- spring的事务管理详解编程语言
- spring中bean的scope属性理解详解编程语言
- java spring boot 写入日志详解编程语言
- Spring queryForLong方法:long类型单值查询方法
- Spring框架下整合Redis的实现(spring整合redis)