当前位置: 首页 > news >正文

Spring Bean生命周期原理、常见的后处理器实现

这里写目录标题

  • 生命周期
  • 模板方法设计模式
  • @Autowired Bean后处理器实现分析

生命周期

springboot项目启动类

@SpringBootApplication
public class BeanLifeCycleApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(BeanLifeCycleApplication.class, args);context.close();}
}

定义一个LifeCycleBean,加上@Component注解,再编写一些方法,给这些方法加上Bean的生命周期过程中的注解

@Component
@Slf4j
public class LifeCycleBean {public LifeCycleBean() {log.debug("构造");}@Autowiredpublic void autowire(@Value("${JAVA_HOME}") String name) {log.debug("依赖注入:{}", name);}@PostConstructpublic void init() {log.debug("初始化");}@PreDestroypublic void destroy() {log.debug("销毁");}
}

在这里插入图片描述
编写自定义Bean的后处理器,需要实现InstantiationAwareBeanPostProcessor和DestructionAwareBeanPostProcessor接口,并加上@Component注解,对lifeCycleBean的生命周期过程进行扩展。

@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {@Override// 实例化前(即调用构造方法前)执行的方法public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<<<<<<< 实例化前执行,如@PreDestroy");// 返回null保持原有对象不变,返回不为null,会替换掉原有对象return null;}@Override// 实例化后执行的方法public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")) {log.debug("<<<<<<<<<<< 实例化后执行,这里如果返回 false 会跳过依赖注入阶段");// return false;}return true;}@Override// 依赖注入阶段执行的方法public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<<<<<<< 依赖注入阶段执行,如@Autowired、@Value、@Resource");return pvs;}@Override// 销毁前执行的方法public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {if(beanName.equals("lifeCycleBean"))log.debug("<<<<<<<<<<<销毁之前执行");}@Override// 初始化之前执行的方法public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if(beanName.equals("lifeCycleBean"))log.debug("<<<<<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean,如 @PostConstruct、@ConfigurationProperties");return bean;}@Override// 初始化之后执行的方法public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if(beanName.equals("lifeCycleBean"))log.debug("<<<<<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的bean,如 代理增强");return bean;}
}

在这里插入图片描述
bean的除了四个阶段,每个阶段都可能会有后置增强功能。

模板方法设计模式

提高现有代码的扩展能力

public class TestMethodTemplatePattern {public static void main(String[] args) {MyBeanFactory beanFactory = new MyBeanFactory();beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));beanFactory.getBean();}static class MyBeanFactory {public Object getBean() {Object bean = new Object();System.out.println("构造:" + bean);System.out.println("依赖注入:" + bean);for (BeanPostProcessor processor : processors) {processor.inject(bean);}System.out.println("初始化:" + bean);return bean;}private List<BeanPostProcessor> processors = new ArrayList<>();public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {processors.add(beanPostProcessor);}}
不能确定的扩展抽象为接口interface BeanPostProcessor {void inject(Object bean);}
}

@Autowired Bean后处理器实现分析

