-
Notifications
You must be signed in to change notification settings - Fork 792
Description
小马哥这本书写的很好,使我收益匪浅,同时也很钦佩小马哥技术造诣之高。
最近看到 第 7 章「走向注解驱动编程(Annotation-Driven)」,很多之前稀里糊涂的地方,在书的指引下,加上动手试验和阅读相关资料之后,豁然开朗。
好了,开始提 Bug 吧 :》
我手上的书版次是:2019年3月第1版,印次是:2019年4月第2次印刷。
第 211 页第 1 段,关于“显性覆盖”,文档中并没有确认指出属性A和B是否在同一个注解中 是理解有误的,官方原文如下:
Explicit Overrides: if attribute A is declared as an alias for attribute B in a meta-annotation via @AliasFor, then A is an explicit override for 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 的几个版本,都无法重现。
书上的运行结果是不会报错,会输出:
Bean 名称: txManager, 对象: thinking.in.spring.boot.samples.spring5.bean.TransactionalServiceBean@52e6fdee
保存...
txManager2: 事务提交...
但我却抛异常了:
beanName: transactionalServiceBean, bean: com.example.springboot.annotationattribute.TransactionalServiceBean@1672fe87
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: txManager,txManager2
我的代码如下:
TransactionalServiceBootstrap.java
@Configuration
@ComponentScan
@EnableTransactionManagement
public class TransactionalServiceBootstrap {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(TransactionalServiceBootstrap.class);
ac.getBeansOfType(TransactionalServiceBean.class).forEach((beanName, bean) -> {
System.out.println("beanName: " + beanName + ", bean: " + bean);
bean.save();
});
}
@Bean("txManager")
public PlatformTransactionManager txManager() {
return new PlatformTransactionManager() {
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
return new SimpleTransactionStatus();
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
System.out.println("txManager commit.");
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
System.out.println("txManager rollback.");
}
};
}
@Bean("txManager2")
public PlatformTransactionManager txManager2() {
return new PlatformTransactionManager() {
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
return new SimpleTransactionStatus();
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
System.out.println("txManager2 commit.");
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
System.out.println("txManager2 rollback.");
}
};
}
}
@TransactionalService
class TransactionalServiceBean {
public void save() {
System.out.println("saving...");
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Transactional
@Service("transactionalService")
@interface TransactionalService {
String name() default "";
String value() default "txManager";
}实际上,无法重现,是符合我的预期的,因为 Spring 对 属性 value 做了特殊对待,「隐性覆盖」对 value 不起作用, Spring 源码位置见org.springframework.core.annotation.AnnotatedElementUtils.MergedAnnotationAttributesProcessor#postProcess 方法,摘取如下:
// Implicit annotation attribute override based on convention
else if (!AnnotationUtils.VALUE.equals(attributeName) && attributes.containsKey(attributeName)) {
overrideAttribute(element, annotation, attributes, attributeName, attributeName);
}
第 220 页第 1 段 末尾 因此@TransactionalService.name()与@Service.value()之间的关系被"Attribute Aliases and Overrides"一节定义为"隐性别名" 理解有误,官方对于"隐性别名"的说明是:
Implicit Aliases: if two or more attributes in one annotation are declared as explicit overrides for the same attribute in a meta-annotation via @AliasFor, they are implicit aliases.
可以看到,in one annotation 才是属性别名,@TransactionalService.name()与@Service.value() 显然不在同一个注解中。
我对「属性别名」和「属性覆盖」的理解总结如下:
-「属性别名」只能发生在同一个注解内部
-「属性覆盖」只能发生在注解之间
另外,我还将这段时间的学习和理解记录在这篇文章中https://github.com/justmehyp/note-spring-boot/blob/master/note/Annotation-Programming-Model.md,不一定都正确,如有错误,还望帮忙提醒纠正,多谢多谢!