1、spring的好處/特點
- 輕量:Spring是輕量的,基本的版本大約2MB。
- 控制反轉(IOC):Spring通過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。
- 面向切面的編程(AOP):Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開。
- 容器:Spring包含並管理應用中對象的生命週期和配置。
- MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
- 事務管理:Spring提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)。
- 異常處理:Spring提供方便的API把具體技術相關的異常(比如由JDBC,Hibernateor JDO拋出的)轉化爲一致的unchecked 異常。
2、Spring主要模塊組成
- Core module
- Bean module
- Context module
- Expression Language module
- JDBC module
- ORM module
- OXM module
- Java Messaging Service(JMS) module
- Transaction module
- Web module
- Web-Servlet module
- Web-Struts module
- Web-Portlet module
3、Spring IOC/DI(控制反轉/依賴注入)
簡單的理解就是,原先將本程序中所使用到的對象,的生命週期交給容器去維護和管理。這就是IOC。SpringIOC 負責創建對象,管理對象(通過依賴注入(DI),裝配對象,配置對象,並且管理這些對象的整個生命週期。
對於DI的理解是,本類中所使用到的其他對象,在程序代碼中只需要聲明一下,相關實例化的工作交給了容器,容器會在運行期new出相應的對象,並賦值給程序代碼。這個過程類似於注入的過程。
4、ApplicationContext的實現
- FileSystemXmlApplicationContext:此容器從一個XML文件中加載beans的定義,XMLBean 配置文件的全路徑名必須提供給它的構造函數。
- ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這裏,你需要正確設置classpath因爲這個容器將在classpath裏找bean配置。
- WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的所有bean。
5、BeanFactory和ApplicationContext的區別
- BeanFactroy採用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),纔對該Bean進行加載實例化,這樣,我們就不能發現一些存在的Spring的配置問題。而ApplicationContext則相反,它是在容器啓動時,一次性創建了所有的Bean。這樣,在容器啓動時,我們就可以發現Spring中存在的配置錯誤。
- ApplicationContext建立在BeanFactory之上,並增加了其他的功能,比如更容易同SpringAOP特性整合, 消息資源處理(用於國際化),事件傳遞,以聲明的方式創建ApplicationContext,可選的父上下文和與應用層相關的上下文(比如WebApplicationContext),以及其他方面的增強。
表格 1 BeanFactory和ApplicationContext對比
特性 |
BeanFactory |
ApplicationContext |
Bean實例化/裝配 |
Yes |
Yes |
自動BeanPostProcessor註冊 |
No |
Yes |
自動BeanFactoryPostProcessor註冊 |
No |
Yes |
便捷的MessageSource訪問(i18n) |
No |
Yes |
ApplicationEvent發送 |
No |
Yes |
6、獲取ApplicationContext的方式
- 直接new出ApplicationContext
- 通過Spring提供的工具類獲取ApplicationContext對象(WebApplicationContextUtils)
- 繼承自抽象類ApplicationObjectSupport。說明:抽象類ApplicationObjectSupport提供getApplicationContext()方法,可以方便的獲取到ApplicationContext。Spring初始化時,會通過該抽象類的setApplicationContext(ApplicationContextcontext)方法將ApplicationContext 對象注入。
- 繼承自抽象類WebApplicationObjectSupport。說明:類似上面方法,調用getWebApplicationContext()獲取WebApplicationContext
- 實現接口ApplicationContextAware
說明:實現該接口的setApplicationContext(ApplicationContextcontext)方法,並保存ApplicationContext 對象。Spring初始化時,會通過該方法將ApplicationContext對象注入。
7 Spring IOC(依賴注入)的方式
- Setter方法注入
- 構造器方法注入
- 工廠方法注入(實例工廠/靜態工廠)
- 使用字段(Filed)注入(用註解方式)
- 自動裝配(需要開啓配置,不建議使用)
8 IOC方式建議(構造器注入還是 Setter方法注入)
兩種依賴方式都可以使用,構造器注入和Setter方法注入。最好的解決方案是用構造器參數實現強制依賴,setter方法實現可選依賴。
9 什麼是Spring beans
Springbeans是那些形成spring應用的主幹的Java對象。它們被SpringIOC容器初始化,裝配,和管理。這些beans通過容器中配置的元數據創建。比如,以XML文件中<bean/>的形式定義。
Spring框架定義的beans都是單例beans。在beantag中有個屬性”singleton”,如果它被賦爲TRUE,bean 就是單例,否則就是一個prototype bean。默認是TRUE,所以所有在Spring框架中的beans缺省都是單例。
10 Spring Bean定義包含什麼
一個SpringBean的定義包含容器必知的所有配置元數據,包括如何創建一個bean,它的生命週期詳情及它的依賴。
11 Spring容器提供配置元數據的方式
這裏有三種重要的方法給Spring容器提供配置元數據。
- XML配置文件。
- 基於註解的配置。
- 基於java的配置。
12 Spring類的作用域
Spring framework支持五種作用域(其中有三種只能用在基於web的SpringApplicationContext)。
表格 2 spring scope作用域詳解
singleton |
在每個Spring IoC容器中一個bean定義對應一個對象實例。 |
prototype |
一個bean定義對應多個對象實例。 |
request |
在一次HTTP請求中,一個bean定義對應一個實例;即每次HTTP請求將會有各自的bean實例,它們依據某個bean定義創建而成。該作用域僅在基於web的Spring ApplicationContext情形下有效。 |
session |
在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。 |
global session |
在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基於web的Spring ApplicationContext情形下有效。 |
13 Spring的單例bean是不是線程安全的
不,Spring框架中的單例bean不是線程安全的。
14 Spring中bean的生命週期
- Bean的建立:Spring容器從XML 文件中讀取bean的定義,並實例化bean。
- 屬性注入:Spring根據bean的定義填充所有的屬性。
- 如果bean實現了BeanNameAware接口,Spring傳遞bean的ID到setBeanName方法。
- 如果Bean實現了BeanFactoryAware接口,Spring傳遞beanfactory給setBeanFactory方法。
- 如果Bean實現了ApplicationContextAware接口,Spring傳遞applicationContext給setApplicationContext方法。
- 如果有任何與bean相關聯的BeanPostProcessors,Spring會在postProcesserBeforeInitialization()方法內調用它們。
- 如果bean實現IntializingBean了,調用它的afterPropertySet方法,如果bean聲明瞭初始化方法,調用此初始化方法。
- 執行Bean的init-method:可以在Bean定義文件中使用"init-method"屬性設定方法名稱例如:<beancalss="onlyfun.caterpillar.HelloBean"init-method="initBean">。
- 如果有BeanPostProcessors和bean 關聯,這些bean的postProcessAfterInitialization()方法將被調用。
- 如果bean實現了DisposableBean,它將調用destroy()方法。
- 執行Bean的destroy-method:在容器關閉時,可以在Bean定義文件中使用"destroy-method"屬性設定方法名稱,例如:<bean destroy-method="destroyBean">
15 Spring的內部bean
Spring的內部Bean在做注入時,只能用於當前的Bean屬性注入,在外不可以引用。在Spring的 基於XML的 配置元數據中,可以在<property/>或<constructor-arg/> 元素內使用<bean/> 元素,內部bean通常是匿名的,它們的Scope一般是prototype。
16 Spring中注入java集合
Spring提供以下幾種集合的配置元素:
- <list>類型用於注入一列值,允許有相同的值。
- <set>類型用於注入一組值,不允許有相同的值。
- <map>類型用於注入一組鍵值對,鍵和值都可以爲任意類型。
- <props>類型用於注入一組鍵值對,鍵和值都只能爲String類型
17 bean裝配和自動裝配
bean 裝配:是指在Spring容器中把bean組裝到一起,前提是容器需要知道bean的依賴關係,如何通過依賴注入來把它們裝配到一起。
Spring容器能夠自動裝配相互合作的bean,這意味着容器不需要<constructor-arg>和<property>配置,能通過Bean工廠自動處理bean之間的協作。
18 Spring自動裝配的方式
有五種自動裝配的方式,可以用來指導Spring容器用自動裝配方式來進行依賴注入。
- no:默認的方式是不進行自動裝配,通過顯式設置ref屬性來進行裝配。
- byName:通過參數名自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byname,之後容器試圖匹配、裝配和該bean的屬性具有相同名字的bean。
- byType::通過參數類型自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byType,之後容器試圖匹配、裝配和該bean的屬性具有相同類型的bean。如果有多個bean符合條件,則拋出錯誤。
- constructor:這個方式類似於byType,但是要提供給構造器參數,如果沒有確定的帶參數的構造器參數類型,將會拋出異常。
- autodetect:首先嚐試使用constructor來自動裝配,如果無法工作,則使用byType方式。
19 自動裝配的侷限性
自動裝配的侷限性是:
- 重寫:你仍需用<constructor-arg>和<property> 配置來定義依賴,意味着總要重寫自動裝配。
- 基本數據類型:你不能自動裝配簡單的屬性,如基本數據類型,String字符串和類。
- 模糊特性:自動裝配不如顯式裝配精確,如果有可能,建議使用顯式裝配。
20 基於Java的spring註解配置(給一些註解的例子)
基於Java的配置,允許你在少量的Java註解的幫助下,進行你的大部分Spring配置而非通過XML文件。
以@Configuration註解爲例,它用來標記類可以當做一個bean的定義,被SpringIOC容器使用。另一個例子是@Bean註解,它表示此方法將要返回一個對象,作爲一個bean註冊進Spring應用上下文。(一般很少用java代碼對元數據進行配置)
21 Spring基於註解的容器配置、和開啓配置
相對於XML文件,註解型的配置依賴於通過字節碼元數據裝配組件,而非尖括號的聲明。開發者通過在相應的類,方法或屬性上使用註解的方式,直接組件類中進行配置,而不是使用xml表述bean的裝配關係。
註解裝配在默認情況下是不開啓的,爲了使用註解裝配,我們必須在Spring配置文件中配置<context:annotation-config/> 元素。(<context:annotation-config/>標籤可以開啓自動掃描,同時也開啓註解裝配)
22 Spring註解簡介
- @Required:這個註解表明bean的屬性必須在配置的時候設置,通過一個bean定義的顯式的屬性值或通過自動裝配,若@Required註解的bean屬性未被設置,容器將拋出BeanInitializationException。
- @Autowired:註解提供了更細粒度的控制,包括在何處以及如何完成自動裝配。它的用法和@Required一樣,修飾setter方法、構造器、屬性或者具有任意名稱和/或多個參數的PN方法。
- @Qualifier:當有多個相同類型的bean卻只有一個需要自動裝配時,將@Qualifier註解和@Autowire 註解結合使用以消除這種混淆,指定需要裝配的確切的bean。
23 @Autowired 和@Resource 的區別
- @Autowired和@Resource都可以用來裝配bean,都可以寫在字段上,或者方法上。
- @Autowired屬於Spring的;@Resource爲JSR-250標準的註釋,屬於J2EE的。
- @Autowired默認按類型裝配,默認情況下必須要求依賴對象必須存在,如果要允許null值,可以設置它的required屬性爲false,例如:@Autowired(required=false),如果我們想使用名稱裝配可以結合@Qualifier註解進行使用,如下:
@Autowired()
@Qualifier("baseDao")
private BaseDao baseDao;
- @Resource,默認安裝名稱進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當註解寫在字段上時,默認取字段名進行安裝名稱查找,如果註解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。例如:
@Resource(name="baseDao")
private BaseDao baseDao;
推薦使用:@Resource註解在字段上,這樣就不用寫setter方法了,並且這個註解是屬於J2EE的,減少了與spring的耦合。這樣代碼看起就比較優雅。
24 spring對DAO的支持
Spring對數據訪問對象(DAO)的支持旨在簡化它和數據訪問技術如JDBC,Hibernateor JDO 結合使用。這使我們可以方便切換持久層。編碼時也不用擔心會捕獲每種技術特有的異常。
- 優化了的異常類型體系:細化了數據訪問異常,豐富了異常類型。(都是 Unchecked Exception,這種異常不會變動,採用同一種異常,表示同一種現象,與使用的持久化技術無關)
- 使用模板回調模式,開發者不再寫模式化代碼,簡化編程:
不變:資源的獲取,資源的釋放,異常轉化(Spring提供了模板類對此負責)。
變化:SQL,變量,結果集的提取。
25 基於JDBC的DAO(Hibernate類似)
簡化對JDBC的操作
- 模板負責:JDBC對象的獲取釋放,異常類型的轉化。
- 開發負責:提供SQL,設置SQL中的變量,提取ResultSet。
應用
- 核心方法:query() update()
- 回調接口:PreparedStatementCreator、PreparedStatementSetter、ResultSetExtractor、RowMapper
DAO中獲得JdbcTemplate的兩種方式:
- 給DAO注入JdbcTempate:Bean配置:DataSource->JdbcTemplate(需要bean工廠控制)->DAO
- 使DAO類繼承 JdbcDaoSupport:繼承的方法getJdbcTemplate()、Bean配置:DataSource->DAO。
26 Spring+Hibernate訪問數據庫的方式
在Spring中有兩種方式訪問hibernate:
- 使用HibernateTemplate和Callback。(推薦)
- 繼承HibernateDAOSupport。(不推薦)
- 直接使用SessionFactory(不推薦)
27 通過HibernateDaoSupport將Spring和Hibernate集成
用Spring的SessionFactory調用LocalSessionFactory。集成過程分三步:
- 配置HibernateSessionFactory。
- 繼承HibernateDaoSupport實現一個DAO。
- 在AOP支持的事務中裝配。
28 Spring支持的事務管理類型
Spring支持兩種類型的事務管理:
- 編程式事務管理:這意味你通過編程的方式管理事務,給你帶來極大的靈活性,但是難維護。
- 聲明式事務管理:這意味着你可以將業務代碼和事務管理分離,你只需用註解和XML配置來管理事務。
29 Spring事務管理的優點
- 它爲不同的事務API 如JTA,JDBC,Hibernate,JPA和JDO,提供一個不變的編程模式。
- 它爲編程式事務管理提供了一套簡單的API而不是一些複雜的事務API。
- 它支持聲明式事務管理。
- 它和Spring各種數據訪問抽象層很好得集成。
30 常用的內置事務管理器實現
- DataSourceTransactionManager:位於org.springframework.jdbc.datasource包中,數據源事務管理器,提供對單個javax.sql.DataSource事務管理,用於SpringJDBC抽象框架、iBATIS框架的事務管理;
- HibernateTransactionManager:位於org.springframework.orm.hibernate3或者hibernate4包中,提供對單個org.hibernate.SessionFactory事務支持,用於集成Hibernate框架時的事務管理;該事務管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate3.2+版本;
- JtaTransactionManager:位於org.springframework.transaction.jta包中,提供對分佈式事務管理的支持,並將事務管理委託給JavaEE應用服務器事務管理器;
31 Spring事務的傳播行爲(propagation)7個
- required:指定當前方法必需在事務環境中運行,如果當前有事務環境就加入當前正在執行的事務環境,如果當前沒有事務,就新建一個事務。這是默認值。
- supports:指定當前方法加入當前事務環境,如果當前沒有事務,就以非事務方式執行。
- mandatory:指定當前方法必須加入當前事務環境,如果當前沒有事務,就拋出異常。
- requires_new:當前方法總是會爲自己發起一個新的事務,如果發現當前方法已運行在一個事務中,則原有事務被掛起,自己創建一個屬於自己的事務,直到自己這個方法commit結束,原先的事務纔會恢復執行。
- not_supported:當前方法以非事務方式執行操作,如果當前存在事務,就把當前事務掛起,等以非事務的狀態運行完,再繼續原來的事務。
- never:當前方法絕對不能在事務範圍內執行,如果方法在某個事務範圍內執行,容器就拋異常,只有沒關聯到事務,才正常執行。
- nested:指定當前方法執行時,如果已經有一個事務存在,則運行在這個嵌套的事務中。如果當前環境沒有運行的事務,就新建一個事務,並與父事務相互獨立,這個事務擁有多個可以回滾的保證點。就是指我自己內部事務回滾不會對外部事務造成影響,只對DataSourceTransactionManager事務管理器起效。
32 Spring事務配置屬性詳解(<tx:method >或@Transactional)
表格3 Spring事務配置選項
屬性 |
類型 |
默認值 |
說明 |
propagation |
Propagation枚舉 |
REQUIRED |
事務傳播屬性 |
isolation |
isolation枚舉 |
DEFAULT(所用數據庫默認級別) |
事務隔離級別 |
readOnly |
boolean |
false |
是否用優化的只讀事務 |
timeout |
int |
-1 |
超時(秒) |
rollbackFor |
Class[] |
{} |
需要回滾的異常類 |
rollbackForClassName |
String[] |
{} |
需要回滾的異常類名 |
noRollbackFor |
Class[] |
{} |
不需要回滾的異常類 |
noRollbackForClassName |
String[] |
{} |
不需要回滾的異常類名 |
33 spring AOP的概念
面向切面的編程,是一種編程技術,是OOP(面向對象編程)的補充和完善。OOP的執行是一種從上往下的流程,並沒有從左到右的關係。因此在OOP編程中,會有大量的重複代碼。而AOP則是將這些與業務無關的重複代碼抽取出來,然後再嵌入到業務代碼當中。常見的應用有:權限管理、日誌、事務管理等。
實現AOP的技術,主要分爲兩大類:一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行爲的執行;二是採用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的代碼。Spring AOP實現用的是動態代理的方式。
34 AOP的相關概念
- 切面/方面(Aspect):AOP核心就是切面,它將多個類的通用行爲封裝成可重用的模塊,該模塊含有一組API提供橫切功能。如,一個日誌模塊可以被稱作日誌的AOP切面。根據需求的不同,一個應用程序可以有若干切面。在SpringAOP中,切面通過帶有@Aspect註解的類實現。
- 連接點(Joinpoint):程序執行過程中明確的點,如方法的調用或特定的異常被拋出。
- 通知/增強(Advice):在切入點上,可以應用的增強包括:around、before和throws。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連接點的攔截器鏈。Spring中定義了四個advice:BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice。
- 切入點(Pointcut):將被增強(Advice)應用的連接點的集合(通常是Method集合)。Spring定義了Pointcut接口,用來組合MethodMatcher和ClassFilter,可以通過名字很清楚的理解,MethodMatcher是用來檢查目標類的方法是否可以被應用此通知,而ClassFilter是用來檢查Pointcut是否應該應用到目標類上。
- 目標對象(TargetObject):被通知(Advice)或被代理對象。
- AOP代理(AOP Proxy):AOP框架創建的對象,包含通知(Advice)。在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。
35 Spring AOP的增強/通知(Advice)類型
- Before Advice:在方法執行前執行。
- AfterAdvice:在方法執行之後調用的通知,無論方法執行是否成功。
- After ReturningAdvice:在方法執行後返回一個結果後執行。
- After ThrowingAdvice:在方法執行過程中拋出異常的時候執行。
- Around Advice:在方法執行前後和拋出異常時執行,相當於綜合了以上三種通知。(相關接口MethodIntercept)
- IntroductionAdvice(引入增強):引入通知是一種特殊的通知,它能將新的成員變量、成員方法引入到目標類中。它不能作用於任何切入點,因爲它只作用於類層次,而不是方法層次。實現引入通知需要實現IntroductionAdvisor和IntroductionInterceptor接口。
36 Spring AOP 的關注點和橫切關注的區別
- 關注點是應用中一個模塊的行爲,一個關注點可能會被定義成一個我們想實現的一個功能。
- 橫切關注點是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,比如日誌,安全和數據傳輸,幾乎應用的每個模塊都需要的功能。因此這些都屬於橫切關注點。
37 引入(Introduction)的概念
引入(Introduction):添加方法或字段到被通知的類。Spring允許引入新的接口到任何被通知的對象。例如,你可以使用一個引入使任何對象實現IsModified接口,來簡化緩存。Spring中要使用Introduction,可有通過DelegatingIntroductionInterceptor來實現通知,通過DefaultIntroductionAdvisor來配置Advice和代理類要實現的接口。
38 Spring有幾種自動代理器
代理器有三類:
- 基於Bean的名字的自動代理創建器,例如BeanNameAutoProxyCreator
- 基於Advisor(切面)匹配機制的自動代理創建器。對spring容器中的所有的Advisor掃描,並將其應用到匹配的Bean中。例如DefaultAdvisorAutoProxyCreator
- 基於Bean中的AspjectJ註解標籤的自動代理創建器,例如AnnotationAwareAspectJAutoProxyCreator
所有的自動代理創建器,都是實現了BeanPostProcessor。spring容器在實例化Bean時,BeanPostProcessor會對其加工,對滿足匹配規則的Bean自動創建代理對象。
39 Spring織入概念
織入(Weaving):把切面(Aspect)應用到目標對象來創建新的代理對象的過程,織入一般發生在如下幾個時機:
- 編譯時:當一個類文件被編譯時進行織入,這需要特殊的編譯器纔可以做的到,例如AspectJ的織入編譯器。
- 類加載時:使用特殊的ClassLoader在目標類被加載到程序之前增強類的字節代碼。
- 運行時:切面在運行的某個時刻被織入,SpringAOP就是以這種方式織入切面的,原理應該是使用了動態代理技術。
40 Spring AOP的實現方式
1、經典的基於代理的AOP:使用Java代碼實現,編寫Advice、PointCut,然後提供給Advisor使用。開啓自動代理後,即可在applicationContext中獲得增強後的bean。
2、@AspectJ註解驅動的切面:基於註解的開發(推薦使用),在項目中需要開啓AOP自動代理<aop:aspectj-autoproxy/>。
3、XML Schema方式:需要實現相應的增強接口,如BeforeAdvice、AfterAdvice等。然後利用一下配置如:
- <aop:config>
- <aop:aspect id="aspect" ref="xmlHandler">
- <aop:pointcut id="pointUserMgr" expression="execution(* com.tgb.aop.*.find*(..))"/>
- <aop:before method="doBefore" pointcut-ref="pointUserMgr"/>
- <aop:after method="doAfter" pointcut-ref="pointUserMgr"/>
- <aop:around method="doAround" pointcut-ref="pointUserMgr"/>
- <aop:after-returning method="doReturn" pointcut-ref="pointUserMgr"/>
- <aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointUserMgr"/>
- </aop:aspect>
- </aop:config>
41 spring MVC原理
Spring工作流程描述
1、用戶向服務器發送請求,請求被Spring前端控制DispatcherServlet捕獲;
2、DispatcherServlet對請求URL進行解析,得到請求資源標識符(URI)。然後根據該URI,調用HandlerMapping獲得該Handler配置的所有相關的對象(包括Handler對象以及Handler對象對應的攔截器),最後以HandlerExecutionChain對象的形式返回;
3、DispatcherServlet根據獲得的Handler,選擇一個合適的HandlerAdapter。(附註:如果成功獲得HandlerAdapter後,此時將開始執行攔截器的preHandler(...)方法)
4、提取Request中的模型數據,填充Handler入參,開始執行Handler(Controller)。在填充Handler的入參過程中,根據你的配置,Spring將幫你做一些額外的工作:
HttpMessageConveter:將請求消息(如Json、xml等數據)轉換成一個對象,將對象轉換爲指定的響應信息。
數據轉換:對請求消息進行數據轉換。如String轉換成Integer、Double等。
數據根式化:對請求消息進行數據格式化。如將字符串轉換成格式化數字或格式化日期等。
數據驗證:驗證數據的有效性(長度、格式等),驗證結果存儲到BindingResult或Error中。
5、Handler執行完成後,向DispatcherServlet返回一個ModelAndView對象;
6、根據返回的ModelAndView,選擇一個適合的ViewResolver(必須是已經註冊到Spring容器中的ViewResolver)返回給DispatcherServlet;
7、ViewResolver結合Model和View,來渲染視圖。
8、將渲染結果返回給客戶端。
42 Spring MVC的DispatcherServlet
Spring的MVC框架是圍繞DispatcherServlet來設計的,它用來處理所有的HTTP請求和響應。DispatcherServlet主要用作職責調度工作,本身主要用於控制流程,主要職責如下:
1、文件上傳解析,如果請求類型是multipart將通過MultipartResolver進行文件上傳解析;
2、通過HandlerMapping,將請求映射到處理器(返回一個HandlerExecutionChain,它包括一個處理器、多個HandlerInterceptor攔截器);
3、通過HandlerAdapter支持多種類型的處理器(HandlerExecutionChain中的處理器);
4、通過ViewResolver解析邏輯視圖名到具體視圖實現;
5、本地化解析;
6、渲染具體的視圖等;
7、如果執行過程中遇到異常將交給HandlerExceptionResolver來解析。
43 Spring MVC WebApplicationContext
WebApplicationContext繼承了ApplicationContext並增加了一些WEB應用必備的特有功能,它不同於一般的ApplicationContext,因爲它能處理主題,並找到被關聯的servlet。
44 Spring中DispatcherServlet、WebApplicationContext、ServletContext之間的關係
1、首先,對於一個Web應用來說,Web容器提供一個全局的上下文環境(servletContext),爲後面的SpringIOC容器作爲宿主環境。
2、然後,在web.xml中會有提供ContextLoaderListener。在web容器啓動的過程當中,會監聽到servletContext的變化,其contextInitialized方法會被調用。在這個方法中,Spring會啓動一個跟上下文(WebApplicationContext/XmlWebApplicationContext)。這個就是SpringIOC容器,對應的Bean定義的配置由web.xml中的context-param標籤指定。在這個IoC容器初始化完畢後,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE爲屬性Key,將其存儲到ServletContext中,便於獲取;
3、最後,contextLoaderListener監聽器初始化完畢後,開始初始化web.xml中配置的Servlet,這個servlet可以配置多個,以最常見的DispatcherServlet爲例,這個servlet實際上是一個標準的前端控制器,用以轉發、匹配、處理每個servlet請求。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文,用以持有springmvc相關的bean。在建立DispatcherServlet自己的IoC上下文時,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作爲自己上下文的parent上下文。有了這個parent上下文之後,再初始化自己持有的上下文。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化處理器映射、視圖解析等。這個servlet自己持有的上下文默認實現類也是XmlWebApplicationContext。初始化完畢後,spring以與servlet的名字相關(此處不是簡單的以servlet名爲Key,而是通過一些轉換,具體可自行查看源碼)的屬性爲屬性Key,也將其存到ServletContext中,以便後續使用。這樣每個servlet就持有自己的上下文,即擁有自己獨立的bean空間,同時各個servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定義的那些bean。
45 Spring MVC的註解
@Controller:該註解表明該類扮演控制器的角色,Spring不需要你繼承任何其他控制器基類或引用ServletAPI。
@RequestMapping:該註解是用來映射一個URL到一個類或一個特定的方處理法上。
@RequestParam:綁定HttpServletRequest請求參數到控制器方法參數。(默認在方法入參中按參數名綁定)
@RequestHeader:註解綁定HttpServletRequest頭信息到Controller方法參數。
@CookieValue:綁定cookie的值到Controller方法參數。
46 @RequestMapping註解支持的方法參數和返回類型
支持的方法參數類型
(1)HttpServlet對象,主要包括HttpServletRequest、HttpServletResponse和HttpSession對象。這些參數Spring在調用處理器方法的時候會自動給它們賦值,所以當在處理器方法中需要使用到這些對象的時候,可以直接在方法上給定一個方法參數的申明,然後在方法體裏面直接用就可以了。但是有一點需要注意的是在使用HttpSession對象的時候,如果此時HttpSession對象還沒有建立起來的話就會有問題。
(2)Spring自己的WebRequest對象。使用該對象可以訪問到存放在HttpServletRequest和HttpSession中的屬性值。
(3)InputStream、OutputStream、Reader和Writer。InputStream和Reader是針對HttpServletRequest 而言的,可以從裏面取數據;OutputStream和Writer 是針對HttpServletResponse而言的,可以往裏面寫數據。
(4)使用@PathVariable、@RequestParam、@CookieValue和@RequestHeader標記的參數。
(5)使用@ModelAttribute標記的參數。
(6)Java.util.Map、Spring封裝的Model和ModelMap。這些都可以用來封裝模型數據,用來給視圖做展示。
(7)實體類。可以用來接收上傳的參數。
(8)Spring封裝的MultipartFile。用來接收上傳文件的。
(9)Spring封裝的Errors和BindingResult對象。這兩個對象參數必須緊接在需要驗證的實體對象參數之後,它裏面包含了實體對象的驗證結果。
支持的返回類型
(1)一個包含模型和視圖的ModelAndView對象。
(2)一個模型對象,這主要包括Spring封裝好的Model和ModelMap ,以及java.util.Map,當沒有視圖返回的時候視圖名稱將由RequestToViewNameTranslator來決定。
(3)一個View對象。這個時候如果在渲染視圖的過程中模型的話就可以給處理器方法定義一個模型參數,然後在方法體裏面往模型中添加值。
(4)一個String字符串。這往往代表的是一個視圖名稱。這個時候如果需要在渲染視圖的過程中需要模型的話就可以給處理器方法一個模型參數,然後在方法體裏面往模型中添加值就可以了。
(5)返回值是void。這種情況一般是我們直接把返回結果寫到HttpServletResponse中了,如果沒有寫的話,那麼Spring將會利用RequestToViewNameTranslator來返回一個對應的視圖名稱。如果視圖中需要模型的話,處理方法與返回字符串的情況相同。
(6)如果處理器方法被註解@ResponseBody標記的話,那麼處理器方法的任何返回類型都會通過HttpMessageConverters轉換之後寫到HttpServletResponse中,而不會像上面的那些情況一樣當做視圖或者模型來處理。
(7)除以上幾種情況之外的其他任何返回類型都會被當做模型中的一個屬性來處理,而返回的視圖還是由RequestToViewNameTranslator來決定,添加到模型中的屬性名稱可以在該方法上用@ModelAttribute(“attributeName”)來定義,否則將使用返回類型的類名稱的首字母小寫形式來表示。使用@ModelAttribute標記的方法會在@RequestMapping 標記的方法執行之前執行。
47 @ModelAttribute和@SessionAttributes傳遞和保存數據
SpringMVC支持使用@ModelAttribute和@SessionAttributes在不同的模型和控制器之間共享數據。
@ModelAttribute:一種是標註在方法上,另一種是標註在Controller方法參數上。
當@ModelAttribute標記單獨使用時,被標註的方法將在處理器方法執行之前執行,然後把返回的對象存放在模型屬性中,傳給標註在方法入參上的變量。
@SessionAttributes:用於標記需要在Session中使用到的數據,包括從Session中取數據和存數據。@SessionAttributes一般是標記在Controller類上的,可以通過名稱、類型或者名稱加類型的形式來指定哪些屬性是需要存放在session中的。
當使用@SessionAttributes時,如沒有@ModelAttribute標註的方法,則去session中尋找。當controller類中的方法的變量,能匹配到@SessionAttributes中的名稱或類型時,在方法返回後會將變量存放在Session中。
48 Spring MVC 自定義數據類型轉換
Spring 3.0以後,可以繼承org.springframework.core.convert.converter接口,實現對應的轉換器,然後,
1、通過XMLSchema註冊到ConversionService。
2、通過ConfigurableWebBindingInitializer註冊ConversionService。
3、註冊ConfigurableWebBindingInitializer到RequestMappingHandlerAdapter。