@Slf4j
public class TestBeanPostProcessors {@Testpublic void testAutowiredAnnotationBeanPostProcessor() throws Throwable {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 这里为了省事就不使用 beanFactory.registerBeanDefinition()方法去添加类的描述信息了// 直接使用 beanFactory.registerSingleton可以直接将Bean的单例对象注入进去,// 后面调用beanFactory.getBean()方法的时候就不会去根据Bean的定义去创建Bean的实例了,// 也不会有懒加载和依赖注入的初始化过程了。beanFactory.registerSingleton("bean2", new Bean2());beanFactory.registerSingleton("bean3", new Bean3());// 设置@Autowired注解的解析器beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// 设置解析 @Value 注解中的 ${} 表达式的解析器beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);// 1. 查找哪些属性、方法加了 @Autowired,这称之为InjectionMetadata// 创建后处理器AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();// 后处理器在解析@Autowired和@Value的时候需要用到其他Bean,// 而BeanFactory提供了需要的Bean,所以需要把BeanFactory传给这个后处理器processor.setBeanFactory(beanFactory);// 创建Bean1Bean1 bean1 = new Bean1();System.out.println(bean1);// 解析@Autowired和@Value注解,执行依赖注入// PropertyValues pvs: 给注解的属性注入给定的值,这里不需要手动给定,传null即可// processor.postProcessProperties(null, bean1, "bean1");// postProcessProperties()方法底层原理探究// 通过查看源码得知 postProcessProperties()方法中调用了一个私有的方法findAutowiringMetadata(beanName, bean.getClass(), pvs); 会返回一个InjectionMetadata的对象,然后会调用InjectionMetadata.inject(bean1, "bean1", null)进行依赖注入// 通过反射调用一下/*Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata",String.class, Class.class, PropertyValues.class);findAutowiringMetadata.setAccessible(true);// 获取Bean1上加了@Value @Autowired注解的成员变量和方法参数信息InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);System.out.println(metadata);// 2. 调用 InjectionMetaData 来进行依赖注入,注入时按类型查找值metadata.inject(bean1, "bean1", null);System.out.println(bean1);*/// 3. 如何去Bean工厂里面按类型查找值// 由于InjectionMetadata.inject(bean1, "bean1", null)的源码调用链过长,摘出主要调用过程进行演示// 3.1 @Autowired加在成员变量上,InjectionMetatadata给Bean1注入Bean3的过程// 通过InjectionMetadata把Bean1加了@Autowired注解的属性的BeanName先拿到,这里假设拿到的BeanName就是 bean3// 通过BeanName反射获取到这个属性,Field bean3Field = Bean1.class.getDeclaredField("bean3");// 设置私有属性可以被访问bean3Field.setAccessible(true);// 将这个属性封装成一个DependencyDescriptor对象DependencyDescriptor dd1 = new DependencyDescriptor(bean3Field, false);// 再执行beanFactory的doResolveDependencyBean3 bean3Value = (Bean3) beanFactory.doResolveDependency(dd1, null, null, null);System.out.println(bean3Value);// 给Bean1的成员bean3赋值bean3Field.set(bean1, bean3Value);System.out.println(bean1);// 3.2 @Autowired加在方法上,InjectionMetatadata给Bean1注入Bean2的过程Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true);Bean2 bean2Value = (Bean2) beanFactory.doResolveDependency(dd2, "bean2", null, null);System.out.println(bean2Value);// 给Bean1的setBean2()方法的参数赋值setBean2.invoke(bean1, bean2Value);System.out.println(bean1);// 3.3 @Autowired加在方法上,方法参数为String类型,加了@Value,// InjectionMetadata给Bean1注入环境变量JAVA_HOME属性的值Method setJava_home = Bean1.class.getDeclaredMethod("setJava_home", String.class);DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setJava_home, 0), true);String java_home = (String) beanFactory.doResolveDependency(dd3, null, null, null);System.out.println(java_home);setJava_home.invoke(bean1, java_home);System.out.println(bean1);}
}


http://www.mrgr.cn/news/100365.html

相关文章:

  • C#中常见的设计模式
  • 【Linux应用】交叉编译环境配置,以及最简单粗暴的环境移植(直接从目标板上复制)
  • Unity接入火山引擎/豆包大模型文生图,实现AI绘画
  • WSL 安装过程整理
  • K8S Service 原理、案例
  • OpenCV --- 图像预处理(七)
  • Adruino:传感器及步进电机
  • 移动通信行业术语
  • 软件项目实施全流程及交付物清单
  • Android HAL HIDL
  • Happens-Before原则
  • python怎么查看函数原型及变量是什么类型
  • 高中数学联赛模拟试题精选第16套几何题
  • 学习笔记:Qlib 量化投资平台框架 — GETTING STARTED
  • Jquery -函数调用使用创建立即执行函数
  • magic-api连接达梦数据库
  • 27-算法打卡-字符串-找出字符串中第一个匹配项的下标-leetcode(28)-第二十七天
  • 当高级辅助驾驶遇上“安全驾校”:NVIDIA如何用技术给无人驾驶赋能?
  • 2:QT联合HALCON编程—图像显示放大缩小
  • classfinal 修改过源码,支持jdk17 + spring boot 3.2.8