Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了

2.1 快速入门工程

第一章的 HelloBookController 控制层中,在代码中以硬编码的方式使用字符串表示书信息。下面把书的信息作为属性,外化配置在 application.properties 。好处是将应用参数、业务参数或第三方参数等统一配置在应用配置文件中,避免配置侵入业务代码,达到可配置的方式,方便及时调整修改。

2.1.1 配置属性

新建工程命名为 chapter-2-spring-boot-config ,在 application.properties 中配置书名和作者,配置如下:

## 书信息demo.book.name=[Spring Boot 2.x Core Action]demo.book.writer=BYSocket

.properties 文件的每行参数被存储为一对字符串,即一个存储参数名称,被称为键;另一个为值。一般称为键值对配置。井号(#)或者英文状态下的叹号(!)作为第一行中第一个非空字符来表示该行的文本为注释。另外,反斜杠(\)用于转义字符。

Spring Boot 支持并推荐使用 YAML 格式的配置文件,将 application.properties 文件替换成 application.yml 文件,并配置相同的属性,配置如下:

## 书信息demo:    book:        name:《SpringBoot2.x核心技术实战-上基础篇》        writer:泥瓦匠BYSocket

YAML 是一个可读性高,用来表达数据序列的格式。表示键值对格式时,注意键和值由冒号及空白字符分开。强调下,空白字符是必须的,IDE 一般也会提示。两种配置方式都非常便捷,在开发中选择 .properties 或 .yml 文件配置。但如果两种配置文件同时存在的时候,默认优先使用 .properties 配置文件。YAML 与 .properties 配置文件对比如图 2-1 所示:

图 2-1 YAML 与 .properties 配置文件对比

注意:

在 application.properties 配置中文值,读取时会出现中文乱码问题。因为 Java .properties 文件默认编码方式是 iso-8859 ,Spring Boot 应用以 UTF-8 的编码方式读取,就导致出现乱码问题。

官方 Issue 中的解决方法是,将 .properties 文件中配置的中文值转义成 Unicode 编码形式。例如 demo.book.writer=泥瓦匠 应该配置成 demo.book.writer=\u6ce5\u74e6\u5320 。利用 IDEA properties 插件 或利用 Java 文件转码工具 native2ascii 来快速地进行转义。该工具有在线版实现,地址如下:

https://javawind.net/tools/native2ascii.jsp

2.1.2 创建属性类

在工程中新建包目录 demo.springboot.config ,并在目录中创建名为 BookProperties 的属性类,代码如下:

importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;/**

* 书属性

*/@ComponentpublicclassBookProperties{/**    * 书名    */@Value("${demo.book.name}")    privateStringname;/**    * 作者    */@Value("${demo.book.writer}")    privateStringwriter;// ... 省略 getter / setter 方法}

利用 @Component 注解定义了书的属性 Bean,并通过 @Value 注解为该 Bean 的成员变量(或者方法参数)自动注入 application.properties 文件的属性值。@Value 注解是通过 “${propName}” 的形式引用属性,propName 表示属性名称。

核心注解的知识点:

@Component 注解:

@Component 对类进行标注,职责是泛指组件 Bean ,应用启动时会被容器加载并加入容器管理。常见的 @Controller、@Service 、@Repository 是 @Component 的分类细化组件,分别对应控制层、服务层、持久层的 Bean。

@Value 注解:

@Value 对 Bean 的字段或者方法参数进行标注,职责是基于表达式给字段或方法参数设置默认属性值。通常格式是注解 + SpEL 表达式,如 @Value("SpEL 表达式")。

使用 @Vlaue 注解来引用属性值时,确保所引用的属性值在 application.properties 文件存在并且相对应匹配,否则会造成 Bean 的创建错误,引发 java.lang.IllegalArgumentException 非法参数异常。

2.1.3 获取属性

修改原有的 HelloBookController 类,通过注入的方式获取书属性 Bean 并返回。代码如下:

importdemo.springboot.config.BookProperties;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloBookController {    @AutowiredBookProperties bookProperties;    @GetMapping("/book/hello")    public String sayHello() {return"Hello, " +bookProperties.getWriter() + "iswriting"                +bookProperties.getName() + " !";    }}

通过 @Autowired 注解标记在 BookProperties 字段,控制层自动装配属性 Bean 并使用。默认情况下要求被注解的 Bean 必须存在,需要允许 NULL 值,可以设置其 required 属性为 false: @Autowired(required = false)。

2.1.4 运行工程

执行 ConfigApplication 类启动,在控制台看到成功运行的输出后,打开浏览器访问 /book/hello 地址,可以看到如图 2-2 所示的返回结果:

正在上传... 取消

图 2-2 Hello Book 页面

也可以通过单元测试的方式验证属性获取是否成功,单元测试具体相关的会在第 9 章节介绍。单元测试代码如下:

importdemo.springboot.config.BookProperties;importorg.junit.Assert;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTestpublicclassConfigApplicationTests{@AutowiredBookPropertiesbookProperties;@Testpublicvoid testBookProperties() {Assert.assertEquals(bookProperties.getName(),"'Spring Boot 2.x Core Action'");Assert.assertEquals(bookProperties.getWriter(),"BYSocket");}}

2.2 配置属性的获取方式

配置属性的常用获取方式有基于 @Value 和 @ConfigurationProperties 注解两种方式。两种方式适合的场景不同,下面具体介绍其使用方法和场景。

2.2.1 @Value 注解

@Value 注解对 Bean 的变量或者方法参数进行标注,职责是基于表达式给字段或方法参数设置默认属性值。通常格式是注解 + SpEL 表达式,如 @Value("SpEL 表达式"),并标注在对应的字段或者方法上方,且必须对变量一一标注。这种方式适用于小而不复杂的属性结构。属性结构复杂,字段很多的情况下,这种方式会比较繁琐,应该考虑使用 @ConfigurationProperties 注解。

另外通过 @PropertySource 注解引入对应路径的其他 .properties 文件。将书信息重新配置在 classpath 下新的 book.properties 配置文件后,读取新配置文件的代码如下:

importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.PropertySource;importorg.springframework.stereotype.Component;/**

* 书属性

*/@Component@PropertySource("classpath:book.properties")publicclassBookProperties{/**    * 书名    */@Value("${demo.book.name}")    privateStringname;/**    * 作者    */@Value("${demo.book.writer}")    privateStringwriter;// ... 省略 getters / setters 方法}

2.2.2 @ConfigurationProperties 注解

在包目录 demo.springboot.config 中创建名为 BookComponent 的属性类,并使用 @ConfigurationProperties 注解获取属性,代码如下:

importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;/**

* 书属性

*

*/@Component@ConfigurationProperties(prefix="demo.book")publicclassBookComponent{/**

    * 书名

    */privateStringname;/**

    * 作者

    */privateStringwriter;// ... 省略 getters / setters 方法}

类似 @Value 注解方式,使用 @ConfigurationProperties(prefix = "demo.book") 注解标注在类上方可以达到相同的效果。 @ConfigurationProperties 注解的 prefix 是指定属性的参数名称。会匹配到配置文件中 “ demo.book.* ” 结构的属性,星号 “ * ” 是指会一一对应匹配 BookComponent 类的字段名。例如,字段 name 表示书名,会匹配到 demo.book.name 属性值。

@Value 注解方式强制字段必须对应在配置文件, @ConfigurationProperties 注解方式则不是必须的。一般情况下,所有字段应该保证一一对应在配置文件。如果没有属性值对应的话,该字段默认为空, @ConfigurationProperties 注解方式也不会引发任何异常,Spring Boot 推荐使用 @ConfigurationProperties 注解方式获取属性。

同样使用单元测试验证获取属性是否成功。单元测试代码如下:

@AutowiredBookComponent bookComponent;@Testpublic void testBookComponent() {Assert.assertEquals(bookComponent.getName(),"'Spring Boot 2.x Core Action'");Assert.assertEquals(bookComponent.getWriter(),"BYSocket");}

API org.springframework.boot.context.properties.ConfigurationProperties 注解参数

prefix

字符串值,绑定该名称前缀的属性对象。

value

字符串值,功能同 prefix 参数。

ignoreInvalidFields

布尔值,默认 false。绑定对象时,忽略无效字段。

ignoreUnknownFields

布尔值,默认 true。绑定对象时,忽略未知字段。

2.2.3 @ConfigurationProperties 数据验证

@ConfigurationProperties 注解方式支持验证功能,即当属性类被 @Validated 注解标注时,Spring Boot 初始化时会验证类的字段。在类的字段上添加 JSR-303 约束注解,进行数据验证。下面为书属性字段添加非 NULL 和字符串非空约束,代码如下:

importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;importorg.springframework.validation.annotation.Validated;importjavax.validation.constraints.NotEmpty;importjavax.validation.constraints.NotNull;/**

* 书属性

*

*/@Component@ConfigurationProperties(prefix="demo.book")@ValidatedpublicclassBookComponent{/**

    * 书名

    */@NotEmptyprivateStringname;/**

    * 作者

    */@NotNullprivateStringwriter;// ... 省略 getters / setters 方法}

龙华大道1号http://www.kinghill.cn/Dynamics/2106.html

你可能感兴趣的:(Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了)