印次:2019 年 5 月第 3 次印刷 的几处修改建议
ReionChan opened this issue · 0 comments
ReionChan commented
《Spring Boot 编程**》勘误
- 所购书籍印刷批次信息
- 版次:
2019 年 3 月第 1 版
- 印次:
2019 年 5 月第 3 次印刷
- 版次:
【第 71 页】 Servlet 规范 Jetty 容器版本支持
Servlet 规范 Jetty
- 4.0 9.x
+ 4.0 10.x
- 3.1 8.x
+ 3.1 9.x
- 3.0 7.x
+ 3.0 8.x
- 资料参考
【第 153、154 页】 几处 元素 应为 属性
- 第三个表格
Spring 注解 场景说明
- @Primary 替换 XML 元素 <bean primary="true|false">
+ @Primary 替换 XML 属性 <bean primary="true|false">
- @Role 替换 XML 元素 <bean role="...">
+ @Role 替换 XML 属性 <bean role="...">
- 第六个表格
Spring 注解 场景说明
- @PostConstruct 替换 XML 元素 <bean init-method="..."> 或 InitializingBean
+ @PostConstruct 替换 XML 属性 <bean init-method="..."> 或 InitializingBean
- @PreDestroy 替换 XML 元素 <bean destroy-method="..."> 或 DisposableBean
+ @PreDestroy 替换 XML 属性 <bean destroy-method="..."> 或 DisposableBean
【第 159 页】排版问题 scan 前多了空格
- 正文第一段第一行:
- 并使用 <context:component- scan /> 元素扫
+ 并使用 <context:component-scan /> 元素扫
【第 209 页】AnnotationAttributes 扩展 LinkedHashMap 目的论述存在歧义
- 正文第一段第三行:
- 又要确保其顺序保持与属性方法声明一致。
+ 又要确保其顺序保持与 Class#getDeclaredMethods 方法返回的数组顺序一致。
属性方法声明 :有人(包括我)误认为是 注解类的属性方法 在 源代码里声明顺序。
除上面绿色修改建议外,另一完全使用中文描述候选建议方案:
+ 又要确保其顺序保持与运行时反射加载的属性方法数组顺序一致。
- 修改原由
当把 属性方法声明顺序 误认为是属性方法在源代码中声明的顺序时,实际代码验证这种理解是错的。而真正 属性方法声明顺序 是与注解的 Class 对象调用 getDeclaredMethods()
方法返回的 Method[]
数组顺序一致。
下面的源代码可以支持这一论点:
public abstract class AnnotationUtils {
static AnnotationAttributes retrieveAnnotationAttributes(@Nullable Object annotatedElement, Annotation annotation,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
Class<? extends Annotation> annotationType = annotation.annotationType();
AnnotationAttributes attributes = new AnnotationAttributes(annotationType);
// Class#getDeclaredMethods() 方法数组顺序借由 List<Method> 传递到此
for (Method method : getAttributeMethods(annotationType)) {
try {
Object attributeValue = method.invoke(annotation);
Object defaultValue = method.getDefaultValue();
if (defaultValue != null && ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
attributeValue = new DefaultValueHolder(defaultValue);
}
// attributes 由于是 LinkedHashMap 的扩展,故此处 put 插入顺序得以和 Class#getDeclaredMethods() 保持一致
attributes.put(method.getName(),
adaptValue(annotatedElement, attributeValue, classValuesAsString, nestedAnnotationsAsMap));
}
catch (Throwable ex) {
if (ex instanceof InvocationTargetException) {
Throwable targetException = ((InvocationTargetException) ex).getTargetException();
rethrowAnnotationConfigurationException(targetException);
}
throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex);
}
}
return attributes;
}
static List<Method> getAttributeMethods(Class<? extends Annotation> annotationType) {
// 第一次执行跳过缓存
List<Method> methods = attributeMethodsCache.get(annotationType);
if (methods != null) {
return methods;
}
methods = new ArrayList<>();
// 此处收集的属性方法列表,顺序来源于 Class#getDeclaredMethods()
for (Method method : annotationType.getDeclaredMethods()) {
if (isAttributeMethod(method)) {
ReflectionUtils.makeAccessible(method);
methods.add(method);
}
}
attributeMethodsCache.put(annotationType, methods);
return methods;
}
}
而之所以属性方法顺序不会与源代码中属性方法顺序一致,根源是 Class#getDeclaredMethods 方法返回的 Method[]
数组元素顺序的不确定性。
以下引用该方法的 JavaDoc 注释:
The elements in the returned array are not sorted and are not in any particular order.
/**
* <p> The elements in the returned array are not sorted and are not in any
* particular order.
*
* @jls 8.2 Class Members
* @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
...
}
【第 294 页】词语颠倒
- 正文最后一行:
- 该引导类在启动秒后数,抛出以下异常:
+ 该引导类在启动数秒后,抛出以下异常:
【第 330 页】单词黏连、拆开后中间加一个 “的” 表示 @AutoConfigureBefore @AutoConfigureAfter 两者的 name 属性
- 正文倒数第三行:
- 建议尽可能地使用 @AutoConfigureBefore 或 @AutoConfigureAftername() 属性方法,
+ 建议尽可能地使用 @AutoConfigureBefore 或 @AutoConfigureAfter 的 name()属性方法,
【第 538 页】缺少 Boot 单词
- 正文最后一行:
- Spring 1.4 开始,将它们重构至
+ Spring Boot 1.4 开始,将它们重构至
【第 558 页】SpringApplication 的 run(String... ) 方法调用 handleRunFailure 多了一个参数
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
context = createAndRefreshContext(listeners, applicationArguments);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
// 此处多了 analyzers 参数
// handleRunFailure(context, listeners, analyzers, ex);
// 应替换为下面的调用
handleRunFailure(context, listeners, ex);
throw new IllegalStateException(ex);
}
}