Open justmehyp opened 5 years ago
感谢反馈,确认中...
原文的Bean是txManager和txManager2,并非txManager1和txManager2,名称有误,所以复现不了,我的是19年第四次印刷,不确定是否修改过。
@wanglforever 已修改 txManager1 为 txManager,结果还是一样的,无法重现,原因是 @TransactionalService.value() 不会隐式覆盖 @Service.value()
@justmehyp 您说的没错,@TransactionalService.value() 不会隐式覆盖 @Service.value(),但是SpringFramework5.0.6,AnnotationBeanNameGenerator#generateBeanName获取Bean的beanName的方式是如果低层注解上有value属性,那么直接返回value属性的值,而不是去取顶层@Component的value属性值,所以会有这种现象 Bean 名称 : txManager , 对象 : thinking.in.spring.boot.samples.spring5.bean.TransactionalServiceBean@7283d3eb 而beanName为txManager的PlatformTransactionManager就会被忽略掉,因此这种现象是没有问题的,您是否使用的不是5.0.6的版本,因为小马哥的配套代码也是基于5.0.6的,而且我这里是可以复现的。
@wanglforever 多谢,看源码确实如此。在我的 mac上,还会出现 TransactionServiceBean bean 被 注解方法 txManager
生成的 bean 覆盖的情况。可能是不同操作系统上 bean 的扫描加载顺序不一致吧,所以我这边切到 5.0.6 版本依然无法重现:
21:03:23.448 [main] INFO ... - Overriding bean definition for bean 'txManager' with a different definition: replacing [Generic bean: class [... TransactionServiceBean]; ... with [ ... factoryMethodName=txManager; ...]
@mercyblitz 由此可见,Spring 对 Annotation 的 value属性做了一些不少特殊处理 ,此处选择 value 属性作为示例不妥,干扰因素太多。
目前发现:
1) 隐式覆盖不适用于 value 属性, 特殊处理逻辑在org.springframework.core.annotation.AnnotatedElementUtils.MergedAnnotationAttributesProcessor#postProcess
2) 如果注解有元注解 @Component
, 那么在 AnnotationBeanNameGenerator#determineBeanNameFromAnnotation
方法中,会取其 value 属性值作为 bean name
觉得还可以增加隐性覆盖和显性覆盖共存情况的讨论,例如:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
@Transactional
public @interface TransactionalService {
String name() default "nameValue";
String value() default "value";
String transactionManager() default "transactionManager";
@AliasFor(annotation = Transactional.class, attribute = "value")
String txManager() default "txManager";
}
5.0.6 版本现在是报错:Caused by: org.springframework.core.annotation.AnnotationConfigurationException: In AnnotationAttributes for annotation [org.springframework.transaction.annotation.Transactional] declared on class thinking.in.spring.boot.samples.spring5.bean.TransactionalServiceBean, attribute 'transactionManager' and its alias 'value' are declared with values of [transactionManager] and [txManager], but only one is permitted.
小马哥这本书写的很好,使我收益匪浅,同时也很钦佩小马哥技术造诣之高。
最近看到 第 7 章「走向注解驱动编程(Annotation-Driven)」,很多之前稀里糊涂的地方,在书的指引下,加上动手试验和阅读相关资料之后,豁然开朗。
好了,开始提 Bug 吧 :》 我手上的书版次是:2019年3月第1版,印次是:2019年4月第2次印刷。
第 211 页第 1 段,关于“显性覆盖”,
文档中并没有确认指出属性A和B是否在同一个注解中
是理解有误的,官方原文如下:可以看到,属性 B 在 meta-annotation 中,所以 A 和 B 不在同一个注解中。 假如 A 和 B 在同一个注解,那么不能单向 A @AliasFor B,还需要 B @AliasFor A,但此时, A 和 B 之间不是"显性覆盖"的关系,而是 显性属性别名(Explicit Aliases) 的关系。
第 215 页末尾 和 第 216 页开头的示例,无法重现,我试了 Spring Boot 版本从 1.0.0.RELEASE 到 2.1.7.RELEASE 的几个版本,都无法重现。
书上的运行结果是不会报错,会输出:
但我却抛异常了:
我的代码如下:
TransactionalServiceBootstrap.java
实际上,无法重现,是符合我的预期的,因为 Spring 对 属性 value 做了特殊对待,「隐性覆盖」对 value 不起作用, Spring 源码位置见
org.springframework.core.annotation.AnnotatedElementUtils.MergedAnnotationAttributesProcessor#postProcess
方法,摘取如下:第 220 页第 1 段 末尾
因此@TransactionalService.name()与@Service.value()之间的关系被"Attribute Aliases and Overrides"一节定义为"隐性别名"
理解有误,官方对于"隐性别名"的说明是:可以看到,in one annotation 才是属性别名,@TransactionalService.name()与@Service.value() 显然不在同一个注解中。
我对「属性别名」和「属性覆盖」的理解总结如下: -「属性别名」只能发生在同一个注解内部 -「属性覆盖」只能发生在注解之间
另外,我还将这段时间的学习和理解记录在这篇文章中
https://github.com/justmehyp/note-spring-boot/blob/master/note/Annotation-Programming-Model.md
,不一定都正确,如有错误,还望帮忙提醒纠正,多谢多谢!