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

Spring扩展点系列-MergedBeanDefinitionPostProcessor

文章目录

    • 简介
    • 源码分析
    • 示例
      • 示例一:Spring中Autowire注解的依赖注入

简介

spring容器中Bean的生命周期内所有可扩展的点的调用顺序
扩展接口 实现接口
ApplicationContextlnitializer initialize
AbstractApplicationContext refreshe
BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor postProcessBeanFactory
BeanFactoryPostProcessor postProcessBeanFactory
instantiationAwareBeanPostProcessor postProcessBeforelnstantiation
SmartlnstantiationAwareBeanPostProcessor determineCandidateConstructors
MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition
InstantiationAwareBeanPostProcessor postProcessAfterlnstantiation
SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference
BeanNameAware setBeanName
BeanFactoryAware postProcessPropertyValues
ApplicationContextAwareProcessor invokeAwarelnterfaces
InstantiationAwareBeanPostProcessor postProcessBeforelnstantiation
@PostConstruct
InitializingBean afterPropertiesSet
FactoryBean getobject
SmartlnitializingSingleton afterSingletonslnstantiated
CommandLineRunner run
DisposableBeandestroy

MergedBeanDefinitionPostProcessor扩展点的作用是对合并后的BeanDefintion进行后置处理。准确的调用时机应该是在创建完 bean 实例之后,接下来会对该接口源码和举例进行说明该扩展点的使用

源码分析

该接口的顶级接口是BeanPostProcessor

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {/*** Post-process the given merged bean definition for the specified bean.* @param beanDefinition 处理后bean definition* @param beanType       解析出来的 bean 的 class* @param beanName       bean 的名字* @see AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors*/void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);/*** A notification that the bean definition for the specified name has been reset,* and that this post-processor should clear any metadata for the affected bean.* <p>The default implementation is empty.* @param beanName bean 的名字* @since 5.1* @see DefaultListableBeanFactory#resetBeanDefinition*/default void resetBeanDefinition(String beanName) {}}

找到 applyMergedBeanDefinitionPostProcessors可以看出, MergedBeanDefinitionPostProcessor 的调用是在创建完 bean 实例之后调用。applyMergedBeanDefinitionPostProcessors 方法会获取所有的 MergedBeanDefinitionPostProcessor,并回调它们的 postProcessMergedBeanDefinition 方法
回调 postProcessMergedBeanDefinition 方法时,已经拿到了 merged bean definition,并且还未开始 poplateBean 填充 bean 属性、initlializeBean 初始化 bean 对象,因此可以在这里对 merged bean definition 进行一些操作,在 poplateBean 或 initlializeBean 阶段使用前面操作结果实现所需功能

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}//.....源码省略
}protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);}
}

示例

示例一:Spring中Autowire注解的依赖注入

在Spring 中,AutowiredAnnotationBeanPostProcessor是MergedBeanDefinitionPostProcessor 的一个实现类,该类通过 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法回调获取 bean 上的 Autowire 注解,并将相关信息保存到缓存中。整体的主要作用是完成 Autowire 注解的依赖注入
在这里插入图片描述

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);//checkConfigMembers方法就是遍历从findAutowiringMetadata方法拿到的数据,返回封装这些数据,最后放入到RootBeanDefinition中,也就是bean定义信息中metadata.checkConfigMembers(beanDefinition);
}private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {// InjectionMetadata会被缓存起来--key为beanNameString cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());//双重锁机制,确保单例InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}//为当前bean构建InjectionMetadatametadata = buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;
}private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {// 构建currElements,用来存储符合条件的数据final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();//遍历当前类上所有属性,寻找到存在相关注解的属性ReflectionUtils.doWithLocalFields(targetClass, field -> {//findAutowiredAnnotation方法就是在遍历autowiredAnnotationTypes,判断参数或方法是否被autowiredAnnotationTypes里面的注解修饰,有就直接返回了。MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static fields: " + field);}return;}boolean required = determineRequiredStatus(ann);currElements.add(new AutowiredFieldElement(field, required));}});//遍历当前类上所有方法,寻找到存在相关注解的属性且非静态方法,然后封装为AutowiredMethodElement后返回ReflectionUtils.doWithLocalMethods(targetClass, method -> {// 查找符合条件的方法Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static methods: " + method);}return;}if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation should only be used on methods with parameters: " +method);}}// 获取required参数boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);// 添加到currElementscurrElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);//注入依赖注入一并处理当前父类上标注的相关依赖注入点targetClass = targetClass.getSuperclass();}// 向上遍历,直到父类为Object为止。while (targetClass != null && targetClass != Object.class);//创建一个InjectionMetadata返回,InjectionMetadata管理当前bean中所有依赖注入点return InjectionMetadata.forElements(elements, clazz);
}public void checkConfigMembers(RootBeanDefinition beanDefinition) {Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());for (InjectedElement element : this.injectedElements) {Member member = element.getMember();if (!beanDefinition.isExternallyManagedConfigMember(member)) {beanDefinition.registerExternallyManagedConfigMember(member);checkedElements.add(element);}}this.checkedElements = checkedElements;
}public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {//后续依赖注入只会对checkedElements集合中的依赖注入点进行处理Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {for (InjectedElement element : elementsToIterate) {element.inject(target, beanName, pvs);}}
}
http://www.lryc.cn/news/442901.html

相关文章:

  • Centos 7.9 使用 crontab 实现开机启动
  • 基于微信的设备故障报修管理系统设计与实现+ssm论文源码调试讲解
  • yolo自动化项目实例解析(二)ui页面整理 1.78
  • PyQt / PySide + Pywin32 + ctypes 自定义标题栏窗口 + 完全还原 Windows 原生窗口边框特效项目
  • 面试时遇见的项目问题
  • 在线骑行网站设计与实现
  • 大批量查询方案简记(Mybatis流式查询)
  • python - 子类为什么调用父类的方法
  • 【JavaScript】数据结构之字典 哈希表
  • Adobe出现This unlicensed Photoshop app has been disabled
  • elementui 单元格添加样式的两种方法
  • 如何有效管理技术债务:IT项目中的长期隐患
  • 2024 “华为杯” 中国研究生数学建模竞赛(D题)深度剖析|大数据驱动的地理综合问题|数学建模完整代码+建模过程全解全析
  • Linux 清空redis缓存及查询key值
  • MySql调优(三)Query SQL优化(2)explain优化
  • Java【代码 18】处理Word文档里的Excel表格数据(源码分享)
  • 21、Tomato
  • 代码随想录 八股文训练营40天总结
  • Debian 12上安装google chrome
  • Python | Leetcode Python题解之第405题数字转换为十六进制数
  • 定位坐标系
  • 安全通信网络等保
  • 7--SpringBoot-后端开发、原理详解(面试高频提问点)
  • wordpress主题摘要调用显示错误解决办法
  • 【ESP32】ESP-IDF开发 | UART通用异步收发传输器+串口收发例程
  • 2025秋招LLM大模型多模态面试题(六)-KV缓存
  • matlab边缘点提取函数
  • Redis 执行 Lua,能保证原子性吗?
  • 让模型评估模型:构建双代理RAG评估系统的步骤解析
  • RabbitMQ 高级特性——发送方确认