自定义BeanPostProcessor实现自动注入标注了特定注解的Bean

embedded/2025/1/23 15:30:30/
  • 定义注解
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnno {
}
  • 定义一个配置类
@Configuration
public class RestConfig {@MyAnno@Beanpublic PayDTO payDTO(){PayDTO payDTO = new PayDTO();payDTO.setPayNo("1");return payDTO;}@Beanpublic PayDTO payDTO1(){PayDTO payDTO = new PayDTO();payDTO.setPayNo("2");return payDTO;}}

这个配置类返回了两个PayDTO 类型的对象。

  • 定义使用类
@Component
public class MyConfigTest implements InitializingBean {@MyAnno@Autowired(required = false)private List<PayDTO> payDTOList = Collections.emptyList();@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("payDTO = " + payDTOList);}
}

这里想只从容器中获取标注了@MyAnno注解的PayDTO对象,也就是说应该是只能获取到一个。

  • 定义BeanPostProcessor
@Component
public class MyAnnoPostProcesser implements BeanPostProcessor {@Autowiredprivate ApplicationContext applicationContext;@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {//这里只考虑对@Autowired作用于属性上Field[] declaredFields = bean.getClass().getDeclaredFields();if (bean instanceof MyConfigTest){System.out.println("MyConfigTest");}for (Field field : declaredFields) {//判断当前属性是否标记了@MyAnno注解MyAnno annotation = field.getAnnotation(MyAnno.class);Autowired autowired = field.getAnnotation(Autowired.class);if (annotation != null && autowired != null) {field.setAccessible(true);//获取字段的类型Type genericType = field.getGenericType();if (genericType instanceof ParameterizedType) {//判断属性类型是否是一个参数化类型,例如 List<String> 这里的String就是泛型参数ParameterizedType parameterizedType = (ParameterizedType) genericType;Type rawType = parameterizedType.getRawType();//泛型原生类型是List类型if (rawType == List.class) {//获取参数化类型列表,每一个参数化列表可能又是一个泛型类型Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();Type argument = actualTypeArguments[0];if (argument instanceof Class) {Class<?> clazz = (Class<?>) argument;//从容器中获取对应此参数化类型并且标注了MyAnno注解的BeanMap<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(MyAnno.class);if (beansWithAnnotation.size() > 0) {List<Object> beanList = beansWithAnnotation.entrySet().stream().filter(entry -> {Object value = entry.getValue();return value.getClass() == clazz;}).map(item -> item.getValue()).collect(Collectors.toList());//进行属性赋值try {field.set(bean, beanList);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}}}}}}return bean;}
}

BeanPostProcessor实现原理:

  1. 获取Bean示例,并拿到这个Bean对象中声明的属性。

  2. 判断属性是否同时标注了MyAnno和Autowired注解。

  3. 获取属性的类型
    属性的类型返回值有多种情况,可能是Class、ParameterizedType、GenericType等
    如果是一个具体的类型则返回Class,如果是一个泛型类型,例如List,则返回ParameterizedType参数化类型,参数化类型的意思就是使用了泛型类型,并指定了泛型参数,这里的泛型参数就是PayDTO。

  4. parameterizedType.getRawType(); 获取泛型类型的原生类型,也就是List.class

  5. Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 获取泛型类型的参数类型,例如List类的声明是
    List 这里的T就是泛型参数,而parameterizedType.getActualTypeArguments();返回的是一个数组,因为可能不止一个泛型类型,例如Map<K,V> 。

  6. 获取参数化类型的第一个元素,其实这里返回的就是PayDTO.class对象。

  7. 从容器中获取所有标注了MyAnno注解的Bean对象,并且遍历出是PayDTO类型的。

  8. 通过field.set(bean, beanList);实现属性值注入。

  9. 完成基于BeanPostProcessor实现的自定义注解Bean对象注入。

  • 踩坑

MyConfigTest对象标注的@Component,如果是标注@Configuration注解,此时Spring会生成一个代理对象,通过代理对象拿不到原始对象的相关属性了。


http://www.ppmy.cn/embedded/156331.html

相关文章

mikrotik7配置内网到内网的lantolan

lan to lan又称site to site&#xff0c;在前面的文章已经配置wireguard实现单个ip互访&#xff0c;这期来实现lan to lan 客户端依然使用windows。本期在上一篇基础上增加配置 一、LAN to LAN配置 windows客户端修改 我的第一个内网网段是192.168.11.0/24,以下为相关修改 …

詳細講一下在RN(ReactNative)中,6個比較常用的組件以及詳細的用法

1.View 组件&#xff08;基础容器&#xff09; import { View, StyleSheet } from react-native;const MyComponent () > {return (<View style{styles.container} // 样式pointerEvents"none" // 控制触摸事件&#xff1a;none, box-none, box-only, …

(2025,BioLM,综述)用于生物信息学的 LLM

Large Language Models for Bioinformatics 目录 0. 摘要 1. 引言 2. 生物信息学中语言模型与基础模型的背景 2.1 语言模型与生物信息学基础概述 2.1.1 LLM 与基础模型 2.1.2 生物信息学的应用与挑战 2.2 训练方法与模型 2.2.1 预训练 2.2.2 RLHF 2.2.3 知识蒸馏 …

政府机构如何使用六西格玛来提高效率和提供更好的服务

联邦机构面临着改善运作、降低成本和确保向公民提供高质量服务的巨大压力。六西格玛方法与Minitab强大的工具相结合&#xff0c;使政府组织能够充满信心地应对这些挑战。通过简化流程、减少浪费和改进决策&#xff0c;政府团队可以提供真正有影响力的服务。 六西格玛如何改善政…

OFD 套版生成原理与 C# 实现详解

1. 引言 OFD&#xff08;Open Fixed-layout Document&#xff09;是一种基于 XML 的开放版式文档格式&#xff0c;主要用于电子文档的存储和交换。与 PDF 类似&#xff0c;OFD 是一种固定版式文档格式&#xff0c;能够确保文档在不同设备和平台上显示的一致性。OFD 格式广泛应…

flask常见问答题

以下是一些关于 Flask 框架的问答题&#xff0c;供您学习或测试知识点&#xff1a; 基础知识 Flask 是什么&#xff1f;它的主要特点是什么&#xff1f; 答&#xff1a;Flask 是一个基于 Python 的轻量级 Web 框架&#xff0c;其特点是简单、灵活和模块化。 Flask 和 Django …

树莓派pico入坑笔记,SPI使用

关于树莓派pico和circuitpython的更多玩法&#xff0c;请看树莓派pico专栏 uart使用见这篇文章 调用circuitpy的busio模块来使用&#xff0c;除此以外&#xff0c;uart、iic等要需要使用该模块&#xff0c;使用方法见及详细信息见这篇文章 收发数据的格式是字节数组bytearra…

【docker-1】快速入门docker

docker搭建 1、下载二进制文件 wget https://mirror.nju.edu.cn/docker-ce/linux/static/stable/aarch64/docker-20.10.7.tgz解压docker目录 tar -xzvf docker-20.10.7.tgz .安装文件到/usr/local/bin mv ./docker/* /usr/local/bin2、配置docker.service [Unit] Descript…