Spring/SpringMVC


1. 介紹spring框架

Spring是一套為了解決企業應用開發的復雜性而創建的框架,特點是分層的架構,允許用戶在不同層面使用不同的組件進行組合。同時通過IOC容器來降低耦合,簡化開發。利用AOP來進行切面編程統一管理通用模塊。

2.Spring中AOP的應用場景、Aop原理、好處?

主要是兩種,一種是JDK動態代理,一種是Cglib代理。
兩者的區別:

  1. JDK動態代理只能代理實現了接口的類,動態代理類的字節碼在程序運行時由Java反射機制動態生成。
  2. Cglib是可以代理沒有實現接口的類,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,所以不能對final修飾的類進行代理。底層采用ASM實現。

原理:AOP是面向切面編程,是通過動態代理(jdk動態代理)的方式為程序添加統一功能,集中解決一些公共問題。

AOP就是縱向的編程,如業務1和業務2都需要一個共同的操作,與其往每個業務中都添加同樣的代碼,不如寫一遍代碼,讓兩個業務共同使用這段代碼。在日常有訂單管理、商品管理、資金管理、庫存管理等業務,都會需要到類似日志記錄、事務控制、權限控制、性能統計、異常處理及事務處理等。AOP把所有共有代碼全部抽取出來,放置到某個地方集中管理,然后在具體運行時,再由容器動態織入這些共有代碼。

優點:

  1. 各個步驟之間的良好隔離性耦合性大大降低
  2. 源代碼無關性,再擴展功能的同時不對源碼進行修改操作

JDK代理的是實現

JDK動態代理的實現是在運行時,根據一組接口定義,使用Proxy、InvocationHandler等工具類去生成一個代理類和代理類實例。
JDK動態代理的類關系模型和靜態代理看起來差不多。也是需要一個或一組接口來定義行為規范。需要一個代理類來實現接口。區別是沒有真實類,因為動態代理就是要解決在不知道真實類的情況下依然能夠使用代理模式的問題

先開始我們的第一步,定義一個接口。這個接口里面定義一個方法helloWorld()。
public interface MyIntf {
void helloWorld();
}

第二步,編寫一個我們自己的調用處理類,這個類需要實現InvocationHandler接口。
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
return null;
}
}
InvocationHandler接口只有一個待實現的invoke方法。這個方法有三個參數,proxy表示動態代理類實例,method表示調用的方法,args表示調用方法的參數。在實際應用中,invoke方法就是我們實現業務邏輯的入口。這里我們的實現邏輯就一行代碼,打印當前調用的方法(在實際應用中這么做是沒有意義的,不過這里我們只想解釋JDK動態代理的原理,所以越簡單越清晰)。
第三步,直接使用Proxy提供的方法創建一個動態代理類實例。並調用代理類實例的helloWorld方法,檢測運行結果。
public class ProxyTest {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
MyIntf proxyObj = (MyIntf)Proxy.newProxyInstance(MyIntf.class.getClassLoader(),new Class[]{MyIntf.class},new MyInvocationHandler());
proxyObj.helloWorld();
}
}
第三行代碼是設置系統屬性,把生成的代理類寫入到文件。這里再強調一下,JDK動態代理技術是在運行時直接生成類的字節碼,並載入到虛擬機執行的。這里不存在class文件的,所以我們通過設置系統屬性,把生成的字節碼保存到文件,用於后面進一步分析。

第四行代碼就是調用Proxy.newProxyInstance方法創建一個動態代理類實例,這個方法需要傳入三個參數,第一個參數是類加載器,用於加載這個代理類。第二個參數是Class數組,里面存放的是待實現的接口信息。第三個參數是InvocationHandler實例。
第五行調用代理類的helloWorld方法,運行結果:
public abstract void com.tuniu.distribute.openapi.common.annotation.MyIntf.helloWorld()
分析運行結果,就可以發現,方法的最終調用是分派到了MyInvocationHandler.invoke方法,打印出了調用的方法信息。

3. Spring中IOC的作用與原理?對象創建的過程。

