这是一个很好的问题,涉及到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 findMergedAnnotation(
- AnnotatedElement element, Class 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 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的处理过程:
- 发现注解:扫描到@MyCustomJmsListener注解
- 识别元注解:发现@MyCustomJmsListener被@JmsListener元注解标记
- 属性合并:通过@AliasFor将value="my-queue"映射到destination属性
- 创建监听器:使用合成后的@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框架强大的元编程能力的体现。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |