Spring Boot初探

Spring Boot初探

在Maven依賴中引入了spring-boot-starter-web,它包含了Spring Boot預定義的一些Web開發的常用依賴:

  • spring-webspring-webmvc Spring WebMvc框架
  • tomcat-embed-* 內嵌Tomcat容器
  • jackson 處理json數據
  • spring-* Spring框架
  • spring-boot-autoconfigure Spring Boot提供的自動配置功能

Java代碼中沒有任何配置,和傳統的Spring應用相比,多了兩個我們不認識的符號:

  • @EnableAutoConfiguration
  • SpringApplication

它們都是由Spring Boot框架提供。在SpringApplication.run()方法執行後,Spring Boot的autoconfigure發現這是一個Web應用(根據類路徑上的依賴確定),於是在內嵌的Tomcat容器中啓動了一個Spring的應用上下文,並且監聽默認的tcp端口8080(默認約定)。同時在Spring Context中根據默認的約定配置了Spring WebMvc:

  • Servlet容器默認的Context路徑是/
  • DispatherServlet匹配的路徑(servlet-mapping中的url-patterns)是/*
  • @ComponentScan路徑被默認設置爲SampleController的同名package,也就是該package下的所有@Controller@Service@Component@Repository都會被實例化後並加入Spring Context中。

沒有一行配置代碼、也沒有web.xml。基於Spring Boot的應用在大多數情況下都不需要我們去顯式地聲明各類配置,而是將最常用的默認配置作爲約定,在不聲明的情況下也能適應大多數的開發場景。

實例:數據庫訪問

除了最基本的Web框架,另一種非常普遍的開發場景是訪問數據庫。在傳統的Spring應用中,訪問數據庫我們需要配置:

  • 類路徑上添加數據庫訪問驅動
  • 實例化DataSource對象,指定數據庫urlusernamepassword等信息
  • 注入JdbcTemplate對象,如果使用HibernateMybatis等框架,還需要進一步配置框架信息

在Spring Boot中,上述過程會被簡化。首先在Maven項目依賴中定義:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

spring-boot-starter-web-jdbc引入了spring-jdbc依賴,h2是一個內存關係型數據庫。在引入了這些依賴並啓動Spring Boot應用程序後,autoconfigure發現spring-jdbc位於類路徑中,於是:

  • 根據類路徑上的JDBC驅動類型(這裏是h2,預定義了derbysqlitemysqloraclesqlserver等等),創建一個DataSource連接池對象,本例中的h2是內存數據庫,無需任何配置,如果是mysqloracle等類型的數據庫需要開發者配置相關信息。
  • 在Spring Context中創建一個JdbcTemplate對象(使用DataSource初始化)

接下來開發者的工作就非常簡單了,在業務邏輯中直接引入JdbcTemplate即可:

@Service
public class MyService {

    @Autowired
    JdbcTemplate jdbcTemplate;

}

除了spring-jdbc,Spring Boot還能夠支持JPA,以及各種NoSQL數據庫——包括MongoDB,Redis,全文索引工具elasticsearchsolr等等。

配置

Spring Boot最大的特色是“約定優先配置”,大量的默認配置對開發者十分的友好。但是在實際的應用開發過程中,默認配置不可能滿足所有場景,同時用戶也需要配置一些必須的配置項——例如數據庫連接信息。Spring Boot的配置系統能夠讓開發者快速的覆蓋默認約定,同時支持Properties配置文件和YAML配置文件兩種格式,默認情況下Spring Boot加載類路徑上的application.propertiesapplication.yml文件,例如:

spring.datasource.url=jdbc:postgresql://localhost/test
spring.datasource.username=postgres
spring.datasource.password=1234
spring.datasource.driver-class-name=org.postgresql.Driver

通過portaddress可以修改服務器監聽的地址和端口,sessionTimeout配置session過期時間(再也不用修改web.xml了,因爲它根本不存在)。同時如果在生產環境中使用內嵌Tomcat,當然希望能夠配置它的日誌、線程池等信息,這些現在都可以通過Spring Boot的屬性文件配置,而不再需要再對生產環境中的Tomcat實例進行單獨的配置管理了。

@EnableAutoCongiguration

從Spring 3.0開始,爲了替代繁瑣的XML配置,引入了@Enable...註解對@Configuration類進行修飾以達到和XML配置相同的效果。想必不少開發者已經使用過類似註解:

  • @EnableTransactionManagement開啓Spring事務管理,相當於XMl中的<tx:*>
  • @EnableWebMvc使用Spring MVC框架的一些默認配置
  • @EnableScheduling會初始化一個Scheduler用於執行定時任務和異步任務

Spring Boot提供的@EnableAutoCongiguration似乎功能更加強大,一旦加上,上述所有的配置似乎都被包含進來而無需開發者顯式聲明。它究竟是如何做到的呢,先看看它的定義:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ EnableAutoConfigurationImportSelector.class,
        AutoConfigurationPackages.Registrar.class })
public @interface EnableAutoConfiguration {

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     */
    Class<?>[] exclude() default {};

}

