Spring入門筆記簡要
總覽:https://www.processon.com/view/link/605b14ab5653bb2225e6b0c5
一、Spring
1、概述
1、spring框架簡介
為簡化企業級開發而生,有效的降低程式碼的耦合度,極大的方便專案的後期維護、升級和擴充套件。
2、優點
輕量、AOP支援、支援對各種框架的整合
3、體系結構
1、資料訪問
2、Web開發
3、AOP
4、整合訊息等
5、核心容器 IOC
2、IOC控制反轉
ioc(Inversion of Control)是一種設計思想,把物件的建立、賦值、管理工作都交給程式碼之外的容器實現,也就是物件的建立是有其他外部資源完成。
控制:建立物件,物件賦值,物件之間的關係管理
反轉:把原來開發人員管理、建立物件的許可權轉交給程式碼之外的容器實現,由容器代替開發人員管理物件,建立、賦值等
正轉:由開發人員在程式碼中,使用new構造方法建立物件,開發人員主動管理物件‘;
容器:是一個伺服器軟體(Tomcat),一個框架(spring)等
目的:
減少對程式碼的改動,也能實現不同的功能,實現解耦合
所以:java中建立物件的方式:
1、new
2、反射,class的newInstance()方法,constructor的newInstance()方法
3、反序列化
4、克隆
5、ioc
ioc的技術實現:
DI 是 ioc 的技術實現
DI (Dependency Injection)依賴注入:只需要在程式中提供使用的物件名稱就可以,至於物件如何在容器中建立、賦值、查詢都由容器內部實現。
spring是使用的 DI 實現了 ioc 的功能,spring底層建立物件,使用的是反射機制。
2.1 由spring建立物件
實現步驟:
-
建立maven專案
-
加入maven依賴
spring依賴、junit依賴
-
建立類(介面和他的實現類)
和沒有使用框架一樣,就是普通類
-
建立spring需要使用的配置檔案
宣告類的資訊,由spring建立和管理
僅限於初學的寫法:
2.2 DI(依賴注入)的實現方式:
1、基於xml配置檔案:在Spring配置檔案中,使用標籤和屬性完成
2、基於註解的實現:使用spring中的註解,完成屬性賦值
2.2.1 基於xml配置檔案
適合經常需要修改
DI的語法分類:
1、 注入(set設值, 注入就是賦值):spring呼叫類的set方法,在set方法中實現屬性的賦值(最常用)
2、構造注入,spring呼叫類的有參構造方法,建立物件,在構造方法中完成賦值
set注入:
- 簡單型別的set注入:
property設值時name屬性必須在相應的類中有set方法,且有set方法沒有相應的變數也不會報錯
2.引用型別的set注入:
引用型別的自動注入:
1、byName:java類中引用型別的屬性名和spring容器中(配置檔案)
<bean id="xx" class="yy" autowire="byName"></bean>
讓Student類中所有的引用型別都按照byName規則完成賦值
2、byType(按型別注入):java類中引用型別的資料型別和spring容器中(配置檔案)
同源:1、java類中引用型別的資料型別和bean中的class值一樣
2、java類中引用型別的資料型別和bean中的class值父子類關係的
3、java類中引用型別的資料型別和bean中的class值介面和實現類關係的
注:只能有一個符合條件的,多個會報錯
class是Student類中引用的School的值:
構造注入
name屬性實現構造注入
index屬性實現
可以省略index=“”,但是必須按照引數的定義順序書寫
多配置檔案優勢:
-
每個檔案的大小比一個檔案小很多,效率高
-
避免多人競爭帶來的衝突
按檔案的分配方式:
-
按功能模組,一個模組一個配置檔案
-
按類的功能,資料庫相關的配置一個配置檔案,做事務的功能一個配置檔案,做service功能的一個配置檔案
2.2.2 基於註解的實現
快捷,方便,適合不經常修改的
實現步驟:
-
加入maven依賴spring-context(間接加入了spring-aop依賴)
-
建立類,在類中加入spring 註解@Component(value=“xxx”),省略value=也可以(常用),如果只寫@Component則會預設value=首字母小寫的類名
還有 @Repository(用在持久層):放在dao的實現類,表示建立dao物件,dao物件是能訪問資料庫的 @Service(用在業務層):service物件是做業務處理,可以有事務等功能的 @Controller(用在控制器上):放在控制器(處理器)類的上面,建立控制器物件的,控制器物件能夠接受使用者提交的引數,顯示請求的處理結果 以上三個適用語法和@Component一樣,都能建立物件,但是他們三個還有額外的功能
引用型別-@Autowired
引用型別@Resource
-
在spring配置檔案中,加入一個元件掃描器的標籤,說明註解在專案中的位置
需要指定多個包時:
3、AOP面向切面程式設計
3.1 動態代理
動態代理能建立物件,在原有類程式碼不變的情況下,實現功能的增加,功能增強。
3.1.1 JDK 動態代理
要求目標物件必須實現介面,java語言通過java.lang.reflect包提供三個類支援代理模式Proxy,Method和InvcationHandler,要求目標類和方法不能是final的,因為final不能被繼承,不能被重寫啊
實現步驟:
-
建立目標類,SomeserviceImpl目標類,給它的doSome,dother增加輸出時間,事務。
-
建立InvocationHandler介面的實現類,在這個類實現給目標方法增加功能。
-
使用jdk中類Proxy ,建立代理物件。實現建立物件的能力。
作用:
-
在目標類原始碼不改變的情況下,增加功能
-
減少程式碼的重複
-
專注業務程式碼邏輯
-
解耦合,讓業務與日誌扥,事務非業務功能分離
3.1.2 CGLB動態代理(瞭解)
CDLIB(Code Generation Library)是一個開源專案,原理是生成目標類的子類,子類是代理物件。
3.2 AOP簡介
AOP(Aspect Orient Programming) 面向切面程式設計,底層的實現就是採用動態代理模式實現的,採用了JDK的動態代理和CGLIB的動態代理。
Aspect:切面,給目標類增加的功能
特點:一般都是非業務方法,獨立使用的
如何理解AOP:
以切面為核心,圍繞切面來開發程式:
1)分析專案功能時找到切面
2)合理安排執行時間,(在目標方法前還是後)
3)合理的安排切面執行的位置, 在哪個類,哪個方法增加增強功能
3.3 AOP程式設計術語
-
AOP:切面,表示增強的功能,就是一堆程式碼,完成某一個功能,非業務功能
常見的切面功能有日誌,事務,統計資訊,引數檢查,許可權驗證
-
JoinPoint:連線點,連線業務方法和切面的位置,就是某類中的業務方法
-
PointCut:切入點,指多個連線方法的集合,多個方法
-
目標物件:給哪個類的方法這個價功能,這個類就是目標物件
-
Advice:通知,表示切面功能 執行的時間,方法之前還是之後
切面三個關鍵要素:
- 切面的功能程式碼,切面幹什麼
- 切面的執行位置,使用PointCut表示切面執行的位置
- 切面的執行時間,使用Advice表示時間,在目標方法之前還是之後
3.4 AOP的實現
AOP是一個規範,是動態的一個規範化,一個標準
aop的技術實現框架:
-
spring:spring內部實現了aop的規範,能做aop的工作
spring在處理事務時使用aop
在專案開發中很少使用spring的aop實現,因為spring的aop比較笨重
-
Aspect:一個開源的專門做aop的框架,spring框架中集成了aspectj框架,通過spring就能使用aspectj的功能
aspectj框架實現aop的兩種方式:
- 使用xml的配置檔案:配置全域性事務
- 使用註解,在專案中要做aop功能,一般使用註解
3.4 AspectJ框架的使用
-
切面的執行時間,這個執行時間在規範中叫做Advice(通知,增強)
在aspect框架中使用註解表示,也可以使用xml配置檔案中的標籤
<!-- 5個常用註解 @Before @AfterReturning @Around @After @AfterThrowing -->
-
表示切面執行的位置,使用的是切入表示式
execution(訪問許可權 方法返回值 方法引數 異常型別)
在其中可以使用以下符號: * :0至多個任意字元 .. : 用在方法引數中,表示任意多個引數;用在包名後,表示當前包及其子包 + :用在類名後,表示當前類及其子類;用在介面名後,表示當前介面及其實現類
指定切入點為:任意公共方法 execution(public * *(..)) 指定切入點為:任意一個以set開始的方法 execution(* set*(..)) 指定切入點為:com.mhz.service包中的任意類中的任意方法,不包含子包 execution(* com.mhz.service.*.*(..)) 指定切入點為:com.mhz.service或者子包包中的任意類中的任意方法 execution(* com.mhz.service..*.*(..)) 指定切入點為:所有service包下的任意類的任意方法 execution(* *..service.*.*(..))
使用aspectJ實現aop的基本步驟:
-
新建maven專案
-
加入依賴
- spring依賴
- aspectj依賴
- junit單元測試(可有可無)
-
建立目標類:介面和他的實現類
要做的是給類中的方法增加功能
-
建立切面類:普通類
-
在類上加入註解@Aspect
-
定義方法,方法就是切面要執行的功能程式碼
在方法上面加入aspectj中的註解,例如@Before,
有需要指定切入點表示式execution()
-
-
建立spring配置檔案:宣告物件,把物件交給容器統一管理
宣告物件可以使用xml配置檔案
或者註解 -
宣告目標物件
-
宣告切面類物件
-
宣告aspectj框架中的自動代理生成器標籤。
自動代理生成器:用來完成代理物件的自動建立功能的。
<!--把物件交給spring容器,由spring容器統―建立,管理物件--> <! --宣告目標物件--> <bean id="someservice" class="com.bjpowernode.bao1.SomeserviceImpl"/> <! --宣告切面類物件--> <bean id="myAspect" class="com.bjpowernode.ba01.MyAspect”/> <!-- 宣告自動代理生成器:使用aspectj框架內部的功能,建立目標物件的代理物件。 建立代理物件是在記憶體中實現的,修改目標物件的記憶體中的結構。建立為代理物件所以目標物件就是被修改後的代理物件 aspectj-autoproxy:會把spring容器內的所有目標物件,一次性都生成代理物件 --> <aop: aspectj-autoproxy />
-
-
建立測試類,從spring容器中獲取目標物件(代理物件)
通過代理物件實現aop
六個註解:
1、@Before:
前置通知註解
屬性: value,是切入點表示式,表示切面的功能執行的位置。
位置: 在方法的上面
特點:
1.在目標方法之前先執行的
2.不會改變目標方法的執行結果
3.不會影響目標方法的執行。
/*
* 指定通知方法中的引數:JoinPoint
* JoinPoint:業務方法,要加入切面功能的業務方法
* 作用是:可以在通知方法中獲取方法執行時的資訊,例如方法名稱,方法的實參。
* 如果你的切面 功能中需要用到方法的資訊,就加入JoinPoint.
* 這個JoinPoint引數的值是由框架賦予,必須是第一個位置的引數
*/
@Before(value = "execution(void *..SomeServiceImpl.doSome(String, Integer))")
public void myBefore(JoinPoint jp){
//獲取方法的完整定義
system.out.println("方法的簽名(定義)="+jp.getsignature());
system.out.println("方法的名稱="+jp.getsignature().getName());//獲取方法的實參
object args []= jp.getArgs();
for (object arg:args){
system.out.println("引數="+arg);
}
}
2、@AfterReturning:
後置通知定義方法,方法是實現切面功能的。
方法的定義要求:
1.公共方法 public
2.方法沒有返回值
3.方法名稱自定義
4.方法有引數的,推薦是object,引數名自定義
@AfterReturning:後置通知
屬性:
1.value切入點表示式
2.returning自定義的變數,表示目標方法的返回值的。自定義變數名必須和通知方法的形參名一樣。
位置:在方法定義的上面
特點:
1. 在目標方法之後執行的。
2. 能夠獲取到目標方法的返回值,可以根據這個返回值做不同的處理功能
3. 可以修改這個返回值
@AfterReturning(value="execution(* *..SomeServiceImpl.doOther(..))",returning="res")
// 此處returning的res名稱=Object的res名稱就行
public void myAfterReturing(object res){
// object res:是目標方法執行後的返回值,根據返回值做你的切面的功能處理
// 思考:如果是對類物件res的更改會不會影響在程式執行後得到的輸出結果?
system.out.println("後置通知:在目標方法之後執行的,獲取的返回值是:"+res);
if(res.equals("abcd"))
{
//做―些功能
}
e1se
{
//做其它功能
}
}
3、@Around
環繞通知
方法的定義格式:
1.public
2.必須有一個返回值,推薦使用object
3.方法名稱自定義
4.方法有引數,固定的引數ProceedingjoinPoint
@Around:環繞通知
屬性:value切入點表示式位宣:在方法的定義什麼
特點:
1.它是功能最強的通知
2.在目標方法的前和後都能增強功能。
3.控制目標方法是否被呼叫執行
4.修改原來的目標方法的執行結果。影響最後的呼叫結果
等同於jdk動態代理的,InvocationHandler介面
引數:ProceedingJoinPoint 等同於Method
作用:執行目標方法
返回值:就是目標方法的執行結果,可以被修改
@Around(value = "execution(* *..SomeService1mpl.doFirst(..))")
public object myAround(ProceedingJoinPoint pjp) throws Throwable {
// 獲取第一個引數值
Object[] args = pjp.getArgs();
String name = "";
if(args != null && args.length > 1){
Object arg = args[0];
name = (String)arg;
}
//實現環繞通知
object result = null;
system.out.println("環繞通知:在目標方法之前,輸出時間:"+ new Date());
//1.目標方法呼叫
if("xxx".equals(name)){
// 控制是否執行目標方法
result = pjp.proceed(); //method.invoke(); object result = doFirst();
}
system.out.println("環繞通知:在目標方法之後,提交事務");
//2.在目標方法的前或者後加入功能
//返回目標方法的執行結果
return result;
}
4、 @AfterThrowing
異常通知:
1、public
2、沒有返回值
3、方法,名稱自定義
4、方法有一個Exception,如果還有就是JoinPoint
@AfterThrowing:異常通知
屬性:1、value
2、throwing自定義變數,表示目標方法丟擲的異常物件,變數名和方法的引數名一樣
特點:1、在目標方法丟擲異常時執行
2、可以做異常的監控程式,如果有異常,可以發郵件,簡訊通知等
執行時:
沒有異常就走正常邏輯,有異常就走定義的@AfterThrowing註解的方法
try{
SomeServiceImpl.doSecond(..);
}
catch(Exception ex){
myAfterThrowing(ex);
}
@AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",throwing = "ex")
public void myAfterThrowing(Exception ex){
system.out.println("異常通知:方法發生異常時,執行: "+ex.getMessage());//傳送郵件,簡訊,通知開發人員
}
5、@ After
最終通知
方法的定義格式
1.public
2.沒有返回值
3.方法名稱自定義
4.方法沒有引數,如果還有是JoinPoint
@After:最終通知
屬性:value 切入點表示式
位置:方法上面
特點:
1、總是執行
2、目標方法後執行,即使丟擲了異常
類似於:
try/catch中的finally程式碼塊
@After(value = "execution(* *..SomeserviceImpl.doThird(..))")
public loidmyAfter(){
//一般做資源清除工作的。
systemyout.println("執行最終通知,總是會被執行的程式碼");
}
6、 @PointCut
定義管理切入點
如果專案中很多個切入點表示式是重複的,,使用@PointCut
屬性:value 切入點表示式
位置:方法上面
特點:
當使用@Pointcut定義在一個方法的上面,此時這個方法的名稱就是切入點表示式的別名。其它的通知中,value屬性就可以使用這個方法名稱,代替切入點表示式了
@Pointcut(value = "execution(* *..SomeserviceImpl.doThird(..))”)
private void mypt(){
//無需程式碼,
}
// 然後:
@Before(value="mypt()")
public void myBefore(){
}
4、Spring事務
4.1 Spring的事務管理
-
什麼是事務?
指的是一組sql語句的集合,集合中有多個sql語句,增刪查改,希望這些sql語句鬥毆成功或者都失敗,這些sql 的執行是一致的,作為一個整體執行。
-
什麼時候用到事務?
當操作涉及多個表或者多個sql語句的增刪改,需要保證這些sql語句都成功才能完成功能,或者都失敗,保證操作是符合要求的。
在java程式碼中寫程式,控制事務,需要寫在service類的業務方法上,因為業務方法匯呼叫多個dao方法,執行多個sql語句
-
jdbc、Mybatis訪問資料庫處理事務?
//jdbc Connection conn; conn.commit(); conn.rollback(); //mybatis SqlSession.commit(); SqlSession.rollback();
-
問3中處理事務的方式是不同的,所以有哪些不足:
-
不同的資料庫訪問技術,處理事務的物件、方法不同,需要掌握瞭解不同資料庫訪問技術使用事務的原理
-
掌握多種資料庫中事務的處理邏輯,提交、回滾等
多種資料庫訪問技術,有不同的事務處理的機制,物件、方法
-
-
解決不足
spring提供一種統一處理事務的統一模型,能使用統一步驟,方式完成多種不同資料庫訪問技術的事務處理。
使用spring的事務處理機制,可以完成mybatis、hibernate等訪問資料庫的事務處理。
-
處理事務,需要怎麼做,做什麼
spring處理事務的模型,使用的步驟都是固定的。把事務使用的資訊提供給spring就可以了-
事務內部提交,回滾事務,使用的事務管理器物件,代替你完成commit,rollback
事務管理器是一個介面和他的眾多實現類。
介面:PlatformTransactionManager ,定義了事務重要方法commit , rollback
實現類: spring把每一種資料庫訪問技術對應的事務處理類都建立好了。
mybatis訪問資料庫---spring建立好的是DatasourceTransactionManagerhibernate 訪問資料庫----spring建立的是HibernateTransactionManager
怎麼使用:你需要告訴spring 你用是那種資料庫的訪問技術,怎麼告訴spring呢?
宣告資料庫訪問技術對於的事務管理器實現類,在spring的配置檔案中使用宣告就可以了例如,你要使用mybatis訪問資料庫,你應該在xml配置檔案中 <bean id="xxx" class=" . ..DataSourceTransactionManager">
-
業務方法需要什麼樣的事務,說明需要事務的型別。
說明方法需要的事務:
1)事務的隔離級別:
DEFAULT:採用 DB預設的事務隔離級別。Mysql的預設為REPEATABLE_READ;Oracle預設為 READ_COMITTED.READ
UNCOMMITTED:讀未提交。未解決任何併發問題。
READ_COMMITTED:讀已提交。解決髒讀,存在不可重複讀與幻讀。 REPEATABLE_READ:可重複讀。解決髒讀、不可重複讀,存在幻讀SERIALIZABLE:序列化。不存在併發問題。
2)事務的超時時間:表示一個方法的最長執行時間,如果方法執行超過了時間,事務就回滾
3)事務的傳播行為:控制業務方法是不是有事務的,是什麼樣的事務
7個傳播行為,表示業務方法呼叫時,事務在方法之間是如何使用的
<!--!!! PROPAGATION REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATIONsUPPORTS --> PROPAGATIONMANDATORY PROPAGATION_NESTED PROPAGATION_NEVER PROPAGATIONNOT_SUPPORTED
-
事務提交事務,回滾事務的時機
1)當你的業務方法,執行成功,沒有異常丟擲,當方法執行完畢,spring在方法執行後提交事務。事務管理器commit2)當你的業務方法丟擲執行時異常或ERROR,spring執行回滾,呼叫事務管理器的rollback
執行時異常的定義: RuntimeException 和他的子類都是執行時異常,例如Ntul1PointException , MunberFormatzxcept.
3)當你的業務方法丟擲非執行時異常,主要是受查異常時,提交事務
受查異常:在你寫程式碼中,必須處理的異常。例如IOException,SQLException
-
總結Spring事務:
- 管理事務的是 事務管理 和他的實現類
- spring的事務是一個統一模型
- 指定使用的事務管理器的實現類,使用
- 指定哪些類,哪些方法需要加入事務的功能
- 指定方法需要的隔離級別,傳播行為,超時
- 指定使用的事務管理器的實現類,使用
4.2 Spring的事務傳播機制
**Required **解義:如果上下文中已經存在事務,就加入到事務當中
上下文有事務 | 上下文沒有事務 | |
---|---|---|
Required | 加入到事務當中 | 新建事務 |
Supports | 加入到事務當中 | 非事務方式執行 |
Mandatory | 必須要有事務 | 丟擲異常 |
Requires_New | 新建事務 | 新建事務 |
Not_Supported | 事務掛起,方法結束後恢復事務 | |
Never | 丟擲runtime異常,強制停止執行 | |
Nested | 巢狀事務執行 | 新建事務 |
二、SpringMVC
1.1 MVC在B/S下的應用
mvc是一個設計模式
1.2 springmvc框架
過程
1、發起請求到前端控制器
2、前端控制器請求HandlerMapping查詢Handler
根據xml配置、註解進行查詢
3、處理器對映器HandlerMapping向前端控制器返回Handler
4、前端控制器用處理器介面卡去執行Handler
5、理器介面卡執行Handler
6、Handler執行完成給介面卡返回ModelAndView
7、處理器向前端控制器返回ModelAndView
ModelAndView是springmvc框架的一個底層物件,包括model 和 view
8、前端控制器請求檢視解析器去進行檢視解析
根據邏輯檢視名解析程真正的檢視jsp
9、檢視解析器向前端控制器返回View
10、前端控制器進行檢視渲染
檢視渲染將模型資料(在ModelAndView中)填充到request域
11、前端控制器向用戶返回響應結果
元件:
1、前端控制器DispatcherServlet,(不需要程式設計師開發)
接收請求,響應結果,相當於轉發器,中央處理器
減少其他元件之間的耦合度
2、處理器對映器HandlerMapping,(不需要程式設計師開發)
根據請求的url查詢Handler
3、處理器介面卡HandlerAdapter(不需要程式設計師開發)
按照特定規則(HandlerAdapter要求的規則)去執行Handler
編寫Handler時按照HandlerAdapter的要求去做才能正確執行Handler
4、處理器Handler,(需要程式設計師開發)
5、檢視解析器View Resolver
檢視解析,根據邏輯檢視域名解析成真正的檢視View
6、檢視View,(需要程式設計師開發jsp)
是一個介面,實現類支援不同的View型別(jsp、freemarker、pdf...)
2、 json資料互動
2.1、使用json互動的原因:
json資料格式在介面呼叫中、html頁面中常用,json格式簡單,解析比較方便
2.2、springmvc進行json互動
springmvc中使用jackson的jar包進行json轉換
客戶端請求key / value串 | |
---|---|
請求的是json串 contenttype=application/json |
請求的是key / value contenttype= |
@RequestBody將json串轉成java物件 | 不需要@RequestBody將json串轉成java物件 |
@ResponseBody將java物件轉成json輸出 | @ResponseBody將java物件轉成json輸出 |
最後都輸出json資料,為了在前端頁面方便對請求結果進行解析 |
1、請求json、輸出json,要求請求的是json串,所以在前端頁面中需要將請求的內容轉成json,不太方便
2、請求key / value ,輸出json,比較常用
3、Restful支援
restful是一種開發理念,是對http的一個詮釋,即表現層狀態的轉化
對url進行規範,寫restful格式的url,就是簡潔
非rest的url:http://.../finditems.action?id=001
rest的url風格:http://.../items/001