找回密码
 立即注册
首页 业界区 安全 springboot~获取原注解的方法findMergedAnnotation使用 ...

springboot~获取原注解的方法findMergedAnnotation使用场景

人弧 2025-9-23 16:37:15
这是一个很好的问题,涉及到Spring注解的元注解处理和属性别名机制。让我详细解释一下Spring JMS是如何获取到你自定义注解中的destination值的。
核心机制:Spring的注解属性别名(Attribute Aliasing)

当你在自定义注解中使用@AliasFor为@JmsListener的destination属性赋值时,Spring通过以下步骤处理:
1. 注解处理流程
  1. // 你的自定义注解
  2. @Target(ElementType.METHOD)
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @JmsListener
  5. public @interface MyCustomJmsListener {
  6.    
  7.     @AliasFor(annotation = JmsListener.class, attribute = "destination")
  8.     String value() default "";
  9.    
  10.     // 其他属性...
  11. }
复制代码
2. Spring JMS的内部处理机制

JmsListenerAnnotationBeanPostProcessor是处理@JmsListener的核心类:
  1. // 简化的处理逻辑
  2. public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor {
  3.    
  4.     @Override
  5.     public Object postProcessAfterInitialization(Object bean, String beanName) {
  6.         // 扫描bean的方法,查找JmsListener注解
  7.         for (Method method : bean.getClass().getMethods()) {
  8.             // 这里会使用Spring的AnnotationUtils找到注解
  9.             JmsListener jmsListener = AnnotatedElementUtils.findMergedAnnotation(
  10.                 method, JmsListener.class);
  11.             
  12.             if (jmsListener != null) {
  13.                 processJmsListener(jmsListener, method, bean);
  14.             }
  15.         }
  16.         return bean;
  17.     }
  18.    
  19.     private void processJmsListener(JmsListener jmsListener, Method method, Object bean) {
  20.         // 获取destination值
  21.         String destination = jmsListener.destination();
  22.         // 创建监听器容器...
  23.     }
  24. }
复制代码
3. 关键方法:AnnotatedElementUtils.findMergedAnnotation()

这是Spring处理注解属性的核心方法:
  1. // Spring内部的处理逻辑
  2. public static  A findMergedAnnotation(
  3.         AnnotatedElement element, Class annotationType) {
  4.    
  5.     // 1. 查找直接或元注解
  6.     Annotation[] annotations = element.getAnnotations();
  7.    
  8.     for (Annotation ann : annotations) {
  9.         // 2. 如果是目标注解直接返回
  10.         if (annotationType.isInstance(ann)) {
  11.             return (A) ann;
  12.         }
  13.         
  14.         // 3. 递归处理元注解
  15.         Annotation[] metaAnnotations = ann.annotationType().getAnnotations();
  16.         for (Annotation metaAnn : metaAnnotations) {
  17.             if (annotationType.isInstance(metaAnn)) {
  18.                 // 4. 处理属性别名映射
  19.                 return synthesizeAnnotation(ann, metaAnn, element);
  20.             }
  21.         }
  22.     }
  23.     return null;
  24. }
复制代码
4. 属性别名解析过程
  1. private static  A synthesizeAnnotation(
  2.         Annotation sourceAnnotation,
  3.         Annotation metaAnnotation,
  4.         AnnotatedElement element) {
  5.    
  6.     Map<String, Object> attributeMap = new HashMap<>();
  7.    
  8.     // 获取元注解的属性
  9.     Method[] metaMethods = metaAnnotation.annotationType().getDeclaredMethods();
  10.     for (Method metaMethod : metaMethods) {
  11.         String attributeName = metaMethod.getName();
  12.         
  13.         // 检查源注解是否有对应的别名属性
  14.         Method sourceMethod = findAliasMethod(sourceAnnotation, attributeName);
  15.         if (sourceMethod != null) {
  16.             // 使用源注解的值覆盖元注解的值
  17.             Object value = invokeMethod(sourceMethod, sourceAnnotation);
  18.             attributeMap.put(attributeName, value);
  19.         } else {
  20.             // 使用元注解的默认值
  21.             Object value = invokeMethod(metaMethod, metaAnnotation);
  22.             attributeMap.put(attributeName, value);
  23.         }
  24.     }
  25.    
  26.     // 创建合成注解
  27.     return AnnotationUtils.synthesizeAnnotation(attributeMap,
  28.         metaAnnotation.annotationType(), element);
  29. }
复制代码
5. 实际示例

假设你的使用方式如下:
  1. @Component
  2. public class MyMessageListener {
  3.    
  4.     @MyCustomJmsListener("my-queue")
  5.     public void handleMessage(String message) {
  6.         // 处理消息
  7.     }
  8. }
复制代码
Spring JMS的处理过程:

  • 发现注解:扫描到@MyCustomJmsListener注解
  • 识别元注解:发现@MyCustomJmsListener被@JmsListener元注解标记
  • 属性合并:通过@AliasFor将value="my-queue"映射到destination属性
  • 创建监听器:使用合成后的@JmsListener(destination = "my-queue")创建JMS监听容器
6. 验证方法

你可以通过以下方式验证这个机制:
  1. @SpringBootTest
  2. class JmsListenerTest {
  3.    
  4.     @Autowired
  5.     private JmsListenerEndpointRegistry endpointRegistry;
  6.    
  7.     @Test
  8.     void testCustomAnnotation() {
  9.         // 检查监听器容器是否创建成功
  10.         Collection<MessageListenerContainer> containers =
  11.             endpointRegistry.getListenerContainers();
  12.         
  13.         for (MessageListenerContainer container : containers) {
  14.             if (container instanceof JmsListenerEndpointRegistry) {
  15.                 // 验证destination是否正确设置
  16.                 String destination = ((AbstractJmsListenerContainer) container)
  17.                     .getDestination();
  18.                 System.out.println("监听的destination: " + destination);
  19.             }
  20.         }
  21.     }
  22. }
复制代码
总结

Spring通过AnnotatedElementUtils和注解属性别名机制,能够正确识别你自定义注解中通过@AliasFor映射的属性值。这种设计使得注解组合和自定义变得非常灵活,是Spring框架强大的元编程能力的体现。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册