IOC--Inversion of Control控制反轉。當某個角色需要另外一個角色協助的時候,在傳統的程序設計過程中,通常由調用者來創建被調用者的實例對象。但在spring中創建被調用者的工作不再由調用者來完成,因此稱為控制反轉。創建被調用者的工作由spring來完成,然后注入調用者 直接使用。

 IOC容器:就是具有依賴注入功能的容器,是可以創建對象的容器, BeanFactory是IoC容器的核心接口。它的職責包括:實例化、定位、配置應用程序中的對象及建立這些對象間的依賴,通常new一個實例,控制權由程序員控制,而"控制反轉"是指new實例工作不由程序員來做而是交給Spring容器來做。 Spring為我們提供了許多易用的BeanFactory實現,XmlBeanFactory就是最常用的一個。該實現將以XML方式描述組成應用的對象以及對象間的依賴關系。XmlBeanFactory類將持有此XML配置元數據,並用它來構建一個完全可配置的系統或應用

  DI(依賴注入Dependency injection) :在容器創建對象后,處理對象的依賴關系。

依賴注入spring的注入方式:

  • set注入方式
  • 靜態工廠注入方式
  • 構造方法注入方式
  • 基於注解的方式
  • 依賴注入的三種方式:(1)接口注入(2)Construct注入(3)Setter注入

4.spring有兩種代理方式:

  1. 若目標對象實現了若干接口,spring使用JDK的java.lang.reflect.Proxy類代理。
    優點:因為有接口,所以使系統更加松耦合
    缺點:為每一個目標類創建接口

  2. 若目標對象沒有實現任何接口,spring使用CGLIB庫生成目標對象的子類。
    優點:因為代理類與目標類是繼承關系,所以不需要有接口的存在。
    缺點:因為沒有使用接口,所以系統的耦合性沒有使用JDK的動態代理好。

代理的共有優點:業務類只需要關注業務邏輯本身,保證了業務類的重用性

5.spring中的核心類有那些,各有什么作用?

BeanFactory:產生一個新的實例,可以實現單例模式
BeanWrapper:提供統一的get及set方法
ApplicationContext:提供框架的實現,包括BeanFactory的所有功能

6.什么是IOC,什么又是DI,他們有什么區別?

依賴注入DI是一個程序設計模式和架構模型, 一些時候也稱作控制反轉,盡管在技術上來講,依賴注入是一個IOC的特殊實現,依賴注入是指一個對象應用另外一個對象來提供一個特殊的能力,例如:把一個 數據庫連接已參數的形式傳到一個對象的結構方法里面而不是在那個對象內部自行創建一個連接。控制反轉和依賴注入的基本思想就是把類的依賴從類內部轉化到外 部以減少依賴

應用控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用,傳遞給它。也可以說,依賴被注入到對象中。所 以,控制反轉是,關於一個對象如何獲取他所依賴的對象的引用,這個責任的反轉。

7.Spring常見創建對象的注解?

@component
除了上述提到的 @Component注解外,Spring中還提供了@Component的3個衍生注解,其功能就目前來說是一致的,均是為了創建對象。
@Controller :WEB層
@Service :業務層
@Repository :持久層
@Service
@Service是一個注解,告訴spring創建一個實現類的實例,就是不用再spring里配置bean
@Configuration和@Bean
@Configuration可理解為用spring的時候xml里面的 標簽
@Bean可理解為用spring的時候xml里面的 標簽
@EnableConfigurationProperties
作用是@ConfigurationProperties注解生效
@ConfigurationProperties
主要用來把properties配置文件轉化為bean來使用的,就是綁定application.properties中的屬性
就是綁定application.properties中的屬性
@ImportResource
引入spring配置文件.xml
@Autowired
它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。 通過 @Autowired的使用來消除 set ,get方法。
@ConditionalOnBean(僅僅在當前上下文中存在某個對象時,才會實例化一個Bean)
@ConditionalOnClass(某個class位於類路徑上,才會實例化一個Bean)
@ConditionalOnExpression(當表達式為true的時候,才會實例化一個Bean)
@ConditionalOnMissingBean(僅僅在當前上下文中不存在某個對象時,才會實例化一個Bean)
@ConditionalOnMissingClass(某個class類路徑上不存在的時候,才會實例化一個Bean)
@ConditionalOnNotWebApplication(不是web應用)

8.Spring的優點?

1.降低了組件之間的耦合性 ,實現了軟件各層之間的解耦
2.可以使用容易提供的眾多服務,如事務管理,消息服務等
3.容器提供單例模式支持
4.容器提供了AOP技術,利用它很容易實現如權限攔截,運行期監控等功能
5.容器提供了眾多的輔助類,能加快應用的開發
6.spring對於主流的應用框架提供了集成支持,如hibernate,JPA,Struts等
7.spring屬於低侵入式設計,代碼的污染極低
8.獨立於各種應用服務器
9.spring的DI機制降低了業務對象替換的復雜性
10.Spring的高度開放性,並不強制應用完全依賴於Spring,開發者可以自由選擇spring 的部分或全部

