1、認識Spring框架 1.1 Spring框架定義 定義:Spring是 輕量級的開源框架 。以 IOC(控制反轉)和AOP(面向切面編程)為內核 ,使用 最基本的JavaBean 完成工作。 1.2 Spring框架的優點 控制反轉(IOC)和
1、認識Spring框架
1.1 Spring框架定義
- 定義:Spring是輕量級的開源框架。以IOC(控制反轉)和AOP(面向切面編程)為內核,使用最基本的JavaBean完成工作。
1.2 Spring框架的優點
- 控制反轉(IOC)和依賴注入(DI)實現松耦合,簡化開發。
- 支持AOP(面向切面編程),并且把應用業務與系統服務分開。
- 支持聲明式事務處理。通過配置就可以完成對事務的處理,提高開發效率。
- 方便程序的測試。Spring支持JUnit4的支持,添加注解便可以測試Spring。
- 方便集成各種優秀框架。內部提供了對一些框架的直接支持。
- 降低了Java EE API的使用難度。對JDBC、Mail等模塊進行了封裝。
1.3 Spring框架體系結構和模塊組成
- 體系結構:分層架構
- 主要模塊
- Core Container(核心容器層):是其他模塊建立的基礎,主要模塊組成:
- Beans模塊:提供了BeanFactory(工廠模式),Spring將管理對象稱為Bean。
- Core模塊:提供了Spring框架的基本組成部分,包括IOC(控制反轉)和DI(依賴注入)功能。
- Context模塊:建立在Beans和Core基礎之上,訪問定義和配置的任何對象的媒介。ApplicationContext接口是Context模塊的焦點。
- Context-support模塊:提供了第三方庫嵌入Spring應用的集成支持。
- DataAccess/Integration(數據訪問/集成層)
- JDBC模塊:提供了JDBC的抽象層,大幅度地減少了在開發過程中對數據庫操作的編碼。
- ORM模塊:對流行的對象關系映射API,包括JPA、JDO、Hibernate提供了集成層面支持。
- OMX模塊:提供了一個支持對象/XML映射的抽象層實現,如JAXB、Castor、XStream等。
- JMS模塊:Java消息傳遞,使用和傳遞信息的特性。
- Transactions事務模塊:支持對實現特殊接口以及所有實體類的編程和注解式的事務管理。
- Web層
- WebSocket模塊:提供了WebSocket和SockJS的實現。
- Servlet模塊:Spring-MVC模塊,包含了Spring模型-視圖-控制器(MVC)。
- 其他模塊
- AOP模塊:提供了面向切面編程的實現,允許定義方法攔截器和切入點,將代碼按照功能進行分離,降低耦合性。
- Aspects模塊:提供了AspectJ一個強大且成熟的AOP框架。
- Test模塊:提供了單元測試和集成測試的支持。
- 體系結構圖
1.4 Spring框架的兩種核心容器
- BeanFactory:基礎類型的IOC容器,提供了完整的IOC服務支持。BeanFactory就是一個管理Bean的工廠,它主要負責初始化各種Bean,并調用它們的生命周期方法。
- ApplicationContext:它是BeanFactory的子接口,除了提供BeanFactory的所有功能外,還添加了對國際化、資源訪問、事件傳播等方面的支持。
- 創建ApplicationContext的三種方式:
- ClassPathXmlApplicationContext(從類路徑中讀取配置文件)創建:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml")
- FileSystemXmlApplicationContext(參數指定的配置文件位置)創建:
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationContext.xml")
- Web服務器實例化ApplicationContext,基于ContextLoaderListener實現。
1.5 獲取Spring中的Bean
-
Object getBean(String name)
:根據Bean的id或者name來獲取指定的Bean,需要強轉。 -
<T> T getBean(Class<T> requiredType)
:根據類的類型來獲取Bean實例,有泛型不需要強轉。
1.6 BeanFactory和ApplicationContext的區別
- 功能上的區別。
- BeanFactory是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命周期,維護bean之間的依賴關系。
- ApplicationContext接口作為BeanFactory的派生,除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能,如繼承MessageSource、支持國際化、統一的資源文件訪問方式、同時加載多個配置文件等功能。
- 加載方式的區別
- BeanFactory采用的是延遲加載的形式來注入Bean,即只有在使用到某個Bean時(調用getBean()),才對該Bean進行加載實例化。如果Bean的某一個屬性沒有注入,BeanFacotry加載后,直至第一次使用調用getBean方法才會拋出異常。
- ApplicationContext在容器啟動時,一次性創建了所有的Bean。在容器啟動時就可以檢查所依賴的屬性是否注入。
- 創建方式的區別
- BeanFactory通常以編程的方式被創建。
- ApplicationContext除了使用編程方式創建(new 實例),還能以聲明的方式創建,例如使用ContextLoader。
- 注冊方式的區別:BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用。
- BeanFactory需要手動注冊。
- ApplicationContext是自動注冊的。
1.7 控制反轉(IOC)和依賴注入(DI)
- 控制反轉
- 概念:IOC也稱控制反轉,由Spring容器管理Bean的整個生命周期,通過反射實現對其他對象的控制,對象的實例不再由調用者來創建,而是由Spring容器來創建,有效的降低類之間的耦合度。
- IOC的好處
- 資源集中管理,實現資源的可配置和易管理。
- 降低了使用資源雙方的依賴程度,耦合度。
- 依賴注入
- 概念:DI也稱依賴注入,在Spring創建對象過程中,把對象依賴的屬性注入到對象中。
- 主要的兩種方式:屬性setter方法注入和構造器注入。
2、Spring中的Bean
2.1 Bean的三種實例化方式
- 構造器實例化:Spring容器通過Bean對應類中默認的無參構造器來實現實例化Bean。
- 靜態工廠方式實例化:配置factory-method屬性。
- 實例工廠方式實例化:配置factory-bean、factory-method屬性。
2.2 Bean的作用域
- singleton(單例):Spring容器中的默認作用域,該作用域表示使用singleton定義的Bean在Spring容器中將只有一個實例。無論有多少個Bean引用它,始終將指向同一個對象。
- prototype(原型):每次通過Spring容器獲取prototype定義的Bean時,容器都將創建一個新的Bean實例。
- request:對不同的Http請求每次請求都會產生一個新的Bean,僅在當前Http request內有效。
- session:對不同的Http請求每次請求都會產生一個新的Bean,僅在當前Http session內有效。
- globalSession:在一個全局的Http Session中,容器會返回該Bean的同一個實例。僅在使用portlet上下文時有效。
2.3 Bean的生命周期
注意:Spring可以管理Singleton單例作用域的Bean完整的生命周期,對于Prototype多例作用域的Bean,Spring只負責創建,創建實例后,Bean的實例就交由客戶端代碼管理,Spring不再跟蹤其生命周期。生命周期圖示:
- 調用bean的構造方法創建Bean。
- 通過反射調用setter方法進行屬性的依賴注入。
- 如果Bean實現了BeanNameAware接口,Spring將調用setBeanName(),設置Bean的name(xml文件中bean標簽的id)。
- 如果Bean實現了BeanFactoryAware接口,Spring將調用setBeanFactory() 把beanfactory設置給Bean。
- 如果存在BeanPostProcessor ,Spring將調用它們的postProcessBeforeInitialization (預初始化)方法,在Bean初始化前對其進行處理。
- 如果Bean實現了InitializingBean接口,Spring將調用它的afterPropertiesSet方法,然后調用xml定義的 init-method方法,兩個方法作用類似,都是在初始化bean的時候執行。
- 如果存在BeanPostProcessor ,Spring將調用它們的postProcessAfterInitialization (后初始化)方法,在Bean初始化后對其進行處理。
- Bean初始化完成,供應用使用,這里分兩種情況:
- 如果Bean為單例的話,那么容器會返回Bean給用戶,并存入緩存池。如果Bean實現了DisposableBean接口,Spring將調用它的destory方法,然后調用在xml中定義的destory-method方法,這兩個方法作用類似,都是在Bean實例銷毀前執行。
- 如果Bean是多例的話,容器將Bean返回給用戶,剩下的生命周期由用戶控制。
2.4 Bean的裝配方式(依賴注入)
- 基于XML裝配:setter注入和構造器注入。
- 注解方式裝配
- @Configuration+@Bean注解:@configuration聲明該類是一個配置類,并將該類交由Spring管理,@Bean一般加在該類的方法上,表示該方法會返回一個Bean。
- 通過包掃描特定注解方式:@ConponentScan放在配置類上,然后指定一個路徑,進行掃描帶有特定注解的Bean,然后加到Spring容器中。特定注解包括@Controller、@Service、@Repository、@Component等。
- 自動裝配:通過設置Autowrited屬性值實現自動裝配。
- 根據類型自動裝配:byType,必須存在setter方法。
- 根據名稱自動裝配:byName。
- 根據構造方法自動裝配。
- 存在單例的Bean優先按照類型進行參數匹配,當存在多個類型相同實例時,按照名稱優先匹配,沒有找到則匹配失敗。
2.5 @Autowrited和@Resource注解
- 兩個注解都可以實現Bean的自動裝配。
- @Autowrited默認按照類型進行裝配(byType)。
- @Resource默認按照Bean的名稱進行裝配(byName)。
- @Resource有name和type兩個屬性,指定誰就按照誰來裝配,若都不指定,默認byName,若都沒有匹配到,拋異常。
- @Qualifier與@Autowrited注解配合使用,會將默認按照Bean類型裝配改為按照Bean的名稱進行裝配。
- 對于配置文件中獲取值以及一些簡單類型(int、long、String等)進行依賴注入,可以直接使用@Value注解。
// 詳細使用Spring Boot中說明
@Value("${jdbc.url}")
private String url;
2.6 @Component和@Bean注解的區別
- @Bean是Java代碼裝配Bean,@Component是自動裝配Bean。
- @Component注解用在類上,表示一個類會作為組件類,并告知Spring要為這個類創建Bean,每個類對應一個Bean。
- @Bean注解用在方法上,表示這個方法會返回一個Bean,一般@Bean使用在配置類中,類上需要使用@Configuration注解。
2.7 常用的特定注解
- @Component:最普通的組件,可以被注入到Spring容器中管理,以下注解也可被注入到Spring中管理。
- @Controller:將類標記為Spring web mvc的控制器。
- @Service:將類標記為業務層組件。
- @Repository:將類標記為數據訪問層組件。
2.8 Spring Bean如何保證并發安全
- 單例模式變原型模式。
- 盡量避免使用成員變量。
- 使用并發安全的類,CurrentHashMap等。
- 分布式或微服務的并發安全:使用Redis等中間件。
3、Spring AOP
3.1 初識AOP
- 概念:AOP也稱為面向切面編程,它是OOP(面向對象編程)的一種補充。
- AOP將公共邏輯(事務管理、日志、緩存等)封裝成切面。與業務代碼進行分離,可以減少系統的重復代碼和降低模塊之間的耦合度。
- 切面就是那些與業務無關,但所有業務模塊都會調用的公共邏輯。
- AOP框架
- Spring AOP:使用純Java實現,不需要專門的編譯過程和類加載器,在運行期間通過代理的方式向目標類織入增強的代碼。
- AspectJ:一個基于Java語言的AOP框架,它擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入。
3.2 使用AOP的好處
- 有效的減少了系統的重復代碼,降低了模塊間的耦合度。
- 提高代碼的復用性。
- 更好的分離關注點,提高代碼的可讀性和可維護性。
3.3 AOP的專業術語
- 切面(Aspect):封裝的用于橫向插入系統功能(事務、日志等)的類。
- 連接點(JoinPoint):在程序執行過程中的某個階段點,它實際上是對象的一個操作。在Spring AOP框架中,指的就是方法的調用。
- 切入點(Pointcut):切面與流程的交叉點,即那些需要處理的連接點。通常在程序中,切入點指的是具體的類或方法名,又或者是正則表達式所匹配到的一些類或方法名。
- 通知/增強處理(Advice):在定義好的切入點處所要執行的代碼,理解為切面類中的方法,切面的具體實現。
- 目標對象(Target Object):所有被通知的對象,通常是一個代理對象。
- 代理(Proxy):將通知應用到目標對象之后,被動態創建的對象。
- 織入(Weaving):將切面代碼插入到目標對象上,從而生成代理對象的過程。
3.4 AOP中織入的時機
*應對的是目標對象的生命周期
- 編譯期:切面在目標類編譯時被織入,AspectJ框架就是這樣實現的。
- 加載期:切面在目標類加載到JVM時織入,需要特殊的類加載器。
- 運行期:切面在應用運行的某個時刻被織入,一般情況下,在織入切面時,AOP容器會為目標對象動態的創建一個代理對象,Spring AOP框架就是以這種方式織入的切面。
3.5 AOP的實現方式(代理方式)
- 靜態代理
- 實現機制:代理類在編譯階段生成,在編譯階段將通知織入Java字節碼中,編譯期增強。AspectJ框架使用的是靜態代理。
- 缺陷:代理對象需要與目標對象實現一樣的接口,并且實現接口的方法存在一定的冗余代碼,其次,一旦接口增加方法,目標對象與代理對象都需要進行維護。
- 動態代理
- 實現機制:代理類在程序運行時創建,Spring AOP框架不會去修改字節碼,而是在內存中臨時生成一個代理對象,在運行期間對業務方法進行增強。
3.6 Spring AOP的實現原理
通過動態代理實現的。如果我們為Spring的某個Bean配置了切面,那么Spring在創建這個Bean的時候,實際上創建的是這個Bean的一個代理對象,后續對目標類Bean的方法調用,實際上調用的是代理類重寫的代理方法。
3.7 Spring AOP主要的兩種動態代理
- JDK動態代理
- 實現機制:如果目標類實現了接口,Spring AOP會選擇使用JDK動態代理目標類。代理類根據目標類實現的接口動態生成,不需要自己編寫,生成的動態代理類和目標類都實現相同的接口。
- 核心:實現InvocationHandler接口和Proxy類
- 局限性:目標類必須實現一個或多個接口,如果類沒有實現接口,就不能使用JDK動態代理該目標類。
- CGLIB動態代理
- 實現機制:CGLIB動態代理是通過繼承實現的。如果目標類沒有實現一個或多個接口,Spring AOP框架會選擇使用CGLIB動態代理目標類。CGLIB動態代理可以在運行時動態生成目標類的字節碼,動態創建目標類的子類對象,在子類對象中增強目標類。
- 特別注意:由于CGLIB動態代理是通過繼承實現的,如果某個類使用了final關鍵字修飾,該類將無法被繼承,所以就無法使用CGLIB動態代理目標類。
- 相比于JDK動態代理的優勢:目標類不需要實現接口,更加靈活。
- Spring AOP框架對兩種動態代理的使用場景
- 如果目標類實現了接口,Spring AOP框架默認使用JDK動態代理,也可強制使用CGLIB動態代理。
- 如果目標類沒有實現接口,必須使用CGLIB動態代理。
3.8 JDK動態代理和CGLIB動態代理的區別
- JDK動態代理使用JDK中的Proxy類來創建代理對象,它使用反射技術來實現,不需要導入其他依賴;CGLIB需要引入相關依賴-asm.jar它使用字節碼增強技術來實現。
- 當目標類實現了接口的時候,Spring AOP框架默認使用的是JDK動態代理增強方法,目標類沒有實現接口的時候,使用CGLIB動態代理。
3.9 Spring的通知類型
- 環繞通知(Around):在目標方法執行前后實施增強,可以應用于日志、事務管理等功能。
- 前置通知(Before):在目標方法執行前實施增強,可以應用于權限管理等功能。
- 后置通知(After-running):在目標方法執行后實施增強,可以應用于關閉流、上傳/刪除臨時文件等功能。
- 異常通知(After-throwing):在方法拋出異常后實施增強,可以應用于處理異常、記錄日志等功能。
- 引介通知(IntroductionInterceptor):在目標類中添加一些新的屬性和方法,通常用于老版本程序的修改。
3.10 基于注解使用AspectJ
- @Aspect:注解用在類上,標注該類是一個切面類。
- @Pointcut:定義切入點表達式,需要指定一個包含和任意參數的方法簽名來表示切入點名稱。通常為返回值為viod的空方法。
- @通知類型(Before/After等):標注在方法上,value值傳入切入點的空方法名。@After最終通知,不管是否異常,該通知都會執行。
- 使用前需要先導入AOP和AspectJ的依賴(Spring Boot)
<!-- 復制粘貼下載即可 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
/**
* 定義切面類
*/
@Aspect
@Component
public class MyAspect {
// 切點
@Pointcut("execution(* com.lz.learning.*.*(..))")
public void myPointCut() {
}
// 前置通知
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint) {
System.out.println("前置通知,目標類:" + joinPoint.getTarget() + ",增強的目標方法:"
+ joinPoint.getSignature().getName());
}
// 后置通知
@AfterReturning("myPointCut()")
public void myAfterRunning(JoinPoint joinPoint) {
System.out.println("后置通知,目標類:" + joinPoint.getTarget() + ",增強的目標方法:"
+ joinPoint.getSignature().getName());
}
// 環繞通知
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("模擬環繞開始...");
// 執行當前目標方法
Object obj = proceedingJoinPoint.proceed();
System.out.println("模擬環繞結束...");
return obj;
}
// 異常通知
@AfterThrowing(value = "myPointCut()", throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("異常通知:" + e.getMessage());
}
// 最終通知,不管是否異常,該通知都會執行
@After("myPointCut()")
public void myAfter() {
System.out.println("最終通知...");
}
}
4、Spring的事務管理
4.1 認識Spring事務
- 概念:多個操作單元組成的集合,多個單元操作是整體不可分割的。
- 基本特性:原子性、一致性、隔離性、持久性。
- Spring事務的實現方式
- 編程式事務:通過編程式的方式進行管理事務,靈活性強,但很難維護。
- 聲明式事務:將事務管理代碼從業務方法中分離出來,通過AOP進行封裝,無需處理關閉連接、提交/回滾等操作。
4.2 Spring事務管理的核心接口
- PlatformTransactionManager接口:Spring提供的平臺事務管理器來管理事務。主要實現方法:
-
TransactionStatus getTransaction(TransactionDefinition td)
:獲取事務的狀態信息。 -
void commit(TransactionStatus status)
:事務提交。 -
void rollback(TransactionStatus status)
:事務回滾。
- TransactionDefinition接口:事務描述的對象,定義了事務的規則。
-
String getName()
:獲取事務對象的名稱。 -
int getlsolationLevel()
:獲取事務的隔離級別。 -
int getPropagationBehavior()
:獲取事務的傳播行為。 -
int getTimeout()
:獲取事務的超時時間。 -
boolean isReadOnly()
:是否是只讀事務。
- TransactionStatus接口:事務的狀態,某一時間點上事務的狀態信息。
-
void flush()
:刷新事務。 -
boolean hasSavepoint()
:獲取事務是否存在保存點。 -
boolean isCompleted()
:獲取事務是否完成。 -
void setRollbackOnly()
:設置事務回滾。
4.3 @Transactional注解
- 作用域
- 聲明在類上:表示整個類的所有方法都起作用。
- 聲明在方法上:表示只對當前方法有效。
- 可配置的相關參數
- value:指定需要使用的事務管理器。默認為"",其別名為transactionManager。
- isolation:指定事務的隔離級別,默認為DEFAULT。
-
noRollbackFor
:指定遇到特定異常時強制不回滾事務。noRollbackFor=RuntimeException.class -
rollbackFor
:指定遇到特定異常強制回滾事務。不指定默認為對RuntimeException異常進行回滾,一般可以指定Exception,rollbackFor=Exception.class - noRollbackForClassName:指定遇到特定的多個異常強制不回滾事務,可以指定多個異常類名。
- rollbackForClassName:指定遇到特定的多個異常強制回滾事務,可以指定多個異常類名。
-
read-only
:指定事務是否為只讀,默認false。 - propagation:指定事務的傳播行為,默認為REQUIRED。
- timeout:指定事務的超時時間,默認為TIMEOUT_DEFAULT(底層事務系統的默認時間)。
4.4 @Transactional注解失效的情況
- 訪問權限的問題
- 權限大小:
private < default < protected < public
- 如果所注解的方法的訪問權限不是public,會導致事務失效,Spring要求被代理方法必須是public。
- 目標方法使用了final關鍵字
- 如果目標方法使用了final關鍵字修飾,事務會失效。
- 原因:Spring事務底層使用了AOP,通過JDK的動態代理或者CGLIB動態代理的方式生成了代理類,在代理類中實現了事務的功能,使用final修飾有悖于兩種動態代理的底層機制。
- 對象沒有被Spring管理
- 使用Spring事務的前提是對象要被Spring容器管理,需要創建Bean的實例,如果類沒有加@Component、@Service、@Controller等特定注解,該類也就沒有交由Spring去管理,事務不會生效。
- 表的存儲引擎不支持事務
- 如果MySQL使用的存儲引擎是myisam,它是不支持事務的。
- 異常被捕獲后沒有拋出[實際開發中常遇到]
- 目標方法中使用了
try{}catch(){}
手動捕獲了異常,并對異常做了處理,沒有繼續拋出異常或異常被吞掉了,此時Spring事務機制認為異常已經被處理,沒有了異常,自然也不會觸發回滾。 - 若需要事務能夠回滾生效,手動捕獲后可以再手動的拋出它所接收的異常。
@Transactional(rollbackFor = Exception.class)
public int test() {
int y = 12;
int x = 0;
int result = 0;
try {
// 算術異常
result = y / x;
} catch (Exception e) {
result = -1;
System.out.println(e.getMessage());
// 捕獲異常處理之后不再拋出,事務失效
// 捕獲處理之后需將異常拋出,此時事務才會生效
throw new RuntimeException(e.getMessage(), e);
}
return result;
}
- 一個類的方法的內部調用
- 同一類中,某個方法方法調用了加了事務注解的目標方法,此時事務注解不會生效。
- 原因:這實際上是在同一個對象中調用了方法,并沒有經過Spring的代理類,所以事務會失效。
@Component
public class MyTransaction {
@Transactional(rollbackFor = Exception.class)
public void printA() {
System.out.println("A");
}
public void printB() {
// 內部直接調用事務方法,此時A方法事務不生效
printA();
}
}
- 未開啟事務
- 如果是Spring項目,需要在配置中手動配置開啟事務的相關參數。
- 如果是Spring Boot項目,不需要手動配置,因為在DataSourceTransactionManagerAutoConfiguration類中已經開啟了事務。
5、Spring MVC
5.1 MVC模式
- 定義:MVC(model模型-view視圖-controller控制器)是一種軟件設計規范,是將業務邏輯、數據、顯示分離的方法來組織代碼。MVC不是一種設計模式,而是一種架構模式。
- 主要作用:降低了視圖與業務邏輯的雙向耦合,代碼的重用性高,易于維護和擴展。
- 分層解讀
- model層:用于處理應用程序中數據邏輯的部分。
- view層:負責進行模型的展示,一般是用戶界面。
- controller層:接收用戶輸入并返回數據的部分,數據交互。
5.2 認識Spring MVC
- 定義:Spring提供的一個實現了Web MVC模式的輕量級web框架,屬于Spring框架的一個模塊。
- 實現機制:Spring MVC通過一套注解讓一個簡單的Java類成為處理請求的控制器,而無需實現任何接口,同時它還支持REST風格的請求。
- 特點:
- 它是Spring框架的一部分,可以方便使用Spring框架提供的其他功能。
- 靈活性強,易于和其他框架集成。
- 可自動綁定用戶輸入,正確轉換數據類型。
- 支持國際化,根據用戶區域顯示多國語言。
- 支持多種視圖技術,JSP、Velocity等。
- 支持REST風格請求。
- 提供了一個前端控制器DispatcherServlet,無需額外開發控制器對象。
- 內置常見的校驗器,可以校驗用戶輸入。校驗不通過會重定向到原表單。
5.3 Spring MVC的主要組件
- 前端控制器(DispatcherServlet):接收用戶請求,給用戶返回結果。
- 處理器映射器(HandlerMapping):根據請求的URL路徑,通過XML配置或者注解來尋找匹配的處理器。
- 處理器適配器(HandlerAdapter):Handler處理器的適配器,調用Handler中的方法處理請求。
- 處理器(Handler):執行相關的請求處理邏輯,并返回相應的數據和視圖信息,將其封裝到ModelAndView對象中。
- 視圖解析器(ViewResolver):將視圖邏輯解析成真正的View視圖。
- 視圖(View):View接口,實現類可支持不同的View類型(JSP等)。
5.4 Spring MVC內部的工作流程
- 用戶通過客戶端向服務器發送請求,請求會被Spring MVC的前端控制器DispatcherServlet攔截。
- DispatcherServlet攔截到請求后,會調用HandlerMapping處理器映射器。
- 處理器映射器根據請求的URL找到具體的處理器,生成處理器對象以及處理器攔截器,一并返回給前端控制器。
- 前端控制器會通過返回的信息選擇合適的HandlerAdapter處理器適配器。
- 處理器適配器會調用并執行Handler處理器,這里的處理器指的就是程序中的Controller類,也被稱為后端控制器。
- Controller執行完之后,會返回一個ModelAndView對象,包含模型和視圖名。
- 處理適配器將ModelAndView對象返回給前端控制器
- 前端控制器會根據ModelAndView對象選擇一個合適的ViewResolver視圖解析器。
- ViewResolver解析之后,會向前端控制器中返回具體的View視圖。
- 前端控制器對View視圖進行渲染。
- 渲染結果會返回給客戶端瀏覽器進行顯示。
5.5 Spring MVC常用注解
- @Controller:標識此類的實例是一個控制器。
- 機制:Spring容器會掃描該類,然后掃描該類下面的帶有@RequestMapping注解的方法,為這個方法生成一個對應的處理器對象。
- @RequestMapping:映射一個請求或映射一個方法。
- 標注在方法上:該方法成為一個請求處理的方法,它會在接收到對應的URL請求時被調用。
- 標注在類上:該類所有的方法都將映射為相對于類級別的請求,該控制器所處理的所有請求都被映射到value屬性所指定的路徑下(常用在類上)。
- @Get/Post/Put/Delete/PatchMapping:匹配GET/POST等方式的請求。
- @RequestBody:接收Http請求的JSON數據,將JSON數據轉換為Java對象,標注在方法的形參上。
- @ResponseBody:返回JSON格式的數據,標注在方法上。
- @PathVariable:獲得URL路徑中的變量的值,常與REST風格請求適配,標注在方法的形參上。
- 若請求參數中的變量名與形參的名稱相同,注解后可以省略標注。
@GetMapping("user/{id}")
// 注解里面的id可以省略
public User getUserById(@PathVariable("id") int id)
- @RestController:組合注解,@Controller + @ResponseBody
- @ExceptionHandle:標識一個方法為全局異常處理的方法。
5.6 Spring MVC的異常處理
可以將異常拋給Spring框架,由Spring框架來處理;只需要配置簡單的異常處理器,在異常處理器中添視圖頁面即可。
- 使用系統定義好的異常處理器 SimpleMappingExceptionResolver
- 使用自定義異常處理器
- 使用異常處理注解
5.7 Spring MVC用什么對象從后臺向前臺傳遞數據
- 將數據綁定到request中。
- 返回ModelAndView。
- 通過ModelMap對象,可以在這個對象里面調用put方法,把對象加到里面,前端就可以通過el表達式拿到。
- 綁定數據到 Session中。
5.8 @RequestParam和@PathVariable的區別
兩個注解都作用于方法的形參上,它們獲取參數值的方式不同。@RequestParam注解的參數值從請求攜帶的參數中獲取,而@PathVariable從請求的URL中獲取。
5.9 @RequestBody和@RequestParam的區別
處理的請求數據類型不同
- @RequestBody一般處理的是ajax請求中contentType:application/json類型的數據,也就是JSON或XML格式數據。
- @RequestParam:一般處理沒有聲明contentType格式的數據。
5.10 REST風格
- 定義:一種軟件架構的風格或設計風格,而不是一個標準。
- Representational:某種表現形式,例如:JSON、XML等
- states Transfer:狀態變化,通過Http method實現。
- 表現形式:把請求參數變為請求路徑的一種風格。例
- 原:
http://.../queryItems?id=6
;REST:http://.../items/6
- REST風格中URL不存在動詞形式的路徑,在HTTP請求中,put(添加)、delete(刪除)、post(修改)、get(查詢)
- 通常配合@PathVariable注解使用。
- 使用REST的優勢
- 風格統一
- 面向資源,具有自解釋性
- 充分利用http本身語義
5.11 Spring MVC攔截器
- 概述:主要用于攔截用戶請求并作相應的處理,用于權限驗證、記錄請求、判斷登錄等功能。
- 實現方式:通過實現HandlerInterceptor接口中的方法(常用的一種)
- preHandler():該方法會在Controller控制器的方法執行前執行,其返回值表示是否中斷后續操作。返回true,繼續向下執行,返回false將中斷后續所有操作。
- postHandler():控制器方法執行之后再執行,且解析視圖之前執行。可以對請求域中的模型和視圖做出進一步的修改。
- afterCompletion():該方法會在整個請求完成,即視圖渲染結束之后執行。實現一些資源清理、記錄日志等功能。
- 三個方法的執行順序
preHandler -> controller中的方法 -> postHandler -> 前端控制器 -> afterCompletion
- Spring MVC攔截器的XML配置
<!-- 配置Spring Mvc攔截器 -->
<mvc:interceptors>
<bean id="myInterceptor" class="com.dabin.MyHandlerInterceptor">
</bean>
<!-- 只攔截部分請求 -->
<mvc:interceptor>
<mvc:mapping path="/xxx.do" />
<bean class="com.dabin.MyHandlerInterceptorAdapter" />
</mvc:interceptor>
</mvc:interceptors>
5.12 Spring MVC攔截器和Filter過濾器的區別
- 功能相同:都可以實現相同的功能。
- 容器不同:攔截器構建在Spring MVC體系中,Filter構建在servlet容器之上。
- 使用的便利性不同:前者實現了三個方法,分別在不同的時機執行,Filter過濾器僅提供了一個方法。
聲明:所有內容來自互聯網搜索結果,不保證100%準確性,僅供參考。如若本站內容侵犯了原著者的合法權益,可聯系我們進行處理。