Spring Framework的誕生讓開發(fā)人員的工作從石器時(shí)代跨域到了工業(yè)時(shí)代,你是否還能記起手?jǐn)]Servlet和JDBC的歲月?,你是否還對(duì)Struts1以及Struts2莫名其妙的404錯(cuò)誤記憶猶新?從2004年3月Spring 1.0發(fā)布到至今,Spring的發(fā)展已經(jīng)走過了15個(gè)年頭,其創(chuàng)造的價(jià)值讓人矚目。今天,帶著這樣一個(gè)背景來(lái)梳理一下Spring Framework,Spring MVC和Spring Boot三者之間的區(qū)別。
我們使用Spring家族的系列產(chǎn)品這么長(zhǎng)時(shí)間,不禁會(huì)問這樣幾個(gè)問題:Spring Framework是什么?Spring MVC是什么?Spring Boot又是什么?它們被設(shè)計(jì)出來(lái)的目的是什么?
你需要了解的知識(shí)
在接下來(lái)的內(nèi)容中,將梳理這樣幾個(gè)知識(shí)點(diǎn):
- Spring Framework基本概述
- Spring Framework主要解決的問題是什么?
- Spring MVC基本概述
- Spring MVC主要解決的問題是什么?
- Spring Boot主要解決的問題是什么?
- Spring,Spring MVC和Spring Boot三者之間的區(qū)別是什么?
Spring Framework 解決了哪些核心問題?
當(dāng)你仔細(xì)思考這個(gè)問題的時(shí)候你會(huì)發(fā)現(xiàn),很多地方它都有滲透到,貌似一個(gè)Spring就可以撐起開發(fā)的半邊天,以至于很難一下子回答這個(gè)問題。那Spring Framework到底解決了哪些核心問題?
Spring Framework最重要也是最核心的特性是依賴注入。所有的Spring模塊的核心就是DI(依賴注入)或者IoC(控制反轉(zhuǎn))。
依賴注入或控制反轉(zhuǎn)是Spring Framework最大的特性,當(dāng)我們正確使用DI(依賴注入)或IoC時(shí),可以開發(fā)出一個(gè)高內(nèi)聚低耦合的應(yīng)用程序,而這一一個(gè)低耦合的應(yīng)用程序可以輕松的對(duì)其實(shí)施單元測(cè)試。這就是Spring Framework解決的最核心的問題。
無(wú)依賴注入
請(qǐng)考慮這一一個(gè)案例:UserAction依賴于UserService來(lái)獲取用戶信息,在沒有依賴注入的情況下,我們需要手動(dòng)在UserAction中實(shí)例化一個(gè)UserService對(duì)象,這樣的手工作業(yè)意味著UserAction和UserService必須精密的聯(lián)系在一起,才能正常工作。如果一個(gè)Action需要多個(gè)Service提供服務(wù),那實(shí)例化這些Service將是一個(gè)繁重的工作。下面我們給出一個(gè)不使用依賴注入的代碼片段加以說明:
UserService.java
public interface UserService{
User profile();
}
UserServiceImpl.java
public class UserServiceImpl implements UserService{
@Override
User profile(){
// TODO
}
}
UserAction.java
@RestController
public class UserAction{
private UserService userService = new UserServiceImpl();
// other services...
@GetMapping("/profile")
public User profile(){
return userService.profile();
}
}
引入依賴注入
引入依賴注入將會(huì)使整個(gè)代碼看起來(lái)很清爽。為了能夠開發(fā)出高內(nèi)聚低耦合的應(yīng)用程序,Spring Framework為我們做了大量的準(zhǔn)備工作。下面我們使用兩個(gè)簡(jiǎn)單的注解@Component和@Autowired來(lái)實(shí)現(xiàn)依賴注入。
- @Component : 該注解將會(huì)告訴Spring Framework,被此注解標(biāo)注的類需要納入到Bean管理器中。
- @Autowired : 告訴Spring Framework需要找到一與其類型匹配的對(duì)象,并將其自動(dòng)引入到所需要的類中。
在接下來(lái)的示例代碼中,我們會(huì)看到Spring Framework將為UserService創(chuàng)建一個(gè)Bean對(duì)象,并將其自動(dòng)引入到UserAction中。
UserService.java
public interface UserService{
User profile();
}
UserServiceImpl.java
@Component
public class UserServiceImpl implements UserService{
@Override
User profile(){
// TODO
}
}
UserAction.java
@RestController
public class UserAction{
@Autowired
private UserService userService;
// other services...
@GetMapping("/profile")
public User profile(){
return userService.profile();
}
}
對(duì)比上下兩部分的代碼,你是否發(fā)現(xiàn)了他們之間的區(qū)別?Action所依賴的Service的初始化工作全部交由Spring Framework來(lái)管理,我們只需要在適當(dāng)?shù)牡胤较騍pring Framework索取想要服務(wù)即可。這就好比當(dāng)我想要吃薯片的時(shí)候,我不需要自己親自種土豆,施肥,收獲...清洗,切片...一直到最后炸土豆片,想想都覺得累,而更簡(jiǎn)單的方法是直接去超市購(gòu)買自己想要的薯片即可。
Spring Framework還有其他的核心特性嗎?
#1:衍生的特性
Spring Framework的依賴注入是核心中的核心,在依賴注入核心特性的基礎(chǔ)上,Spring Framework還衍生出了很多的高級(jí)模塊:
- Spring JDBC
- Spring MVC
- Spring AOP
- Spring ORM
- Spring JMS
- Spring Test
對(duì)于這些新的高級(jí)模塊,可能會(huì)產(chǎn)生這一一個(gè)問題:它們是否是一個(gè)全新的功能?答案是否定的,在不使用Spring Framework的情況下,我們依然能夠使用JDBC連接數(shù)據(jù)庫(kù),依然能夠?qū)σ晥D和數(shù)據(jù)模型進(jìn)行控制,依然能夠使用第三方的ORM框架。那Spring Framework干了什么?Spring Framework站在巨人的肩膀上,對(duì)這些原生的模塊進(jìn)行了抽象,而抽象可以帶來(lái)這樣一些好處:
- 減少了應(yīng)用中模板代碼的數(shù)量
- 降低了原生框架的技術(shù)門檻
- 基于依賴注入特性,實(shí)現(xiàn)了代碼的解耦,真正的高內(nèi)聚、低耦合
- 更細(xì)粒度的單元測(cè)試
這樣的好處是顯而易見的,比如與傳統(tǒng)的JDBC相比,使用JDBCTemplate操作數(shù)據(jù)庫(kù),首先是代碼量小了,其次是我們不需要再面對(duì)恐怖的try-catch。
#2:優(yōu)秀的集成能力
Spring Framework還具備另外一個(gè)重要特性,那就是能夠快速的與其他三方框架進(jìn)行整合。與其自己造輪子,還不如想辦法將好的輪子整合在一起,我想這句話應(yīng)該可以用來(lái)概況Spring Framework這一特性。Spring Framework對(duì)于整合其他的框架,給出了不錯(cuò)的解決方案,下面將列舉一些常見的方案:
- 與Hibernate ORM框架整合
- 與MyBatis 對(duì)象映射框架整合
- 與Junit單元測(cè)試框架整合
- 與Log4J日志記錄框架整合
Spring MVC是什么?
Spring MVC提供了構(gòu)建Web應(yīng)用程序的全功能MVC模塊,實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式以及請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架,即采用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦?;谡?qǐng)求驅(qū)動(dòng)指的是使用請(qǐng)求-響應(yīng)模型,視圖與數(shù)據(jù)模型分離,以簡(jiǎn)化Web應(yīng)用的開發(fā)。
使用Spring MVC提供的Dispatcher Servlet,ModelAndView和ViewResolver等功能,可以輕松的開發(fā)出一個(gè)Web應(yīng)用程序。
Spring Boot出現(xiàn)的原因是什么?
我們都知道,使用Spring Framework來(lái)開發(fā)應(yīng)用程序,需要進(jìn)行大量的配置工作以及依賴包的管理,工作繁重而且極易出現(xiàn)配置錯(cuò)誤,尤為明顯的是依賴包之間的版本沖突問題。
舉一個(gè)簡(jiǎn)單的案例,當(dāng)我們使用Spring MVC來(lái)開發(fā)Web應(yīng)用程序時(shí),我們大致需要經(jīng)歷這樣幾個(gè)步驟:
-
1:配置組件掃描的包路徑
-
2:配置對(duì)應(yīng)的Servlet程序
-
3:配置視圖解析器
-
4:配置頁(yè)面模板引擎(JSP、Freemarker等)
下面給出了一個(gè)小范圍的舉例:
...
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/static/**" location="/static/"/>
...
此外,我們還需要配置先關(guān)的Servlet處理程序,它們大致是這樣的:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/todo-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
如果我們的應(yīng)用程序還需要鏈接數(shù)據(jù),則還需要配置數(shù)據(jù)源,實(shí)體對(duì)象管理器,事務(wù)管理器等眾多配置:
<bean id="datasource" class="">
...
</bean>
<bean id="entityManagerFactory" class="">
...
</bean>
<bean id="transactionManager" class="">
...
</bean>
...
面對(duì)眾多的配置文件,我們需要花費(fèi)大量的時(shí)間去處理,這時(shí)你可能會(huì)問,我為什么要花費(fèi)那么多的時(shí)間去管理Spring的配置工作?不是應(yīng)該專注于應(yīng)用本身的業(yè)務(wù)邏輯嗎?現(xiàn)在,有了Spring Boot,這些煩心事就不需要你去操心了。
#1:Spring Boot的自動(dòng)化配置能力
我為什么會(huì)把Spring Boot的自動(dòng)化配置能力放在第一位,因?yàn)樗鼧O大的降低了我們使用Spring Framework所付出的成本。這是Spring Boot的自動(dòng)化配置是一個(gè)最具價(jià)值的解決方案。
這難道不值得我們拍案叫好嗎?如果你想要開發(fā)一個(gè)Web應(yīng)用程序,你需要做的事情就是將Spring Boot Web包引入到項(xiàng)目的類路徑下,Spring Boot就可以幫你解決后續(xù)的大多數(shù)配置工作。
- 如果Hibernate的依賴被放到了類路徑上,Spring Boot會(huì)自動(dòng)配置數(shù)據(jù)源
- 如果Spring MVC的依賴被放到了類路徑上,Spring Boot又會(huì)自動(dòng)配置Dispatcher Servlet
當(dāng)Spring Boot檢測(cè)到有新的依賴包添加到類路徑上,Spring Boot會(huì)采用默認(rèn)的配置對(duì)新的依賴包進(jìn)行設(shè)置,如果我們想自己配置依賴包時(shí),只需要手動(dòng)覆蓋默認(rèn)的配置項(xiàng)即可。
- Spring Boot掃描類路徑上可用的框架信息
- 獲取應(yīng)用程序現(xiàn)有的配置信息
- 如果應(yīng)用程序沒有提供框架的配置信息,Spring Boot將采用默認(rèn)的配置來(lái)配置框架,這就是Spring Boot的自動(dòng)配置特性(Auto Configuration)
#2:Spring Boot Starter項(xiàng)目
在傳統(tǒng)模式的開發(fā)過程中,我們需要反復(fù)的確認(rèn)應(yīng)用程序所需要的第三方JAR包,以及這些JAR的版本和依賴關(guān)系。例如,現(xiàn)在我們打算開發(fā)一款Web應(yīng)用程序,應(yīng)用程序大概需要如下的一些依賴包:Spring MVC,Jackson Databind(用于數(shù)據(jù)綁定),Hibernate-Validator(用于服務(wù)端的數(shù)據(jù)校驗(yàn))和Log4j(用于日志記錄)?,F(xiàn)在,我們需要去下載對(duì)應(yīng)的jar包到應(yīng)用程序中,并且還需要處理依賴包之間版本沖突的問題。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.2.Final</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
這不是一件簡(jiǎn)單的事情,特別是發(fā)生版本沖突的時(shí)候,讓應(yīng)用程序能夠正常運(yùn)行起來(lái)就需要花費(fèi)一定的時(shí)間。
Spring Boot Starter是一組用于管理依賴關(guān)系的描述符,通過這些描述符,我們可以在應(yīng)用程序中輕松的管理依賴包,你可以以開箱即用的方式獲取想要的依賴包,而無(wú)需去Maven倉(cāng)庫(kù)總檢索對(duì)應(yīng)的依賴,并將依賴配置復(fù)制粘貼到應(yīng)用程序的pom文件中。例如,如果你想要使用Spring和JPA進(jìn)行數(shù)據(jù)庫(kù)訪問,只需要在pom中添加spring-boot-starter-data-jpa依賴項(xiàng)就可以。
現(xiàn)在,如果我們想要開發(fā)一個(gè)Web應(yīng)用程序,使用Spring Boot Starter Web依賴會(huì)是一個(gè)不錯(cuò)的選擇。我們可以通過使用Spring INitializr快速構(gòu)建一個(gè)Web應(yīng)用程序,并將Spring Boot Starter Web添加到項(xiàng)目中。此時(shí)我們的pom文件只需要很少的配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot Starter Web會(huì)為我們預(yù)裝如下的一些依賴:
- Spring : core,beans,context,aop
- Web MVC : Spring MVC
- Jackson : JSON Binding
- Validation : Hibernate Validator,Validation API
- Embedded Servlet Container: Tomcat
- Logging : logback,slf4j
對(duì)于開發(fā)人員而言,我們不需要去擔(dān)心這些依賴項(xiàng)的管理工作以及解決他們之間的兼容性問題,Spring Boot已經(jīng)幫我們解決了。
Spring Boot的核心目標(biāo)
Spring Boot的核心目標(biāo)在于快速實(shí)現(xiàn)生產(chǎn)就緒的應(yīng)用程序,這將包含這樣幾個(gè)部分:
- 執(zhí)行器 : 啟用高級(jí)監(jiān)控和跟蹤應(yīng)用程序功能
- 嵌入式服務(wù)器:Spring Boot已經(jīng)內(nèi)置了多個(gè)Web服務(wù)器,如Undertow,jetty,tomcat,因此我們不需要再額外的配置服務(wù)器,就可以完成應(yīng)用程序的調(diào)試工作。
- 默認(rèn)的異常處理機(jī)制
- 開箱即用的依賴項(xiàng)管理機(jī)制
- 自動(dòng)化配置
總結(jié)
通過上述的梳理,我們可以看到,Spring Framework是一個(gè)提供了DI(依賴注入)和IoC(控制反轉(zhuǎn))的開發(fā)框架,使用Spring Framework可以幫助我們開發(fā)出高內(nèi)聚,低耦合的應(yīng)用程序,Spring MVC是在Spring Framework基礎(chǔ)上發(fā)展出來(lái)的基于MVC模式的全功能Web開發(fā)框架,實(shí)現(xiàn)了Model,View和Controller之間的職責(zé)解耦;Spring Boot為我們提供了一個(gè)能夠快速使用Spring Framework的優(yōu)秀解決方案,通過最小化的配置,我們就可以使用Spring Framework,嚴(yán)格意義上講,Spring Boot并不是某種框架,它只是為開發(fā)人員提供了一個(gè)更好的更方便的使用Spring Framework的解決方案。
作者:譚朝紅
鏈接:(第二講)Spring&Spring MVC&Spring Boot三者之間的區(qū)別與聯(lián)系
來(lái)源:譚朝紅的技術(shù)分享博客