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 的声明就会被忽略掉。
虽然本例中的条件相当简单,但 Spring Boot 定义了很多更有趣的条件,并把它们运用到了配置类上,这些配置类构成了 Spring Boot 的自动配置。Spring Boot 运用条件化配置的方法是,定义多个特殊的条件化注解,并将它们用到配置类上。表 2-1 列出了 Spring Boot 提供的条件化注解。
表 2-1 自动配置中使用的条件化注解
条件化注解 | 配置生效条件 |
---|---|
| 配置了某个特定 Bean |
| 没有配置特定的 Bean |
| Classpath 里有指定的类 |
| Classpath 里缺少指定的类 |
| 给定的 Spring Expression Language(SpEL)表达式计算结果为 |
| Java 的版本匹配特定值或者一个范围值 |
| 参数中给定的 JNDI 位置必须存在一个,如果没有给参数,则要有 JNDI |
| 指定的配置属性要有一个明确的值 |
| Classpath 里有指定的资源 |
| 这是一个 Web 应用程序 |
| 这不是一个 Web 应用程序 |
一般来说,无需查看 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 的重任,因此你能专注于编写自己的应用程序。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论