特点直接查找原始注解局限性无法获取被元注解如AliasFor覆盖的属性值无法处理注解属性覆盖Annotation Attribute Overrides场景若注解是通过元注解如Component派生出的Service间接存在可能无法正确获取属性值2.AnnotatedElementUtils.findMergedAnnotation()特点查找合并后的注解优势支持Spring的注解属性覆盖机制通过AliasFor会递归处理元注解合并属性值能正确获取经过覆盖后的最终属性值支持查找接口/父类上的注解通过Inherited示例场景差异Spec(name defaultName) // 元注解 Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface Spec { String name() default ; } Spec(name customName) // 实际使用的注解 public void someMethod() {} // 测试结果 AnnotationUtils.findAnnotation() - 可能返回原始元注解的namedefaultName AnnotatedElementUtils.findMergedAnnotation() - 会返回合并后的namecustomName何时使用需要原始注解时 →AnnotationUtils需要实际生效的注解属性时 →AnnotatedElementUtilsSpring注解处理如Transactional等组合注解 → 优先使用AnnotatedElementUtils建议在Spring环境下优先使用AnnotatedElementUtils除非明确需要访问未经处理的原始注解。二 Spring的注解属性别名的应用当你在自定义注解中使用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, ClassA 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) { MapString, 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的处理过程发现注解扫描到MyCustomJmsListener注解识别元注解发现MyCustomJmsListener被JmsListener元注解标记属性合并通过AliasFor将valuemy-queue映射到destination属性创建监听器使用合成后的JmsListener(destination my-queue)创建JMS监听容器验证方法你可以通过以下方式验证这个机制SpringBootTest class JmsListenerTest { Autowired private JmsListenerEndpointRegistry endpointRegistry; Test void testCustomAnnotation() { // 检查监听器容器是否创建成功 CollectionMessageListenerContainer containers endpointRegistry.getListenerContainers(); for (MessageListenerContainer container : containers) { if (container instanceof JmsListenerEndpointRegistry) { // 验证destination是否正确设置 String destination ((AbstractJmsListenerContainer) container) .getDestination(); System.out.println(监听的destination: destination); } } } }
springboot~获取原注解的方法findMergedAnnotation使用场景
特点直接查找原始注解局限性无法获取被元注解如AliasFor覆盖的属性值无法处理注解属性覆盖Annotation Attribute Overrides场景若注解是通过元注解如Component派生出的Service间接存在可能无法正确获取属性值2.AnnotatedElementUtils.findMergedAnnotation()特点查找合并后的注解优势支持Spring的注解属性覆盖机制通过AliasFor会递归处理元注解合并属性值能正确获取经过覆盖后的最终属性值支持查找接口/父类上的注解通过Inherited示例场景差异Spec(name defaultName) // 元注解 Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface Spec { String name() default ; } Spec(name customName) // 实际使用的注解 public void someMethod() {} // 测试结果 AnnotationUtils.findAnnotation() - 可能返回原始元注解的namedefaultName AnnotatedElementUtils.findMergedAnnotation() - 会返回合并后的namecustomName何时使用需要原始注解时 →AnnotationUtils需要实际生效的注解属性时 →AnnotatedElementUtilsSpring注解处理如Transactional等组合注解 → 优先使用AnnotatedElementUtils建议在Spring环境下优先使用AnnotatedElementUtils除非明确需要访问未经处理的原始注解。二 Spring的注解属性别名的应用当你在自定义注解中使用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, ClassA 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) { MapString, 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的处理过程发现注解扫描到MyCustomJmsListener注解识别元注解发现MyCustomJmsListener被JmsListener元注解标记属性合并通过AliasFor将valuemy-queue映射到destination属性创建监听器使用合成后的JmsListener(destination my-queue)创建JMS监听容器验证方法你可以通过以下方式验证这个机制SpringBootTest class JmsListenerTest { Autowired private JmsListenerEndpointRegistry endpointRegistry; Test void testCustomAnnotation() { // 检查监听器容器是否创建成功 CollectionMessageListenerContainer containers endpointRegistry.getListenerContainers(); for (MessageListenerContainer container : containers) { if (container instanceof JmsListenerEndpointRegistry) { // 验证destination是否正确设置 String destination ((AbstractJmsListenerContainer) container) .getDestination(); System.out.println(监听的destination: destination); } } } }