5、使用自动配置
资源编号:76575 Java Spring Boot实战 热度:38

``` 这个模板定义了一个HTML页面,该页面概念上分为两个部分:页面上方是读者的阅读列表 中的图书清单;下方是是一个表单,读者可以从这里添加新书。 为了美观,Thymeleaf模板引用了一个名为style.css的样式文件,该文件位于src/main/resources/ static目录中,看起来是这样的: ``` body { background-color: #cccccc; font-family: arial, helvetica, sans-serif; } .bookHeadline { font-size: 12pt; font-weight: bold; } .bookDescription { font-size: 10pt; } label { font-weight: bold; } ``` 这个样式表并不复杂,也没有过分追求让应用程序变漂亮,但已经能满足我们的需求了。很 快你就会看到,它能用来演示Spring Boot的自动配置功能。 不管你相不相信,以上就是一个完整的应用程序了——本章已经向你呈现了所有的代码。等 一下,回顾一下前几页的内容,你看到什么配置了吗?实际上,除了代码清单2-1里的三行配置 (这是开启自动配置所必需的),你不用再写任何Spring配置了。 虽然没什么Spring配置,但这已经是一个可以运行的完整Spring应用程序了。让我们把它运 行起来,看看会怎样。 # 2.3.2 运行应用程序 运行Spring Boot应用程序有几种方法。先前在2.5节里,我们讨论了如何通过Maven和Gradle 来运行应用程序,以及如何构建并运行可执行JAR。稍后,在第8章里你将看到如何构建WAR文 件,并用传统的方式部署到Java Web应用服务器里,比如Tomcat。 假设你正使用Spring Tool Suite开发应用程序,可以在IDE里选中项目,在Run菜单里选择Run As > Spring Boot App,通过这种方式来运行应用程序,如图2-3所示。 ![image.png](https://img.handsomemark.com/2020/04/30/55a0992a-8acf-11ea-995f-0242ac120007.png) 图2-3:在Spring Tool Suite里运行Spring Boot应用程序 2.3 使用自动配置 如果一切正常,你的浏览器应该会展现一个空白的阅读列表,下方有一个用于向列表添加新 书的表单,如图2-4所示。 ![image.png](https://img.handsomemark.com/2020/04/30/5e234a0c-8acf-11ea-9e5c-0242ac120007.png) 图2-4:初始状态下的空阅读列表 接下来,通过表单添加一些图书吧。随后你的阅读列表看起来就会像图2-5这样。 ![image.png](https://img.handsomemark.com/2020/04/30/698a95e4-8acf-11ea-b658-0242ac120007.png) 图2-5:添加了一些图书后的阅读列表 再多用用这个应用程序吧。你准备好之后,我们就来看一下Spring Boot是如何做到不写Spring 配置代码就能开发整个Spring应用程序的。 # 2.3.3 刚刚发生了什么 如我所说,在没有配置代码的情况下,很难描述自动配置。与其花时间讨论那些你不用做的 事情,不如在这一节里关注一下你要做的事——写代码。 当然,某处肯定是有些配置的。配置是Spring Framework的核心元素,必须要有东西告诉Spring 如何运行应用程序。 在向应用程序加入Spring Boot时,有个名为spring-boot-autoconfigure的JAR文件,其中包含了 很多配置类。每个配置类都在应用程序的Classpath里,都有机会为应用程序的配置添砖加瓦。这 些配置类里有用于Thymeleaf的配置,有用于Spring Data JPA的配置,有用于Spiring MVC的配置, 还有很多其他东西的配置,你可以自己选择是否在Spring应用程序里使用它们。 所有这些配置如此与众不同,原因在于它们利用了Spring的条件化配置,这是Spring 4.0引入 的新特性。条件化配置允许配置存在于应用程序中,但在满足某些特定条件之前都忽略这个配置。 在Spring里可以很方便地编写你自己的条件,你所要做的就是实现Condition接口,覆盖它 的matches()方法。举例来说,下面这个简单的条件类只有在Classpath里存在JdbcTemplate时 才会生效: ``` package readinglist; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class JdbcTemplateCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { try { context.getClassLoader().loadClass("org.springframework.jdbc.core.JdbcTemplate"); return true; } catch (Exception e) { return false; } } } ``` 当你用Java来声明Bean的时候,可以使用这个自定义条件类: ``` @Conditional(JdbcTemplateCondition.class) public MyService myService() { ... } ``` 在这个例子里,只有当JdbcTemplateCondition类的条件成立时才会创建MyService这个 Bean。也就是说MyService Bean创建的条件是Classpath里有JdbcTemplate。否则,这个Bean 2.3 使用自动配置的声明就会被忽略掉。 虽然本例中的条件相当简单,但Spring Boot定义了很多更有趣的条件,并把它们运用到了配 置类上,这些配置类构成了Spring Boot的自动配置。Spring Boot运用条件化配置的方法是,定义 多个特殊的条件化注解,并将它们用到配置类上。表2-1列出了Spring Boot提供的条件化注解。 表2-1 自动配置中使用的条件化注解 ![image.png](https://img.handsomemark.com/2020/04/30/f0046c8a-8acf-11ea-a6ba-0242ac120007.png) 一般来说,无需查看Spring Boot自动配置类的源代码,但为了演示如何使用表2-1里的注解, 我们可以看一下DataSourceAutoConfiguration里的这个片段(这是Spring Boot自动配置库 的一部分): ``` @Configuration @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @EnableConfigurationProperties(DataSourceProperties.class) @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class }) public class DataSourceAutoConfiguration { ... } ``` 如你所见,DataSourceAutoConfiguration添加了@Configuration注解,它从其他配 置类里导入了一些额外配置, 还自己定义了一些Bean。 最重要的是, DataSourceAutoConfiguration 上添加了 @ConditionalOnClass 注解, 要求Classpath里必须要有 DataSource 和 EmbeddedDatabaseType。如果它们不存在,条件就不成立,DataSourceAutoConfiguration 提供的配置都会被忽略掉。 DataSourceAutoConfiguration里嵌入了一个JdbcTemplateConfiguration类,自动 配置了一个JdbcTemplate Bean: ``` @Configuration @Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class) protected static class JdbcTemplateConfiguration { @Autowired(required = false) private DataSource dataSource; @Bean @ConditionalOnMissingBean(JdbcOperations.class) public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(this.dataSource); } ... } ``` JdbcTemplateConfiguration使用了@Conditional注解,判断DataSourceAvailableCondition条件是否成立——基本上就是要有一个DataSource Bean或者要自动配置创建一个。 假 设 有 DataSource Bean , 使 用 了 @Bean 注 解 的 jdbcTemplate() 方 法 会 配 置 一 个 JdbcTemplate Bean。这个方法上还加了@ConditionalOnMissingBean注解,因此只有在不 存在JdbcOperations(即JdbcTemplate实现的接口)类型的Bean时,才会创建JdbcTemplate Bean。 此处看到的只是DataSourceAutoConfiguration的冰山一角,Spring Boot提供的其他自 动配置类也有很多知识没有提到。但这已经足以说明Spring Boot如何利用条件化配置实现自动 配置。 自动配置会做出以下配置决策,它们和之前的例子息息相关。  因 为 Classpath 里 有 H2 , 所 以 会 创 建 一 个 嵌 入 式 的 H2 数 据 库 Bean , 它 的 类 型 是 javax.sql.DataSource,JPA实现(Hibernate)需要它来访问数据库。  因为Classpath里有Hibernate(Spring Data JPA传递引入的)的实体管理器,所以自动配置 会 配 置 与 Hibernate 相 关 的 Bean , 包 括 Spring 的 LocalContainerEntityManagerFactoryBean和JpaVendorAdapter。  因为Classpath里有Spring Data JPA,所以它会自动配置为根据仓库的接口创建仓库实现。  因为Classpath里有Thymeleaf, 所以Thymeleaf会配置为Spring MVC的视图, 包括一个 Thymeleaf的模板解析器、模板引擎及视图解析器。视图解析器会解析相对于Classpath根 目录的/templates目录里的模板。  因 为 Classpath 里 有 Spring MVC ( 归 功 于 Web 起 步 依 赖 ), 所 以 会 配 置 Spring 的 DispatcherServlet并启用Spring MVC。  因为这是一个Spring MVC Web应用程序,所以会注册一个资源处理器,把相对于Classpath 根目录的/static目录里的静态内容提供出来。(这个资源处理器还能处理/public、/resources 和/META-INF/resources的静态内容。)  因为Classpath里有Tomcat(通过Web起步依赖传递引用),所以会启动一个嵌入式的Tomcat 容器,监听8080端口。 由此可见,Spring Boot自动配置承担起了配置Spring的重任,因此你能专注于编写自己的应 用程序。 # 2.4 小结 通过Spring Boot的起步依赖和自动配置,你可以更加快速、便捷地开发Spring应用程序。起 步依赖帮助你专注于应用程序需要的功能类型,而非提供该功能的具体库和版本。与此同时,自 动配置把你从样板式的配置中解放了出来。这些配置在没有Spring Boot的Spring应用程序里非常 常见。 虽然自动配置很方便,但在开发Spring应用程序时其中的一些用法也有点武断。要是你在配 置Spring时希望或者需要有所不同,该怎么办?在第3章,我们将会看到如何覆盖Spring Boot自动 配置,借此达成应用程序的一些目标,还有如何运用类似的技术来配置自己的应用程序组件。