9.Spring Bean的作用域之間有什么區別?

Spring容器中的bean可以分為5個范圍。所有范圍的名稱都是自說明的,但是為了避免混淆,還是讓我們來解釋一下:

singleton:這種bean范圍是默認的,這種范圍確保不管接受到多少個請求,每個容器中只有一個bean的實例,單例的模式由bean factory自身來維護。

prototype:原形范圍與單例范圍相反,為每一個bean請求提供一個實例。

request:在請求bean范圍內會每一個來自客戶端的網絡請求創建一個實例,在請求完成以后,bean會失效並被垃圾回收器回收。

Session:與請求范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效。

global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那么這全局變量需要存儲在global-session中。

全局作用域與Servlet中的session作用域效果相同。

10.Spring事務

Spring事務其實就是Spring AOP,底層創建動態代理對象,在代碼的開頭結尾封裝了開啟事務和事務回滾操作

事務屬性這個概念,事務屬性通常由事務的傳播行為,事務的隔離級別,事務的超時值和事務只讀標志組成

什么是事務*

事務是訪問數據庫的一個操作序列,數據庫應用系統通過事務集來完成對數據庫的存取。事務的正確執行使得數據庫從一種狀態轉換為另一種狀態。

事務必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)的縮寫,這四種狀態的意思是:

1、原子性

即不可分割,事務要么全部被執行,要么全部不執行。如果事務的所有子事務全部提交成功,則所有的數據庫操作被提交,數據庫狀態發生變化;如果有子事務失敗,則其他子事務的數據庫操作被回滾,即數據庫回到事務執行前的狀態,不會發生狀態轉換

2、一致性

事務的執行使得數據庫從一種正確狀態轉換成另外一種正確狀態

3、隔離性

在事務正確提交之前,不允許把事務對該數據的改變提供給任何其他事務,即在事務正確提交之前,它可能的結果不應該顯示給其他事務

4、持久性

事務正確提交之后,其結果將永遠保存在數據庫之中,即使在事務提交之后有了其他故障,事務的處理結果也會得到保存

事務的作用

事務管理對於企業級應用而言至關重要,它保證了用戶的每一次操作都是可靠的,即便出現了異常的訪問情況,也不至於破壞后台數據的完整性。就像銀行的自動提款機ATM,通常ATM都可以正常為客戶服務,但是也難免遇到操作過程中及其突然出故障的情況,此時,事務就必須確保出故障前對賬戶的操作不生效,就像用戶剛才完全沒有使用過ATM機一樣,以保證用戶和銀行的利益都不受損失。

並發下事務會產生的問題

舉個例子,事務A和事務B操縱的是同一個資源,事務A有若干個子事務,事務B也有若干個子事務,事務A和事務B在高並發的情況下,會出現各種各樣的問題。"各種各樣的問題",總結一下主要就是五種:第一類丟失更新、第二類丟失更新、臟讀、不可重復讀、幻讀。五種之中,第一類丟失更新、第二類丟失更新不重要,不講了,講一下臟讀、不可重復讀和幻讀。

1、臟讀

所謂臟讀,就是指事務A讀到了事務B還沒有提交的數據,比如銀行取錢,事務A開啟事務,此時切換到事務B,事務B開啟事務-->取走100元,此時切換回事務A,事務A讀取的肯定是數據庫里面的原始數據,因為事務B取走了100塊錢,並沒有提交,數據庫里面的賬務余額肯定還是原始余額,這就是臟讀。

2、不可重復讀

所謂不可重復讀,就是指在一個事務里面讀取了兩次某個數據,讀出來的數據不一致。還是以銀行取錢為例,事務A開啟事務-->查出銀行卡余額為1000元,此時切換到事務B事務B開啟事務-->事務B取走100元-->提交,數據庫里面余額變為900元,此時切換回事務A,事務A再查一次查出賬戶余額為900元,這樣對事務A而言,在同一個事務內兩次讀取賬戶余額數據不一致,這就是不可重復讀。

3、幻讀

所謂幻讀,就是指在一個事務里面的操作中發現了未被操作的數據。比如學生信息,事務A開啟事務-->修改所有學生當天簽到狀況為false,此時切換到事務B,事務B開啟事務-->事務B插入了一條學生數據,此時切換回事務A,事務A提交的時候發現了一條自己沒有修改過的數據,這就是幻讀,就好像發生了幻覺一樣。幻讀出現的前提是並發的事務中有事務發生了插入、刪除操作。

