Spring Boot——開發新一代Spring應用
Spring官方網站本身使用Spring框架開發,隨著功能以及業務邏輯的日益複雜,應用伴隨著大量的XML配置檔案以及複雜的Bean依賴關係。隨著Spring 3.0的釋出,Spring IO團隊逐漸開始擺脫XML配置檔案,並且在開發過程中大量使用“約定優先配置”(convention over configuration)的思想來擺脫Spring框架中各類繁複紛雜的配置(即時是Java Config)。
Spring Boot正是在這樣的一個背景下被抽象出來的開發框架,它本身並不提供Spring框架的核心特性以及擴充套件功能,只是用於快速、敏捷地開發新一代基於Spring框架的應用程式。也就是說,它並不是用來替代Spring的解決方案,而是和Spring框架緊密結合用於提升Spring開發者體驗的工具。同時它集成了大量常用的第三方庫配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot應用中這些第三方庫幾乎可以零配置的開箱即用(out-of-the-box),大部分的Spring Boot應用都只需要非常少量的配置程式碼,開發者能夠更加專注於業務邏輯。
Hello World
傳統基於Spring的Java Web應用,需要配置web.xml
, applicationContext.xml
,將應用打成war包放入應用伺服器(Tomcat,
Jetty等)中並執行。如果基於Spring Boot,這一切都將變得簡單:
以Maven專案為例,首先引入Spring Boot的開發依賴:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId >
<version>1.2.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
編寫一個類包含處理HTTP請求的方法以及一個main()
@Controller
@EnableAutoConfiguration
public class SampleController {
@RequestMapping("/")
@ResponseBody
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleController.class, args);
}
}
啟動main函式後,在控制檯中可以發現啟動了一個Tomcat容器,一個基於Spring MVC的應用也同時啟動起來,這時訪問http://localhost:8080
就可以看到Hello
World!
出現在瀏覽器中了。
Spring Boot初探
在Maven依賴中引入了spring-boot-starter-web
,它包含了Spring
Boot預定義的一些Web開發的常用依賴:
spring-web
,spring-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
物件,指定資料庫url
,username
,password
等資訊 - 注入
JdbcTemplate
物件,如果使用Hibernate
,Mybatis
等框架,還需要進一步配置框架資訊
在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
,預定義了derby
,sqlite
,mysql
,oracle
,sqlserver
等等),建立一個DataSource
連線池物件,本例中的h2
是記憶體資料庫,無需任何配置,如果是mysql
,oracle
等型別的資料庫需要開發者配置相關資訊。 - 在Spring Context中建立一個
JdbcTemplate
物件(使用DataSource
初始化)
接下來開發者的工作就非常簡單了,在業務邏輯中直接引入JdbcTemplate
即可:
@Service
public class MyService {
@Autowired
JdbcTemplate jdbcTemplate;
}
除了spring-jdbc
,Spring Boot還能夠支援JPA,以及各種NoSQL資料庫——包括MongoDB,Redis,全文索引工具elasticsearch
, solr
等等。
配置
Spring Boot最大的特色是“約定優先配置”,大量的預設配置對開發者十分的友好。但是在實際的應用開發過程中,預設配置不可能滿足所有場景,同時使用者也需要配置一些必須的配置項——例如資料庫連線資訊。Spring Boot的配置系統能夠讓開發者快速的覆蓋預設約定,同時支援Properties配置檔案和YAML配置檔案兩種格式,預設情況下Spring Boot載入類路徑上的application.properties
或application.yml
檔案,例如:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
YAML格式更加簡潔:
spring:
datasource:
url: jdbc:mysql://localhost/test
username: dbuser
password: dbpass
driver-class: com.mysql.jdbc.Driver
一旦發現這些資訊,Spring Boot就會根據它們建立DataSource
物件。另一個常見的配置場景是Web應用伺服器:
# Server settings (ServerProperties)
server:
port: 8080
address: 127.0.0.1
sessionTimeout: 30
contextPath: /
# Tomcat specifics
tomcat:
accessLogEnabled: false
protocolHeader: x-forwarded-proto
remoteIpHeader: x-forwarded-for
basedir:
backgroundProcessorDelay: 30 # secs
通過port
和address
可以修改伺服器監聽的地址和埠,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
, DispatcherServletAutoConfiguration
,ServerPropertiesAutoConfiguration
等配置完成,而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
總結
Spring Boot是新一代Spring應用的開發框架,它能夠快速的進行應用開發,讓人忘記傳統的繁瑣配置,更加專注於業務邏輯。現在Spring官方文件中所有的Guide中的例子都是使用Spring Boot進行構建,這也是一個學習Spring, Spring Boot非常好的地方。如果想