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

news/2025/1/24 1:00:07/
  • 定义注解
@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/news/1565636.html

相关文章

三篇物联网漏洞挖掘综述

由于物联网设备存在硬件资源受限、硬件复杂异构&#xff0c; 代码、文档未公开的问题&#xff0c; 物联网设备的漏洞挖掘存在较大的挑战&#xff1a; 硬件资源受限性: 通用动态二进分析技术需要在运行程序外围实施监控分析。由于物联网设备存储资源(存储)的受限性&#xff0c;…

win32汇编环境,怎么得到磁盘的盘符

;运行效果 ;win32汇编环境,怎么得到磁盘的盘符 ;以下代码主要为了展示一下原理&#xff0c;应用GetLogicalDrives、GetLogicalDriveStrings函数、屏蔽某些二进制位、按双字节复制内容等。以下代码最多查8个盘&#xff0c;即返回值中的1个字节的信息 ;直接抄进RadAsm可编译运行。…

【Rust自学】14.3. 使用pub use导出方便使用的API

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 14.3.1. 使用pub use导出方便使用的API 在第七章中我们介绍了mod关键字&#xff0c;我们使…

电脑有两张网卡,如何实现同时访问外网和内网?

要是想让一台电脑用两张网卡&#xff0c;既能访问外网又能访问内网&#xff0c;那可以通过设置网络路由还有网卡的 IP 地址来达成。 检查一下网卡的连接 得保证电脑的两张网卡分别连到外网和内网的网络设备上&#xff0c;像路由器或者交换机啥的。 给网卡配上不一样的 IP 地…

vllm多卡部署Qwen2.5-72B-Instruct-GPTQ-Int4

双卡v100 32G部署结果如下&#xff0c;推理时长16s 3卡&#xff0c;tensor_parallel_size3&#xff0c;tensor并行的数量一定要能被attention heads整除 4卡&#xff0c;tensor_parallel_size4&#xff0c;推理速度4s

【博客之星】2024年度个人成长、强化学习算法领域总结

&#x1f4e2;在2025年初&#xff0c;非常荣幸能通过审核进入到《2024年度CSDN博客之星总评选》TOP300的年度评选中&#xff0c;排名40。这还是第一次来到这个阶段&#xff0c;作为一名博士研究生&#xff0c;还是备受鼓舞的。在这里我将以回顾的方式讲述一下这一年在CSDN中走过…

分布式理解

分布式 如何理解分布式 狭义的分布是指&#xff0c;指多台PC在地理位置上分布在不同的地方。 分布式系统 分布式系**统&#xff1a;**多个能独立运行的计算机&#xff08;称为结点&#xff09;组成。各个结点利用计算机网络进行信息传递&#xff0c;从而实现共同的“目标或者任…

除了基本的事件绑定,鸿蒙的ArkUI

鸿蒙操作系统&#xff08;HarmonyOS&#xff09;是由华为技术有限公司开发的分布式操作系统&#xff0c;旨在为多种智能设备提供一个统一的操作平台。它不仅适用于智能手机&#xff0c;还适用于平板电脑、智能手表、智能电视等物联网设备。为了使开发者能够更加便捷地创建跨设备…