事務隔離級別

事務隔離級別,就是為了解決上面幾種問題而誕生的。為什么要有事務隔離級別,因為事務隔離級別越高,在並發下會產生的問題就越少,但同時付出的性能消耗也將越大,因此很多時候必須在並發性和性能之間做一個權衡。所以設立了幾種事務隔離級別,以便讓不同的項目可以根據自己項目的並發情況選擇合適的事務隔離級別,對於在事務隔離級別之外會產生的並發問題,在代碼中做補償。

事務隔離級別有4種,但是像Spring會提供給用戶5種,來看一下:

1、DEFAULT(default)

默認隔離級別,每種數據庫支持的事務隔離級別不一樣,如果Spring配置事務時將isolation設置為這個值的話,那么將使用底層數據庫的默認事務隔離級別。順便說一句,如果使用的MySQL,可以使用"select @@tx_isolation"來查看默認的事務隔離級別

2、READ_UNCOMMITTED(read_uncommitted)

讀未提交,即能夠讀取到沒有被提交的數據,所以很明顯這個級別的隔離機制無法解決臟讀、不可重復讀、幻讀中的任何一種,因此很少使用

3、READ_COMMITED(read_commited)

讀已提交,即能夠讀到那些已經提交的數據,自然能夠防止臟讀,但是無法限制不可重復讀和幻讀

4、REPEATABLE_READ(repeatable)

重復讀取,即在數據讀出來之后加鎖,類似"select * from XXX for update",明確數據讀取出來就是為了更新用的,所以要加一把鎖,防止別人修改它。REPEATABLE_READ的意思也類似,讀取了一條數據,這個事務不結束,別的事務就不可以改這條記錄,這樣就解決了臟讀、不可重復讀的問題,但是幻讀的問題還是無法解決

5、SERLALIZABLE(serlalizable)

串行化(序列化 ),最高的事務隔離級別,不管多少事務,挨個運行完一個事務的所有子事務之后才可以執行另外一個事務里面的所有子事務,這樣就解決了臟讀、不可重復讀和幻讀的問題了

10.Spring管理事務有幾種方式?

有兩種方式:

1、編程式事務,在代碼中硬編碼。(不推薦使用)
2、聲明式事務,在配置文件中配置(推薦使用)

聲明式事務又分為兩種:

a、基於XML的聲明式事務
b、基於注解的聲明式事務

11.Springmvc的優點

1.它是基於組件技術的.全部的應用對象,無論控制器和視圖,還是業務對象之類的都是 java組件.並且和Spring提供的其他基礎結構緊密集成.
2.不依賴於Servlet API(目標雖是如此,但是在實現的時候確實是依賴於Servlet的)

  1. 可以任意使用各種視圖技術,而不僅僅局限於JSP
    4 . 支持各種請求資源的映射策略
    5 .它應是易於擴展的

12.SpringBean的生命周期

image.jpeg
image.jpeg

Spring MVC 的簡單原理圖如下:

image.jpeg
image.jpeg

SpringMVC 工作原理(重要)

簡單來說:
客戶端發送請求-> 前端控制器 DispatcherServlet 接受客戶端請求 -> 找到處理器映射 HandlerMapping 解析請求對應的 Handler-> HandlerAdapter 會根據 Handler 來調用真正的處理器開處理請求,並處理相應的業務邏輯 -> 處理器返回一個模型視圖 ModelAndView -> 視圖解析器進行解析 -> 返回一個視圖對象->前端控制器 DispatcherServlet 渲染數據(Moder)->將得到視圖對象返回給用戶

流程說明(重要):

(1)客戶端(瀏覽器)發送請求,直接請求到 DispatcherServlet。
(2)DispatcherServlet 根據請求信息調用 HandlerMapping,解析請求對應的 Handler。
(3)解析到對應的 Handler(也就是我們平常說的 Controller 控制器)后,開始由 HandlerAdapter 適配器處理。
(4)HandlerAdapter 會根據 Handler 來調用真正的處理器開處理請求,並處理相應的業務邏輯。
(5)處理器處理完業務后,會返回一個 ModelAndView 對象,Model 是返回的數據對象,View 是個邏輯上的 View。
(6)ViewResolver 會根據邏輯 View 查找實際的 View。
(7)DispaterServlet 把返回的 Model 傳給 View(視圖渲染)。
(8)把 View 返回給請求者(瀏覽器)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM