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

这是一个很好的问题,涉及到Spring注解的元注解处理和属性别名机制。让我详细解释一下Spring JMS是如何获取到你自定义注解中的destination值的。

核心机制:Spring的注解属性别名(Attribute Aliasing)

当你在自定义注解中使用@AliasFor@JmsListener的destination属性赋值时,Spring通过以下步骤处理:

1. 注解处理流程

// 你的自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@JmsListener
public @interface MyCustomJmsListener {
 
 @AliasFor(annotation = JmsListener.class, attribute = "destination")
 String value() default "";
 
 // 其他属性...
}

2. Spring JMS的内部处理机制

JmsListenerAnnotationBeanPostProcessor是处理@JmsListener的核心类:

// 简化的处理逻辑
public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor {
 
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) {
 // 扫描bean的方法,查找JmsListener注解
 for (Method method : bean.getClass().getMethods()) {
 // 这里会使用Spring的AnnotationUtils找到注解
 JmsListener jmsListener = AnnotatedElementUtils.findMergedAnnotation(
 method, JmsListener.class);
 
 if (jmsListener != null) {
 processJmsListener(jmsListener, method, bean);
 }
 }
 return bean;
 }
 
 private void processJmsListener(JmsListener jmsListener, Method method, Object bean) {
 // 获取destination值
 String destination = jmsListener.destination();
 // 创建监听器容器...
 }
}

3. 关键方法:AnnotatedElementUtils.findMergedAnnotation()

这是Spring处理注解属性的核心方法:

// Spring内部的处理逻辑
public static <A extends Annotation> A findMergedAnnotation(
 AnnotatedElement element, Class<A> annotationType) {
 
 // 1. 查找直接或元注解
 Annotation[] annotations = element.getAnnotations();
 
 for (Annotation ann : annotations) {
 // 2. 如果是目标注解直接返回
 if (annotationType.isInstance(ann)) {
 return (A) ann;
 }
 
 // 3. 递归处理元注解
 Annotation[] metaAnnotations = ann.annotationType().getAnnotations();
 for (Annotation metaAnn : metaAnnotations) {
 if (annotationType.isInstance(metaAnn)) {
 // 4. 处理属性别名映射
 return synthesizeAnnotation(ann, metaAnn, element);
 }
 }
 }
 return null;
}

4. 属性别名解析过程

private static <A extends Annotation> A synthesizeAnnotation(
 Annotation sourceAnnotation, 
 Annotation metaAnnotation, 
 AnnotatedElement element) {
 
 Map<String, Object> attributeMap = new HashMap<>();
 
 // 获取元注解的属性
 Method[] metaMethods = metaAnnotation.annotationType().getDeclaredMethods();
 for (Method metaMethod : metaMethods) {
 String attributeName = metaMethod.getName();
 
 // 检查源注解是否有对应的别名属性
 Method sourceMethod = findAliasMethod(sourceAnnotation, attributeName);
 if (sourceMethod != null) {
 // 使用源注解的值覆盖元注解的值
 Object value = invokeMethod(sourceMethod, sourceAnnotation);
 attributeMap.put(attributeName, value);
 } else {
 // 使用元注解的默认值
 Object value = invokeMethod(metaMethod, metaAnnotation);
 attributeMap.put(attributeName, value);
 }
 }
 
 // 创建合成注解
 return AnnotationUtils.synthesizeAnnotation(attributeMap, 
 metaAnnotation.annotationType(), element);
}

5. 实际示例

假设你的使用方式如下:

@Component
public class MyMessageListener {
 
 @MyCustomJmsListener("my-queue")
 public void handleMessage(String message) {
 // 处理消息
 }
}

Spring JMS的处理过程:

  1. 发现注解:扫描到@MyCustomJmsListener注解
  2. 识别元注解:发现@MyCustomJmsListener@JmsListener元注解标记
  3. 属性合并:通过@AliasForvalue="my-queue"映射到destination属性
  4. 创建监听器:使用合成后的@JmsListener(destination = "my-queue")创建JMS监听容器

6. 验证方法

你可以通过以下方式验证这个机制:

@SpringBootTest
class JmsListenerTest {
 
 @Autowired
 private JmsListenerEndpointRegistry endpointRegistry;
 
 @Test
 void testCustomAnnotation() {
 // 检查监听器容器是否创建成功
 Collection<MessageListenerContainer> containers = 
 endpointRegistry.getListenerContainers();
 
 for (MessageListenerContainer container : containers) {
 if (container instanceof JmsListenerEndpointRegistry) {
 // 验证destination是否正确设置
 String destination = ((AbstractJmsListenerContainer) container)
 .getDestination();
 System.out.println("监听的destination: " + destination);
 }
 }
 }
}

总结

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

作者:张占岭原文地址:https://www.cnblogs.com/lori/p/19107625

%s 个评论

要回复文章请先登录注册