通過優銳課核心java學習筆記中,我們可以看到,碼了很多專業的相關知識, 分享給大家參考學習。
帶有Spring Web示例的控件反轉和依賴注入的教程簡介
在21世紀初出現的基於組件的框架中,Spring也許是最好的。 它極大地改善了開發人員在基於Java的應用程序中編寫和交付基礎結構代碼的方式。 自成立以來,Spring被公認為是企業Java開發的領先框架。 作為端到端的應用程序框架,Spring反映了Java EE的某些功能,但它提供了功能和編程約定的組合,這些在其他地方都找不到。
本文介紹了Spring及其核心編程哲學和方法:控制反轉和依賴注入。 你還將開始使用Spring批注和一些動手的編碼示例。
依賴注入和控制反轉
Spring的核心思想是,你可以將它們卸載到框架中,而不是自己管理對象關系。 控制反轉(IOC)是用於管理對象關系的方法。 依賴注入是實現IOC的機制。 由於這兩個概念相關但不同,因此讓我們更仔細地考慮它們:
- ·控制反轉(IOC)的名稱恰如其分:它反轉了用於實現對象關系的傳統控制層次結構。 關系不是由應用程序代碼定義對象之間如何關聯的,而是由框架定義的。 作為一種方法,IOC為對象關系引入了一致性和可預測性,但是它確實要求你(作為開發人員)放棄一些細粒度的控制。
- ·依賴項注入(DI)是一種機制,框架可以將依賴項“注入”到你的應用程序中。 這是IOC的實際實施。 從某種意義上說,依賴注入取決於多態性,它允許根據框架中的配置更改引用類型的實現。 該框架注入變量引用,而不是在應用程序代碼中手動實現它們。
JSR-330
像Java世界中的許多地方一樣,Spring最初是作為一種狂放的創新而開始的,一部分已被標准規范所吸收。 在這種情況下,JSR-330是Java標准。 關於JSR-330規范的好處是,你可以在其他地方使用它,並將在Spring之外的其他地方看到它的使用。 你可以不使用Spring而使用它。 但是,Spring給桌面帶來了更多的好處。
示例1:Spring依賴項注入
通過使用它們可以最好地理解控制反轉和依賴注入,因此我們將以一個快速的編程示例開始。
假設你正在為汽車建模。 如果你使用普通的Java建模,那么Car類上可能有一個接口成員來引用Engine接口,如清單1所示。
清單1.普通的舊Java中的對象關系
public Interface Engine() { ... }
public class Car {
private Engine engine;
public Engine getEngine() { ... }
public void setEngine(Engine engine) { ... }}
清單1包含一個Engine類型的接口和一個具體Car類型的類,該類引用了Engine。 (請注意,在實際的編程場景中,這些文件將放在單獨的文件中。)現在,當你創建Carinstance時,你將設置關聯,如清單2所示。
清單2.使用Engine界面創建汽車
// ...Car newCar = new Car();Engine sixCylEngine = new InlineSixCylinderEngine();
newCar.setEngine(sixCylEngine );// Do stuff with the car
請注意,你首先創建了Car對象。 然后,你創建一個滿足Engine接口的新對象,並將其手動分配給Car對象。 這就是對象關聯在普通的舊Java中的工作方式。
在Spring中建模類和對象
現在讓我們看一下Spring中的相同示例。 在這里,你可以執行清單3中所示的操作。你從Car類開始,但是在這種情況下,你向其添加了一個注釋:@Inject。
清單3.在Spring中使用@Inject批注的示例
public class Car {
@Inject
private Engine engine;
// ...}
使用@Inject批注(或@Autowired,如果你願意的話)告訴Spring根據一組規則搜索上下文並將對象自動注入到引用中。
接下來,考慮清單4所示的@Component注釋。
清單4. @Component批注
@Componentpublic class InlineSixCylinderEngine implements Engine{
//...}
用@Component注釋類告訴Spring它可用於完成注入。 在這種情況下,將插入InlineSixCylEngine,因為它可用並且滿足關聯的接口要求。 在春季,這稱為“自動接線”注射。 (有關Spring的@Autowired注釋的更多信息,請參見下文。)
解耦作為設計原則
帶有依賴項注入的控件倒置從代碼中刪除了具體的依賴項源。 程序中無處沒有對引擎實現的硬編碼引用。 這是作為軟件設計原理的解耦示例。 將應用程序代碼與實現分離開來可使你的代碼更易於管理和維護。 該應用程序不太了解其各個部分如何組合在一起,但是在應用程序生命周期的任何時候進行更改要容易得多。
@Autowired vs @Inject
@Autowired和@Inject做同樣的事情。 但是,@ Inject是Java標准注釋,而@Autowired是特定於Spring的。 它們都具有相同的目的,即告訴DI引擎使用匹配的對象注入字段或方法。 你可以在Spring中使用任何一個。
Spring框架概述
現在,你已經看到了一些Spring代碼,讓我們來概述一下框架及其組件。 如你所見,該框架包含四個主要模塊,這些模塊分為多個包。 Spring將為你使用的模塊提供相當大的靈活性
- 核心容器
- 核心
- 豆
- 語境
- 表達語言
- 面向方面的編程(AOP)
- 行動計划
- 方面
- 儀器儀表
- 資料存取與整合
- JDBC
- JPA / ORM
- JMS
- 交易次數
- 網頁
- 網絡/ REST
- Servlet
- 支柱
讓我們開始使用兩個更常用的Spring功能,而不是在這里介紹所有內容。
啟動一個新項目:Spring Boot
我們將使用Spring Boot創建一個示例項目,以用於演示Spring功能。 Spring Boot使啟動新項目變得更加容易,你將自己看到。 首先,請看下面顯示的主類。 在Spring Boot中,我們可以使用具有main()方法的主類,然后選擇獨立運行它,或者選擇打包運行在Tomcat之類的容器中。
清單5列出了我們的主類的概述,它們將位於標准的src / main / java / hello位置。
清單5. Spring Boot的主類
package hello;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublic class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
請注意上述代碼的兩件事:首先,所有工作都抽象到框架中。 主類會啟動應用程序,但它對應用程序的工作方式或功能一無所知。 其次,SpringApplication.run()完成啟動應用程序並傳遞Application類本身的實際工作。 同樣,應用程序所做的工作在這里並不明顯。
@SpringBootApplication注釋包裝了一些標准注釋,並告訴Spring查看組件主類所在的包。 在我們之前的示例中,對於汽車和發動機,這將允許Spring查找所有帶有@Component和@Inject注釋的類。 該過程本身稱為組件掃描,可高度自定義。
你可以使用標准的mvn全新安裝來構建應用程序,並且可以使用Spring Boot目標(mvn spring-boot:run)運行該應用程序。 在此之前,讓我們看一下該應用程序的pom.xml文件。
清單6.入門pom.xml
<groupId>com.javaworld</groupId>
<artifactId>what-is-spring</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependencies>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
請注意上述代碼中的兩個重要功能:
- 1.父元素依賴於spring-boot-starter-parent項目。 該父項目定義了許多有用的默認值,例如JDK 1.8的默認編譯器級別。 在大多數情況下,你可以相信它知道自己在做什么。 例如,你可以忽略許多常見依賴項的版本號,並且SpringBootParent會將版本設置為兼容。 當你增加父級的版本號時,依賴項版本和默認值也會更改。
- 2. spring-boot-maven-plugin允許可執行JAR / WAR打包和就地運行(通過mvn spring-boot:run命令)。
將Spring Web添加為依賴項
到目前為止,我們已經能夠使用spring-boot來限制為啟動和運行應用程序而進行的工作量。 現在讓我們添加一個依賴項,看看我們能多快地在瀏覽器中獲取內容。
清單7.將Spring Web添加到項目
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId></dependency>
Note
Spring將自動檢測哪些文件已更改並相應地進行編譯。 你只需執行mvn spring-boot:run即可進行更改。
既然我們已經完成了基本的項目設置,就可以為兩個示例做好准備了。
示例2:使用Spring Web構建RESTful端點
我們已經使用spring-boot-starter-web引入了一些對構建Web應用程序有用的依賴項。 接下來,我們將為URL路徑創建路由處理程序。 Spring的Web支持是Spring MVC(Model-View-Controller)模塊的一部分,但請不要擔心:Spring Web也為構建RESTful端點提供了全面而有效的支持。
用來處理URL請求的類稱為控制器,如清單8所示。
清單8. Spring MVC REST控制器
package hello;
import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RequestParam;
@Controllerpublic class GreetingController {
@RequestMapping(value = "/hi", method = RequestMethod.GET)
public String hi(@RequestParam(name="name", required=false, defaultValue="JavaWorld") String name, Model model) {
return "Hello " + name;
}
}
@Controller批注
@Controller注釋將一個類標識為控制器。 標記為控制器的類也將自動識別為組件類,這使其成為自動裝配的候選對象。 無論何時需要此控制器,都將其插入框架。 在這種情況下,我們將其插入MVC系統以處理請求。
控制器是一種特殊的組件。 它支持你在hi()方法上看到的@RequestMapping和@ResponseBody注釋。 這些注釋告訴框架如何將URL請求映射到應用程序。
此時,你可以使用mvn spring-boot:run運行該應用程序。 當你點擊/ hi URL時,你將收到類似``Hello,JavaWorld''的響應。
請注意,Spring是如何利用自動裝配組件的基礎,並交付了整個Web框架的。 使用Spring,你不必顯式地將任何東西連接在一起!
@Request批注
@RequestMapping允許你定義URL路徑的處理程序。 選項包括定義所需的HTTP方法,這是我們在本例中所做的。 離開RequestMethod關閉將指示程序處理所有HTTP方法類型。
@RequestParam參數注釋使我們可以將請求參數直接映射到方法簽名中,包括要求某些參數和定義默認值(如此處所做的那樣)。 我們甚至可以使用@RequestBody參數注釋將請求主體映射到一個類。
REST和JSON響應
如果要創建REST端點,並且想從該方法返回JSON,則可以使用@ResponseBody對該方法進行注釋。 然后,響應將自動打包為JSON。 在這種情況下,你將從方法中返回一個對象。
在Spring Web上使用MVC
與Struts相似,Spring Web模塊可以輕松地用於真正的模型-視圖-控制器設置。 在這種情況下,你將以給定的模板語言(如Thymeleaf)返回映射,而Spring將解析該映射,提供傳遞給它的模型並呈現響應。
例3:使用JDBC的Spring
現在,讓我們對請求處理程序做一些更有趣的事情:讓我們從數據庫中返回一些數據。 出於本示例的目的,我們將使用H2數據庫。 幸運的是,Spring Boot開箱即用地支持內存中的H2 DB。
你可以通過將H2 DB包含在pom.xml中來將其添加到應用程序中,如清單9所示。我們還將為spring-boot-starter-jdbc添加一個依賴項。 這帶來了我們需要用Spring控制JDBC的東西。
清單9.向H2 DB添加Maven依賴項
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.194</version></dependency>
接下來,你將要配置數據庫。 這是通過spring.database.properties文件完成的,該文件位於/ resources目錄中。 清單10顯示了如何在激活內存模式的情況下使用H2。
清單10. H2內存中的配置
driverClassName=org.hsqldb.jdbc.JDBCDriver
url=jdbc:hsqldb:mem:myDb
username=sa
password=sa
服務組件類
現在,我們可以開始使用數據庫了。 就這么簡單。 但是,基本的軟件設計告訴我們永遠不要通過視圖層訪問數據層。 在這種情況下,我們不想通過視圖控制器訪問JDBC支持。 我們需要一個服務組件。 在Spring Web中,我們使用@Service注釋創建服務類。 與@Controller注釋類似,使用@Service注釋將類指定為一種@Component。 這意味着Spring會將其添加到DI上下文中,並且你可以將其自動連接到控制器中。
注釋組件
Spring提供了幾種注釋組件的方法。 指示可用於自動布線的類的最基本方法是通過@Componentannotation。 @Service注釋執行相同的操作,但是指示類的特定類型。 你可以使用@Bean批注指定一種方法,該方法用於創建要自動裝配的Bean。
清單11顯示了一個簡單的Service組件。
清單11.服務組件
package hello.service;
import org.springframework.stereotype.Service;
@Service("myService")public class MyService {
public String getGreeting(){
return "Hey There";
}
public boolean addSong(String name) {
if (name.length() > 15){
return false;
}
return true;
}
public List<String> getSongs() {
return new ArrayList();
}}
現在,我們可以從控制器訪問服務類。 在清單12中,我們將其注入。
清單12.將MyService注入控制器
@Controllerpublic class GreetingController {
@Inject
private MyService myService;
@RequestMapping(value = "/hi", method = RequestMethod.GET)
public String hi(@RequestParam(name="name", required=false, defaultValue="JavaWorld") String name, Model model) {
return myService.getGreeting() + name;
}
}
現在控制器正在使用Service類。 注意Spring是如何允許我們使用相同的DI系統定義分層體系結構的。 我們可以在定義服務類可以使用的數據層時做同樣的事情,並同時利用Spring對各種數據存儲和數據存儲訪問方法的支持。
我們可以使用@Repository注釋數據層類,如清單13所示,然后將其注入服務類中。 以同樣的方式,@ Service允許我們定義服務層,現在我們以分離的方式定義數據層。
JdbcTemplate類
數據層比服務層需要更多的資源,因為它將與數據庫進行通信。 Spring主要通過提供JdbcTemplate類來緩解這種情況。
清單13.倉庫數據類
import org.springframework.jdbc.core.JdbcTemplate;
@Repositorypublic class MyDataObject {
public void addName(String name){
jdbcTemplate.execute("DROP TABLE names IF EXISTS");
jdbcTemplate.execute("CREATE TABLE names("id SERIAL, name VARCHAR(255))");
jdbcTemplate.update("INSERT INTO names (name) VALUES (?)", name);
}
}
Spring將自動使用我們配置的內存中H2 DB。 注意jdbcTemplate如何消除了此類中的所有樣板代碼和錯誤處理代碼。 盡管這是訪問數據庫的簡化示例,但它使你了解了Spring如何工作以連接應用程序層,並促進其他必需服務的使用。
結論
Spring是Java最先進,最完整的應用程序開發框架之一。 它使設置應用程序變得更加容易,使你可以隨着應用程序的增長輕松地引入所需的依賴關系,並且完全有能力逐步實現大批量的生產級使用。
很難反對在新的Java應用程序中使用Spring。 Spring平台的維護和發展充滿活力,實際上,你可能需要執行的任何任務都可以通過Spring完成。 使用該平台將為你省去大量繁重的工作,並有助於確保你的應用程序設計穩定可靠。 如果你可以使用Spring簡化你的開發路徑,那就去做吧。
> 喜歡這篇文章的可以點個贊,歡迎大家留言評論,記得關注我,每天持續更新技術干貨、職場趣事、海量面試資料等等
> 如果你對java技術很感興趣也可以交流學習,共同學習進步。
> 不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代
文章寫道這里,歡迎完善交流。最后奉上近期整理出來的一套完整的java架構思維導圖,分享給大家對照知識點參考學習。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java干貨

