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配置的负担,让你可以专注于编写你的应用程序代码。

results matching ""

    No results matching ""