2.3.3 刚才到底发生了什么?
正如我所说过的,当没有具体配置的时候,很难描述自动配置。所以没必要花时间讨论你不需要做的,这一节我们主要关注你所需要的是什么,或则说是编写应程序代码。
但是这里仍然有些配置存在,不是吗?配置是Spring框架的主要元素,你必须有一些配置告诉Spring如何运行你的应用。
当你添加SpringBoot到你的应用程序时,会有一个名为spring-boot-autoconfigure的jar文件,里面包含了多个配置类。每一个配置类会在你的应用的ClassPath下,会在适当的机会下为你的应用做配置。里边有Thymeleaf的配置,SpringDataJPA的配置,SpringMVC的配置还有许多其他的你可能或不可能添加到你的应用的配置中。
是什么让这一切配置特殊的,问题在于,它利用Spring有条件的配置支持,Spring4.0的对条件配置支持做了介绍,允许配置在可用的应用程序中,但除去有些条件满足需要被忽略的配置。
编写你的Spring条件配置变得容易了,因为只要你实现Condition接口中的matches()方法就可以了。比如,下面就一个简单的条件配置类,会仅当JdbcTemplate出现在Classpath中的时候会被创建对应的Bean。
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;
}
}
}
You can use this custom condition class when you declare beans in Java:
@Conditional(JdbcTemplateCondition.class)
public MyService myService() {
...
}
在这种情况下,MyService的Bean会被创建如果JdbcTemplateCondition通过的化。也就是说,MyserviceBean只有在JdbcTemplate存在在Classpath时会被创建。否则,bean的声明将会被忽略。
尽管条件配置在这里看起来已很容易配置了,SpringBoot还定义了许多有趣的注解可以应用他们到条件配置类中,来控制SpringBoot的自动配置。即SpringBoot会应用使用这些注解了条件配置类。表2-1就是SpringBoot主要提供的条件注解:
Table 2.1 Conditional annotations used in auto-configuration
Conditional annotation Configuration applied if...?
@ConditionalOnBean ...the specified bean has been configured
@ConditionalOnMissingBean ...the specified bean has not already been configured
@ConditionalOnClass ...the specified class is available on the classpath
@ConditionalOnMissingClass ...the specified class is not available on the classpath
@ConditionalOnExpression ...the given Spring Expression Language (SpEL) expression evaluates to true
@ConditionalOnJava ...the version of Java matches a specific value or range of versions
@ConditionalOnJndi ...there is a JNDI InitialContext available and optionally given JNDI locations exist
@ConditionalOnProperty ...the specified configuration property has a specific value
@ConditionalOnResource ...the specified resource is available on the classpath
@ConditionalOnWebApplication ...the application is a web application
@ConditionalOnNotWebApplication ...the application is not a web application
一般你不需要查看SpringBoot自动配置的相关类。但是为了介绍表2.1中的一些条件注解被使用,以下有些片段从Spring Boot的自动配置的库中摘抄出来(有关DataSourceAutoConfiguration的配置)。
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class
})
public class DataSourceAutoConfiguration {
...
}
正如你所见的,DataSourceAutoConfiguration是一个基于@Configuration注解的类,导入了额外的其他配置,也定义了自己的一些Bean。最重要的是DataSourceAutoConfiguration使用了@ConditionalOnClass指名需要DataSource和EmbeddedDatabaseType在classpath中提供。如果条件失败,DataSourceAutoConfiguration的其他任何配置都会被忽略。
在DataSourceAutoConfiguration有一个内部类用来提供JdbcTemplate的自动配置:
@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被提供和自动配置。@Bean注解在jdbcTemplate()上,以便提供jdbcTemplate的bean。不过由于@ConditionalOnMissingBean也配置在jdbcTemplate()上,仅当JdbcOperations(Jdbctemplate接口的实现)不存在的时候才会配置jdbcTemplate。
当然以上代码还说明了很多DataSourceAutoConfiguration的配置,如需要提供SpringBoot其他的配置类。以上知识让你简单了解下SpringBoot如何使用条件配置实现自动配置的。
以下配置的决定就是通过自动配置实现的,由于这些直接涉及到了我们的例子中,让我们来一起看看:
- Because H2 is on the classpath, an embedded H2 database bean will be created. This bean is of type javax.sql.DataSource , which the JPA implementation (Hibernate) will need to access the database.
- Because Hibernate Entity Manager is on the classpath (transitively via Spring Data JPA ), auto-configuration will configure beans needed to support working with Hibernate, including Spring’s LocalContainerEntityManagerFactory- Bean and JpaVendorAdapter .
- Because Spring Data JPA is on the classpath, Spring Data JPA will be configured to automatically create repository implementations from repository interfaces.
- Because Thymeleaf is on the classpath, Thymeleaf will be configured as a view option for Spring MVC , including a Thymeleaf template resolver, template engine, and view resolver. The template resolver is configured to resolve tem- plates from /templates relative to the root of the classpath.
Because Spring MVC is on the classpath (thanks to the web starter depen- dency), Spring’s DispatcherServlet will be configured and Spring MVC will be enabled.
Because this is a Spring MVC web application, a resource handler will be regis- tered to serve static content from /static relative to the root of the classpath. (The resource handler will also serve static content from /public, /resources, and / META-INF /resources).
- Because Tomcat is on the classpath (transitively referred to by the web starter dependency), an embedded Tomcat container will be started to listen on port 8080.
最后,你从这里学到最主要就是,SpringBoot的自动配置可以帮你去除Spring配置的负担,让你可以专注于编写你的应用程序代码。