mercyblitz/thinking-in-spring-boot-samples

印次:2019 年 5 月第 3 次印刷 的几处修改建议

ReionChan opened this issue · 0 comments

《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);
		}
}