教育訓練出身,非科班,全憑自己濃厚的興趣成為一名java軟體開發工程師,畢業後工作兩年,自以為springmvc springboot等玩的很6了,前陣子面試後才讓我知道,需要看書了。不然看到的時候懂,問到的時候不懂。記得面試官問了一個很搞笑的問題,http的2x 3x 4x 5x是代表什麼意思?嗯,我懵逼了。最後我才忍不住問了,才知道其實就是請求狀态碼 200 400.......好了 廢話不多說了。
本章内容:
- spring的bean容器
- 介紹spring的核心子產品
- 更為強大的spring生态系統
- spring的新功能
1.1 spring的bean容器
spring最根本的使命:簡化java開發
為了降低java開發的複雜性,spring采取了一下四種關鍵政策:
- 基于POJO的輕量級和最小侵入性程式設計
- 通過依賴注入和面向接口實作松耦合
- 基于切面和慣例進行聲明式程式設計
- 通過切面和模闆減少樣闆式代碼
開發過程中經常會遇到POJO和javabean這兩個詞,書上提到,POJO:一個簡單普通的java類。但二者到底什麼差別?很多人一知半解。
以下解釋來自:
大白話講解POJO與JavaBean
POJO 就好比是一個普通自行車,而 JavaBean 就好比是一個電動自行車(特殊的自行車)。普通自行車擁有輪子,而電動自行車也有輪子,但是電動自行車有了電瓶,才能稱為是電動自行車。它倆的差別就在于本質上的不同,一個帶電瓶,一個不帶電瓶,雖然它倆都可以表示為自行車,但因為本質上的不同,帶電的能稱為是電動自行車,而不帶電的隻能稱為普通自行車。在 Java 中,POJO 是一個普通的 Java對象,而 JavaBean 卻是一個特殊的 Java對象,這個特殊的 Java對象具有一定的标準才能稱為 JavaBean。也就是說,萬物皆對象,即POJO,其中,滿足特殊條件和規範的就成為javabean。下面我們就結合 Java 近距離看 POJO 與 JavaBean。
POJO 是 Plain Ordinary Java Object 的縮寫,意思是 簡單普通的 Java對象,它的特征是:
1、擁有一些 private修飾的屬性;
2、這些 private修飾的屬性都提供 get…()&set…() 方法。
我們把這樣的類稱為 POJO類,POJO類 執行個體化出來的對象稱為 POJO對象。下面是一個 POJO類的例子:
// 自行車
public class Bike {
private String wheel; // 輪子
// set...() & get...()
public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
}
JavaBean 從字面上來看,它有咖啡豆的含義,關于 Java 這個名字由來的故事相信大家都聽說過,它的名字是和印度尼西亞爪哇島上爪哇咖啡有關,在 Java中也有很多類和方法的名字都和咖啡有着密不可分的聯系,就連 JavaBean 也有咖啡豆的含義,寓意着它是 Java中重要的組成部分,它也必須符合一些特定的标準才可稱為 JavaBean,它的特征是:
1、所有的屬性都被 private修飾;
2、這個類必須有一個無參構造器;
3、所有的屬性必須都提供 get…()&set…() 方法;
4、這個類必須是可序列化的,實作 serializable 接口。
我們把符合這樣特征的類稱為 JavaBean類,JavaBean類 執行個體化出來的對象稱為 JavaBean對象。下面是一個 JavaBean類的例子:
// 電動車
public class Ebike implements serializable {
private String wheel; // 輪子
// 無參構造器
public Ebike() {}
// set...() & get...()
public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
}
這個時候,序列化這個詞相信很多人也很熟悉。具體什麼作用?為什麼要序列化?
把對象轉換為位元組序列的過程稱為對象的序列化。
把位元組序列恢複為對象的過程稱為對象的反序列化。
對象的序列化主要有兩種用途:
1) 把對象的位元組序列永久地儲存到硬碟上,通常存放在一個檔案中;
2) 在網絡上傳送對象的位元組序列。
在很多應用中,需要對某些對象進行序列化,讓它們離開記憶體空間,入住實體硬碟,以便長期儲存。比如最常見的是Web伺服器中的Session對象,當有 10萬使用者并發通路,就有可能出現10萬個Session對象,記憶體可能吃不消,于是Web容器就會把一些seesion先序列化到硬碟中,等要用了,再把儲存在硬碟中的對象還原到記憶體中。
更詳細内容有興趣的可以看這篇文章:Java基礎學習總結——Java對象的序列化和反序列化
想要更深入了解的話就看這個:深入了解JAVA I/O系列五:對象序列化
稍微拓展了解了之後,好了,回歸正題,這些java類---POJO形式上雖然看起來很簡單,但spring一樣可以讓它賦予魔力,方式之一就是通過DI來裝配它們。DI----依賴注入。通過DI,對象的依賴關系将由系統中負責協調各對象的第三方元件在建立對象的時候進行設定。對象無需自行建立或管理它們的依賴關系。依賴關系将自動注入到需要它們的對象當中去。常用的方式就是構造器注入。将一個對象作為另外一個對象的構造器參數注入的方式。
建立應用元件之間協作的行為通常被稱為裝配(wiring)。spring有多種裝配bean的方式,采用XML是很常見的。比如:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
<constructor-arg value="#{T(System).out} />
</bean>
</beans>
在這裡,BraveKnight和SlayDragonQuest被聲明為Spring中的bean。就BraveKnight bean來講,它在構造時傳入了對SlayDragonQuest bean的引用,将其作為構造器參數。同時,SlayDragonQuest bean的聲明使用了Spring表達式語言(Spring Expression Language),将System.out(這是一個PrintStream)傳入到了SlayDragonQuest的構造器中。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL4FEVOlXSU9EMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1QzMzQjM0MjMyADNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
如果XML配置不符合你的喜好,spring還支援使用java來描述配置。
import com.springframework.content.annotation.Configuration;
@Configuration
public class KnightConfig{
@Bean
public Knight knight(){
return new BraveKnight(quest());
}
@Bean
public Quest quest(){
return new SlayDragonQuest(System.out);
}
}
spring通過應用上下文(Application Context)裝載bean、的定義并把它們組裝起來。Spring應用上下文全權負責對象的建立群組裝。
==========================================================
DI能夠讓互相協作的軟體元件保持松散耦合。而面向切面程式設計(AOP)可以把遍布應用各處的功能分離出來形成可重用的元件。
===========================================================
程式可以了解為一個圓,AOP就是在這個圓外圍的同心圓,程式運作時從左到右穿過兩個圓。要将一個類抽象為一個切面,可以在spring配置檔案中聲明它。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
<constructor-arg value="#{T(System).out} />
</bean>
<bean id="minstrel" class="com.springinaction.knights.Minstrel">
<constructor-arg value="#{T(System).out} />
</bean>
<aop:config>
<aop:aspect ref ="minstrel">
<aop:pointcut id="embard"> expression="execution(* *.embarkOnQuest(..))" />
<aop:before pointcut-ref="embark" method="singBeforeQuest" />
<aop:after pointcut-ref="embark" method="singBeforeQuest" />
</aop:aspect>
</aop:config>
</beans>
1.2 容納你的bean
1.2.1使用應用上下文
- AnnotationConfigApplicationContext:從一個或多個基于java的配置類中加載Spring應用上下文
- AnnotaionConfigWebApplicationContext:從一個或多個基于java的配置類中加載Spring Web 應用上下文
- ClassPathXmlApplicationContext:從類路徑下的一個或多個xml配置檔案中加載上下文定義,把應用上下文的定義檔案作為類資源
- FileSystemXmlApplicationContext:從檔案系統下的一個或多個xml配置檔案中加載上下文定義
- XmlWebApplicationContext:從web應用下的一個或多個xml配置檔案中加載上下文定義
1)從檔案系統加載xml檔案
ApplicationContext context = new FileSystemXmlApplicationContext("knight.xml");
<!-- 如果需要從resources路徑下加載,可以使用classpath -->
ApplicationContext context = new FileSytemXmlApplicationContext("classpath:knight.xml")
2)從類路徑下加載
ApplicationContext context = new ClassPathXmlApplicationContext("knight.xml");
3)從java配置中加載
ApplicationContext context = new AnnotationConfigApplicationContext(com.xxx.knights.config.KnightConfig.class);
1.2.2 bean的生命周期
傳統java應用中,使用java關鍵字new進行bean執行個體化,這個bean就可以使用了。一旦該bean不再被使用,則由java自動進行垃圾回收。
spring容器中的bean生命周期就複雜很多了,以下流程圖來自:Spring Bean的生命周期(非常詳細)
我覺得我隻要大概知道有這麼個流程就行了 不必深究。會用,知道大概什麼原理,畢竟要學的東西很多,要跟上時代節奏不被淘汰的技術。(不知道這個想法對不對)
1.3俯瞰Spring風景線
1.3.1 Spring子產品
六大子產品劃分如下:
子產品分解分析:
1.Spring核心容器
容器 是Spring架構最核心的部分。管理着Spring應用中bean的建立、配置和管理。所有的Spring子產品都建立在核心容器之上。
2.Spring的AOP子產品
AOP可以幫助應用對象解耦,可以将遍布系統的關注點(例如事務和安全),從它們所應用的對象中解耦出來。
3.資料通路與內建
Sping的JDBC和DAO(Data Access Object)子產品抽象了資料庫連接配接等樣闆代碼(重複性代碼),使我們的資料庫代碼程式設計簡單明了。還建構了語義豐富的異常層(會有sql報錯資訊)
喜歡ORM工具而不喜歡直接使用JDBC的開發者,Spring的ORM子產品建立在對DAO的支援之上,Spring對流行的ORM架構進行了內建,包括Hibernate等。
本子產品包含了JMS之上建構的Spring抽象層,使用消息以異步的方式與其他應用內建。
本子產品會使用SpringAOP子產品為Spring應用中的對象提供事務管理服務
4. Web與遠端調用
MVC(Model-View-Controller)模式是一種普遍被接受的建構web應用的方法。java有很多MVC架構,如:struts,JSF等。但它的web和遠端調用子產品自帶強大的MVC架構。
5. Instrumentation
Spring的instrumentation子產品提供了為JVM添加代理(agent)的功能。這個子產品使用場景非常有限,了解即可
6.測試
Spring提供了測試子產品。
1.3.2 Spring Portfolio
Spring遠不止Spring架構所下載下傳的那些。整個Spring Portfolio幾乎為每一個領域的Java開發都提供了Spring程式設計模型。
- Spring Web Flow
Spring Web Flow建立在SpringMVC架構上,它為基于流程的會話式Web應用(可以想象一些購物車或者向導功能)提供了支援。
- Spring Web Service
- Spring Security
利用SpringAOP,Spring Security為Spring應用提供了聲明式的安全機制
- Spring Integration
- Spring Batch
當我們需要對資料進行大量操作時,沒有任何技術可以比批處理更勝任這種場景。可以通過Spring Batch開發一個批處理應用
- Spring Data
springdata 使得在Spring中使用任何資料庫都變得非常容易。。不管是使用文檔資料庫如:MongoDB,圖資料庫如:Neo4j,還是傳統的關系型資料庫,SpringData都為之提供了一種簡單的程式設計模型。
- Spring Social
社交網絡是網際網路領域中新興的一種潮流,越來越多的應用正在融入社交網絡網站,如Facebook或者Twitter。如果你對此感興趣,可以了解一下Spring Social,這是Spring的一個社交網絡擴充子產品。
- Spring mobile
Spring Mobile是Spring MVC新的擴充子產品,用于支援移動Web應用開發。
- Spring For Android
- Spring Boot
Spring極大的簡化了衆多的程式設計任務,減少甚至少出了很多樣闆式代碼。Springboot大量依賴于自動配置技術,她能消除大部分(很多場景中,甚至是全部)Spring配置。它還提供了多個Starter項目,不管你使用maven還是gradle,這都能減少Spring工程建構檔案的大小!!!!!重點學習!!!
---------------------------------------------------------------------------
總結:
在本章,我們體驗了Spring的DI。DI是組裝應用對象的一種方式,借助這種方式對象無需知道依賴來自何處或者依賴的實作方式。不同于自己擷取依賴對象,對象會在運作期賦予它們所依賴的對象。依賴對象通常會通過接口了解所注入的對象,這樣的話就能確定低耦合。DI說白了,就是我們平時聽的最多的依賴注入。再實際一點,Spring裝配bean有三種方式:
==> 1. 自動化配置(最推薦,避免顯示配置帶來的維護成本)
1.1 元件掃描:spring自動發現容器所建立的bean。開啟元件掃描,預設情況下自動掃描配置類相同包(以及子包)下所有帶有@component注解的類,并為其自動建立一個bean。開啟元件掃描有兩種方式,基于java配置(推薦)和xml配置:
Java配置:在配置類上添加@componentScan注解
Xml配置:利用<context:component-scan base-package=”...”/>
1.2 自動裝配:spring自動滿足bean之間的依賴。使用@Autowired(推薦)或@Inject注解添加在構造、setter還是其他方法上,實作bean的自動注入,無需手動去new。
==> 2. Java配置(推薦,基于java語言,類型安全易于重構)
利用@Bean注解來聲明(建立)一個bean,同時還可以注入另外依賴的bean(利用構造器和setter方法)
==> 3. Xml配置
3.1利用<bean>标簽聲明一個bean。
舉例 <bean id = “peoson” class=”soundsystem.Person” />
3.2 如何注入bean(構造器和setter方法)
構造器注入bean,舉例
<bean id = “cdPlayer” class= “com.CDPlayer” >
<constructor-arg ref=”cd” />
</bean>
構造器注入字面量,舉例
<bean id = “...” class= “...”>
<constructor-arg value=”...” />
</bean>
c命名空間注入bean,舉例
<bean id = “...” class= “...”c:cd-ref=”...” />
c命名空間注入字面量,舉例
<bean id = “...” class= “...” c:_...=”...” />
利用<list>、<set>等标簽,構造器注入方式可以用來裝配集合,而c命名空間不行。
Setter方法注入bean,舉例
<bean id = “cdPlayer” class= “com.CDPlayer” >
<property name = “...” ref = “...” />
</bean> 或者使用p命名空間
<bean id = “cdPlayer” class= “com.CDPlayer” p: cd-ref = “...” />
Setter方法注入字面量,舉例
<bean id = “cdPlayer” class= “com.CDPlayer” >
<property name = “...” value = “...” />
</bean> 或者使用p命名空間
<bean id = “cdPlayer” class= “com.CDPlayer” p: ... = “...” />
除了DI,我們還介紹了Spring對AOP的支援。面向切面程式設計,其實就是能夠避免重複性代碼,在需要這些代碼的時候切入到程式中,就像登入功能,有的地方需要登入,有的地方不需要登入,而需要登入的地方業務邏輯都是一樣的,如果每個地方都寫上相同的代碼,維護起來相當麻煩,顯然不可取。這也就是AOP的目的所在。
PS:工作忙,間斷的寫完了這篇筆記,若有不對的地方歡迎指正,我當虛心學習。