EnableAutoConfigurationImportSelector使用的是spring-core模塊中的SpringFactoriesLoader#loadFactoryNames()方法,它的作用是在類路徑上掃描META-INF/spring.factories文件中定義的類:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration

實際上這就是Spring Boot會自動配置的一些對象,例如前面提到的Web框架由EmbeddedServletContainerAutoConfiguration,DispatcherServletAutoConfigurationServerPropertiesAutoConfiguration等配置完成,而DataSource的自動配置則是由DataSourceAutoConfiguration完成。現在我們以Mongo的配置MongoAutoConfiguration爲例,來探索Spring Boot是如何完成這些配置的:

@Configuration
@ConditionalOnClass(Mongo.class)
@EnableConfigurationProperties(MongoProperties.class)
public class MongoAutoConfiguration {

    @Autowired
    private MongoProperties properties;

    private Mongo mongo;

    @PreDestroy
    public void close() throws UnknownHostException {
        if (this.mongo != null) {
            this.mongo.close();
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public Mongo mongo() throws UnknownHostException {
        this.mongo = this.properties.createMongoClient();
        return this.mongo;
    }

}

首先這是一個Spring的配置@Configuration,它定義了我們訪問Mongo需要的@Bean,如果這個@Configuration被Spring Context掃描到,那麼Context中自然也就有兩個一個Mongo對象能夠直接爲開發者所用。

但是注意到其它幾個Spring註解:

  • @ConditionOnClass表明該@Configuration僅僅在一定條件下才會被加載,這裏的條件是Mongo.class位於類路徑上
  • @EnableConfigurationProperties將Spring Boot的配置文件(application.properties)中的spring.data.mongodb.*屬性映射爲MongoProperties並注入到MongoAutoConfiguration中。
  • @ConditionalOnMissingBean說明Spring Boot僅僅在當前上下文中不存在Mongo對象時,纔會實例化一個Bean。這個邏輯也體現了Spring Boot的另外一個特性——自定義的Bean優先於框架的默認配置,我們如果顯式的在業務代碼中定義了一個Mongo對象,那麼Spring Boot就不再創建。

接下來看一看MongoProperties

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {

    private String host;
    private int port = DBPort.PORT;
    private String uri = "mongodb://localhost/test";
    private String database;

    // ... getters/ setters omitted
}

顯然,它就是以spring.data.mongodb作爲前綴的屬性,然後通過名字直接映射爲對象的屬性,同時還包含了一些默認值。如果不配置,那麼mongo.uri就是mongodb://localhost/test

Production特性

從前面的例子可以看出,Spring Boot能夠非常快速的做出一些原型應用,但是它同樣可以被用於生產環境。爲了添加生產環境特性支持,需要在Maven依賴中引入:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

加入actuator依賴後,應用啓動後會創建一些基於Web的Endpoint:

  • /autoconfig,用來查看Spring Boot的框架自動配置信息,哪些被自動配置,哪些沒有,原因是什麼。
  • /beans,顯示應用上下文的Bean列表
  • /dump,顯示線程dump信息
  • /health,應用健康狀況檢查
  • /metrics
  • /shutdown, 默認沒有打開
  • /trace
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章