文章很長,建議收藏起來,慢慢讀! 瘋狂創客圈爲小夥伴奉上如下珍貴的學習資源:html
高併發 必讀 的精彩博文 | |
---|---|
nacos 實戰(史上最全) | sentinel (史上最全+入門教程) |
Zookeeper 分佈式鎖 (圖解+秒懂+史上最全) | Webflux(史上最全) |
SpringCloud gateway (史上最全) | TCP/IP(圖解+秒懂+史上最全) |
10分鐘看懂, Java NIO 底層原理 | Feign原理 (圖解) |
更多精彩博文 ..... | 請參見【 瘋狂創客圈 高併發 總目錄 】 |
Spring是一個輕量級Java開發框架,最先有Rod Johnson建立,目的是爲了解決企業級應用開發的業務邏輯層和其餘各層的耦合問題。它是一個分層的JavaSE/JavaEE full-stack(一站式)輕量級開源框架,爲開發Java應用程序提供全面的基礎架構支持。Spring負責基礎架構,所以Java開發者能夠專一於應用程序的開發。前端
Spring最根本的使命是解決企業級應用開發的複雜性,即簡化Java開發。java
Spring能夠作不少事情,它爲企業級開發提供給了豐富的功能,可是這些功能的底層都依賴於它的兩個核心特性,也就是依賴注入(dependency injection,DI)和麪向切面編程(aspect-oriented programming,AOP)。git
爲了下降Java開發的複雜性,Spring採起了如下4種關鍵策略程序員
Spring設計目標:Spring爲開發者提供一個一站式輕量級應用開發平臺;github
Spring設計理念:在JavaEE開發中,支持POJO和JavaBean開發方式,使應用面向接口開發,充分支持OO(面向對象)設計方法;Spring經過IoC容器實現對象耦合關係的管理,並實現依賴反轉,將對象之間的依賴關係交給IoC容器,實現解耦;web
Spring框架的核心:IoC容器和AOP模塊。經過IoC容器管理POJO對象以及他們之間的耦合關係;經過AOP以動態非侵入的方式加強服務。面試
IoC讓相互協做的組件保持鬆散的耦合,而AOP編程容許你把遍及於應用各層的功能分離出來造成可重用的功能組件。ajax
優勢正則表達式
方便解耦,簡化開發
Spring就是一個大工廠,能夠將全部對象的建立和依賴關係的維護,交給Spring管理。
AOP編程的支持
Spring提供面向切面編程,能夠方便的實現對程序進行權限攔截、運行監控等功能。
聲明式事務的支持
只須要經過配置就能夠完成對事務的管理,而無需手動編程。
方便程序的測試
Spring對Junit4支持,能夠經過註解方便的測試Spring程序。
方便集成各類優秀框架
Spring不排斥各類優秀的開源框架,其內部提供了對各類優秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
下降JavaEE API的使用難度
Spring對JavaEE開發中很是難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大下降。
缺點
應用場景:JavaEE企業應用開發,包括SSH、SSM等
Spring價值:
Spring 總共大約有 20 個模塊, 由 1300 多個不一樣的文件構成。 而這些組件被分別整合在核心容器(Core Container)
、 AOP(Aspect Oriented Programming)和設備支持(Instrmentation)
、數據訪問與集成(Data Access/Integeration)
、 Web
、 消息(Messaging)
、 Test
等 6 個模塊中。 如下是 Spring 5 的模塊結構圖:
這是基本的Spring模塊,提供spring 框架的基礎功能,BeanFactory 是 任何以spring爲基礎的應用的核心。Spring 框架創建在此模塊之上,它使Spring成爲一個容器。
Bean 工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和依賴從真正的應用代碼中分離。最經常使用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根據XML文件中的定義加載beans。該容器從XML 文件讀取配置元數據並用它去建立一個徹底配置的系統或應用。
Spring 提供瞭如下5種標準的事件:
Spring 應用通常有如下組件:
使用 Spring 有如下方式:
控制反轉即IoC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器,經過容器來實現對象組件的裝配和管理。所謂的「控制反轉」概念就是對組件對象控制權的轉移,從程序代碼自己轉移到了外部容器。
Spring IOC 負責建立對象,管理對象(經過依賴注入(DI),裝配對象,配置對象,而且管理這些對象的整個生命週期。
Spring 中的 IoC 的實現原理就是工廠模式加反射機制。
示例:
interface Fruit { public abstract void eat(); } class Apple implements Fruit { public void eat(){ System.out.println("Apple"); } } class Orange implements Fruit { public void eat(){ System.out.println("Orange"); } } class Factory { public static Fruit getInstance(String ClassName) { Fruit f=null; try { f=(Fruit)Class.forName(ClassName).newInstance(); } catch (Exception e) { e.printStackTrace(); } return f; } } class Client { public static void main(String[] a) { Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple"); if(f!=null){ f.eat(); } } }
Spring 的 IoC 設計支持如下功能:
其中,最重要的就是依賴注入,從 XML 的配置上說,即 ref 標籤。對應 Spring RuntimeBeanReference 對象。
對於 IoC 來講,最重要的就是容器。容器管理着 Bean 的生命週期,控制着 Bean 的依賴注入。
BeanFactory和ApplicationContext是Spring的兩大核心接口,均可以當作Spring的容器。其中ApplicationContext是BeanFactory的子接口。
依賴關係
BeanFactory:是Spring裏面最底層的接口,包含了各類Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命週期,維護bean之間的依賴關係。
ApplicationContext接口做爲BeanFactory的派生,除了提供BeanFactory所具備的功能外,還提供了更完整的框架功能:
加載方式
BeanFactroy採用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),纔對該Bean進行加載實例化。這樣,咱們就不能發現一些存在的Spring的配置問題。若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法纔會拋出異常。
ApplicationContext,它是在容器啓動時,一次性建立了全部的Bean。這樣,在容器啓動時,咱們就能夠發現Spring中存在的配置錯誤,這樣有利於檢查所依賴屬性是否注入。 ApplicationContext啓動後預載入全部的單實例Bean,經過預載入單實例bean ,確保當你須要的時候,你就不用等待,由於它們已經建立好了。
相對於基本的BeanFactory,ApplicationContext 惟一的不足是佔用內存空間。當應用程序配置Bean較多時,程序啓動較慢。
建立方式
BeanFactory一般以編程的方式被建立,ApplicationContext還能以聲明的方式建立,如使用ContextLoader。
註冊方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但二者之間的區別是:BeanFactory須要手動註冊,而ApplicationContext則是自動註冊。
Spring 做者 Rod Johnson 設計了兩個接口用以表示容器。
BeanFactory 簡單粗暴,能夠理解爲就是個 HashMap,Key 是 BeanName,Value 是 Bean 實例。一般只提供註冊(put),獲取(get)這兩個功能。咱們能夠稱之爲 「低級容器」。
ApplicationContext 能夠稱之爲 「高級容器」。由於他比 BeanFactory 多了更多的功能。他繼承了多個接口。所以具有了更多的功能。例如資源的獲取,支持多種消息(例如 JSP tag 的支持),對 BeanFactory 多了工具級別的支持等待。因此你看他的名字,已經不是 BeanFactory 之類的工廠了,而是 「應用上下文」, 表明着整個大容器的全部功能。該接口定義了一個 refresh 方法,此方法是全部閱讀 Spring 源碼的人的最熟悉的方法,用於刷新整個容器,即從新加載/刷新全部的 bean。
固然,除了這兩個大接口,還有其餘的輔助接口,這裏就不介紹他們了。
BeanFactory和ApplicationContext的關係
爲了更直觀的展現 「低級容器」 和 「高級容器」 的關係,這裏經過經常使用的 ClassPathXmlApplicationContext 類來展現整個容器的層級 UML 關係。
有點複雜? 先不要慌,我來解釋一下。
最上面的是 BeanFactory,下面的 3 個綠色的,都是功能擴展接口,這裏就不展開講。
看下面的隸屬 ApplicationContext 粉紅色的 「高級容器」,依賴着 「低級容器」,這裏說的是依賴,不是繼承哦。他依賴着 「低級容器」 的 getBean 功能。而高級容器有更多的功能:支持不一樣的信息源頭,能夠訪問文件資源,支持應用事件(Observer 模式)。
一般用戶看到的就是 「高級容器」。 但 BeanFactory 也很是夠用啦!
左邊灰色區域的是 「低級容器」, 只負載加載 Bean,獲取 Bean。容器其餘的高級功能是沒有的。例如上圖畫的 refresh 刷新 Bean 工廠全部配置,生命週期事件回調等。
小結
說了這麼多,不知道你有沒有理解Spring IoC? 這裏小結一下:IoC 在 Spring 裏,只須要低級容器就能夠實現,2 個步驟:
上面就是 Spring 低級容器(BeanFactory)的 IoC。
至於高級容器 ApplicationContext,他包含了低級容器的功能,當他執行 refresh 模板方法的時候,將刷新整個容器的 Bean。同時其做爲高級容器,包含了太多的功能。一句話,他不只僅是 IoC。他支持不一樣信息源頭,支持 BeanFactory 工具類,支持層級容器,支持訪問文件資源,支持事件發佈通知,支持接口回調等等。
FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這裏,你須要正確設置classpath由於這個容器將在classpath裏找bean配置。
WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的全部bean。
控制反轉IoC是一個很大的概念,能夠用不一樣的方式來實現。其主要實現方式有兩種:依賴注入和依賴查找
依賴注入:相對於IoC而言,依賴注入(DI)更加準確地描述了IoC的設計理念。所謂依賴注入(Dependency Injection),即組件之間的依賴關係由容器在應用系統運行期來決定,也就是由容器動態地將某種依賴關係的目標對象實例注入到應用系統中的各個關聯的組件之中。組件不作定位查詢,只提供普通的Java方法讓容器去決定依賴關係。
依賴注入的基本原則是:應用組件不該該負責查找資源或者其餘依賴的協做對象。配置對象的工做應該由IoC容器負責,「查找資源」的邏輯應該從應用組件的代碼中抽取出來,交給IoC容器負責。容器全權負責組件的裝配,它會把符合依賴關係的對象經過屬性(JavaBean中的setter)或者是構造器傳遞給須要的對象。
依賴注入之因此更流行是由於它是一種更可取的方式:讓容器全權負責依賴查詢,受管組件只須要暴露JavaBean的setter方法或者帶參數的構造器或者接口,使容器能夠在初始化時組裝對象的依賴關係。其與依賴查找方式相比,主要優點爲:
依賴注入是時下最流行的IoC實現方式,依賴注入分爲接口注入(Interface Injection),Setter方法注入(Setter Injection)和構造器注入(Constructor Injection)三種方式。其中接口注入因爲在靈活性和易用性比較差,如今從Spring4開始已被廢棄。
構造器依賴注入:構造器依賴注入經過容器觸發一個類的構造器來實現的,該類有一系列參數,每一個參數表明一個對其餘類的依賴。
Setter方法注入:Setter方法注入是容器經過調用無參構造器或無參static工廠 方法實例化bean以後,調用該bean的setter方法,即實現了基於setter的依賴注入。
構造函數注入 | setter 注入 |
---|---|
沒有部分注入 | 有部分注入 |
不會覆蓋 setter 屬性 | 會覆蓋 setter 屬性 |
任意修改都會建立一個新實例 | 任意修改不會建立一個新實例 |
適用於設置不少屬性 | 適用於設置少許屬性 |
兩種依賴方式均可以使用,構造器注入和Setter方法注入。最好的解決方案是用構造器參數實現強制依賴,setter方法實現可選依賴。
Spring beans 是那些造成Spring應用的主幹的java對象。它們被Spring IOC容器初始化,裝配,和管理。這些beans經過容器中配置的元數據建立。好比,以XML文件中 的形式定義。
一個Spring Bean 的定義包含容器必知的全部配置元數據,包括如何建立一個bean,它的生命週期詳情及它的依賴。
這裏有三種重要的方法給Spring 容器提供配置元數據。
Spring配置文件是個XML 文件,這個文件包含了類信息,描述瞭如何配置它們,以及如何相互調用。
當定義一個 在Spring裏,咱們還能給這個bean聲明一個做用域。它能夠經過bean 定義中的scope屬性來定義。如,當Spring要在須要的時候每次生產一個新的bean實例,bean的scope屬性被指定爲prototype。另外一方面,一個bean每次使用的時候必須返回同一個實例,這個bean的scope 屬性 必須設爲 singleton。
Spring框架支持如下五種bean的做用域:
注意: 缺省的Spring bean 的做用域是Singleton。使用 prototype 做用域須要慎重的思考,由於頻繁建立和銷燬 bean 會帶來很大的性能開銷。
不是,Spring框架中的單例bean不是線程安全的。
spring 中的 bean 默認是單例模式,spring 框架並無對單例 bean 進行多線程的封裝處理。
實際上大部分時候 spring bean 無狀態的(好比 dao 類),全部某種程度上來講 bean 也是安全的,但若是 bean 有狀態的話(好比 view model 對象),那就要開發者本身去保證線程安全了,最簡單的就是改變 bean 的做用域,把「singleton」變動爲「prototype」,這樣請求 bean 至關於 new Bean()了,因此就能夠保證線程安全了。
在通常狀況下,只有無狀態的Bean才能夠在多線程環境下共享,在Spring中,絕大部分Bean均可以聲明爲singleton做用域,由於Spring對一些Bean中非線程安全狀態採用ThreadLocal進行處理,解決線程安全問題。
ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。同步機制採用了「時間換空間」的方式,僅提供一份變量,不一樣的線程在訪問前須要獲取鎖,沒得到鎖的線程則須要排隊。而ThreadLocal採用了「空間換時間」的方式。
ThreadLocal會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進ThreadLocal。
在傳統的Java應用中,bean的生命週期很簡單。使用Java關鍵字new進行bean實例化,而後該bean就可使用了。一旦該bean再也不被使用,則由Java自動進行垃圾回收。相比之下,Spring容器中的bean的生命週期就顯得相對複雜多了。正確理解Spring bean的生命週期很是重要,由於你或許要利用Spring提供的擴展點來自定義bean的建立過程。下圖展現了bean裝載到Spring應用上下文中的一個典型的生命週期過程。
bean在Spring容器中從建立到銷燬經歷了若干階段,每一階段均可以針對Spring如何管理bean進行個性化定製。
正如你所見,在bean準備就緒以前,bean工廠執行了若干啓動步驟。
咱們對上圖進行詳細描述:
Spring對bean進行實例化;
Spring將值和bean的引用注入到bean對應的屬性中;
若是bean實現了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;
若是bean實現了BeanFactoryAware接口,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入;
若是bean實現了ApplicationContextAware接口,Spring將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來;
若是bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessBeforeInitialization()方法;
若是bean實現了InitializingBean接口,Spring將調用它們的after-PropertiesSet()方法。相似地,若是bean使用initmethod聲明瞭初始化方法,該方法也會被調用;
若是bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessAfterInitialization()方法;
此時,bean已經準備就緒,能夠被應用程序使用了,它們將一直駐留在應用上下文中,直到該應用上下文被銷燬;
若是bean實現了DisposableBean接口,Spring將調用它的destroy()接口方法。一樣,若是bean使用destroy-method聲明瞭銷燬方法,該方法也會被調用。
如今你已經瞭解瞭如何建立和加載一個Spring容器。可是一個空的容器並無太大的價值,在你把東西放進去以前,它裏面什麼都沒有。爲了從Spring的DI(依賴注入)中受益,咱們必須將應用對象裝配進Spring容器中。
有兩個重要的bean 生命週期方法,第一個是setup , 它是在容器加載bean的時候被調用。第二個方法是 teardown 它是在容器卸載類的時候被調用。
bean 標籤有兩個重要的屬性(init-method和destroy-method)。用它們你能夠本身定製初始化和註銷方法。它們也有相應的註解(@PostConstruct和@PreDestroy)。
在Spring框架中,當一個bean僅被用做另外一個bean的屬性時,它能被聲明爲一個內部bean。內部bean能夠用setter注入「屬性」和構造方法注入「構造參數」的方式來實現,內部bean一般是匿名的,它們的Scope通常是prototype。
Spring提供如下幾種集合的配置元素:
類型用於注入一列值,容許有相同的值。
類型用於注入一組值,不容許有相同的值。
類型用於注入一組鍵值對,鍵和值均可覺得任意類型。
類型用於注入一組鍵值對,鍵和值都只能爲String類型。
裝配,或bean 裝配是指在Spring 容器中把bean組裝到一塊兒,前提是容器須要知道bean的依賴關係,如何經過依賴注入來把它們裝配到一塊兒。
在Spring框架中,在配置文件中設定bean的依賴關係是一個很好的機制,Spring 容器可以自動裝配相互合做的bean,這意味着容器不須要和配置,能經過Bean工廠自動處理bean之間的協做。這意味着 Spring能夠經過向Bean Factory中注入的方式自動搞定bean之間的依賴關係。自動裝配能夠設置在每一個bean上,也能夠設定在特定的bean上。
在spring中,對象無需本身查找或建立與其關聯的其餘對象,由容器負責把須要相互協做的對象引用賦予各個對象,使用autowire來配置自動裝載模式。
在Spring框架xml配置中共有5種自動裝配:
使用@Autowired註解來自動裝配指定的bean。在使用@Autowired註解以前須要在Spring配置文件進行配置,<context:annotation-config />。
在啓動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor後置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找須要的bean,並裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:
自動裝配的侷限性是:
重寫:你仍需用 和 配置來定義依賴,意味着總要重寫自動裝配。
基本數據類型:你不能自動裝配簡單的屬性,如基本數據類型,String字符串,和類。
模糊特性:自動裝配不如顯式裝配精確,若是有可能,建議使用顯式裝配。
能夠。
基於Java的配置,容許你在少許的Java註解的幫助下,進行你的大部分Spring配置而非經過XML文件。
以@Configuration 註解爲例,它用來標記類能夠當作一個bean的定義,被Spring IOC容器使用。
另外一個例子是@Bean註解,它表示此方法將要返回一個對象,做爲一個bean註冊進Spring應用上下文。
@Configuration public class StudentConfig { @Bean public StudentBean myStudent() { return new StudentBean(); } }
註解裝配在默認狀況下是不開啓的,爲了使用註解裝配,咱們必須在Spring配置文件中配置 <context:annotation-config/>
元素。
@Component:這將 java 類標記爲 bean。它是任何 Spring 管理組件的通用構造型。spring 的組件掃描機制如今能夠將其拾取並將其拉入應用程序環境中。
@Controller:這將一個類標記爲 Spring Web MVC 控制器。標有它的 Bean 會自動導入到 IoC 容器中。
@Service:此註解是組件註解的特化。它不會對 @Component 註解提供任何其餘行爲。您能夠在服務層類中使用 @Service 而不是 @Component,由於它以更好的方式指定了意圖。
@Repository:這個註解是具備相似用途和功能的 @Component 註解的特化。它爲 DAO 提供了額外的好處。它將 DAO 導入 IoC 容器,並使未經檢查的異常有資格轉換爲 Spring DataAccessException。
這個註解代表bean的屬性必須在配置的時候設置,經過一個bean定義的顯式的屬性值或經過自動裝配,若@Required註解的bean屬性未被設置,容器將拋出BeanInitializationException。示例:
public class Employee { private String name; @Required public void setName(String name){ this.name=name; } public string getName(){ return name; } }
@Autowired默認是按照類型裝配注入的,默認狀況下它要求依賴對象必須存在(能夠設置它required屬性爲false)。@Autowired 註解提供了更細粒度的控制,包括在何處以及如何完成自動裝配。它的用法和@Required同樣,修飾setter方法、構造器、屬性或者具備任意名稱和/或多個參數的PN方法。
public class Employee { private String name; @Autowired public void setName(String name) { this.name=name; } public string getName(){ return name; } }
@Autowired可用於:構造函數、成員變量、Setter方法
@Autowired和@Resource之間的區別
當您建立多個相同類型的 bean 並但願僅使用屬性裝配其中一個 bean 時,您可使用@Qualifier 註解和 @Autowired 經過指定應該裝配哪一個確切的 bean 來消除歧義。
@RequestMapping 註解用於將特定 HTTP 請求方法映射到將處理相應請求的控制器中的特定類/方法。此註釋可應用於兩個級別:
Spring 經過提供ORM模塊,支持咱們在直接JDBC之上使用一個對象/關係映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS,JPA,TopLink,JDO,OJB 。Spring的事務管理一樣支持以上全部ORM框架及JDBC。
使用Spring JDBC 框架,資源管理和錯誤處理的代價都會被減輕。因此開發者只需寫statements 和 queries從數據存取數據,JDBC也能夠在Spring框架提供的模板類的幫助下更有效地被使用,這個模板叫JdbcTemplate
經過使用JDBC抽象和DAO模塊,保證數據庫代碼的簡潔,並能避免數據庫資源錯誤關閉致使的問題,它在各類不一樣的數據庫的錯誤信息之上,提供了一個統一的異常訪問層。它還利用Spring的AOP 模塊給Spring應用中的對象提供事務管理服務。
Spring DAO(數據訪問對象) 使得 JDBC,Hibernate 或 JDO 這樣的數據訪問技術更容易以一種統一的方式工做。這使得用戶容易在持久性技術之間切換。它還容許您在編寫代碼時,無需考慮捕獲每種技術不一樣的異常。
JdbcTemplate
SimpleJdbcTemplate
NamedParameterJdbcTemplate
SimpleJdbcInsert
SimpleJdbcCall
JdbcTemplate 類提供了不少便利的方法解決諸如把數據庫數據轉變成基本數據類型或對象,執行寫好的或可調用的數據庫操做語句,提供自定義的數據錯誤處理。
在Spring中有兩種方式訪問Hibernate:
用Spring的 SessionFactory 調用 LocalSessionFactory。集成過程分三步:
Spring支持兩種類型的事務管理:
編程式事務管理:這意味你經過編程的方式管理事務,給你帶來極大的靈活性,可是難維護。
聲明式事務管理:這意味着你能夠將業務代碼和事務管理分離,你只需用註解和XML配置來管理事務。
Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是沒法提供事務功能的。真正的數據庫層的事務提交和回滾是經過binlog或者redo log實現的。
spring事務的傳播行爲說的是,當多個事務同時存在的時候,spring如何處理這些事務的行爲。
① PROPAGATION_REQUIRED:若是當前沒有事務,就建立一個新事務,若是當前存在事務,就加入該事務,該設置是最經常使用的設置。
② PROPAGATION_SUPPORTS:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就以非事務執行。
③ PROPAGATION_MANDATORY:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就拋出異常。
④ PROPAGATION_REQUIRES_NEW:建立新事務,不管當前存不存在事務,都建立新事務。
⑤ PROPAGATION_NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
⑥ PROPAGATION_NEVER:以非事務方式執行,若是當前存在事務,則拋出異常。
⑦ PROPAGATION_NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則按REQUIRED屬性執行。
spring 有五大隔離級別,默認值爲 ISOLATION_DEFAULT(使用數據庫的設置),其餘四個隔離級別和數據庫的隔離級別一致:
髒讀 :表示一個事務可以讀取另外一個事務中還未提交的數據。好比,某個事務嘗試插入記錄 A,此時該事務還未提交,而後另外一個事務嘗試讀取到了記錄 A。
不可重複讀 :是指在一個事務內,屢次讀同一數據。
幻讀 :指同一個事務內屢次查詢返回的結果集不同。好比同一個事務 A 第一次查詢時候有 n 條記錄,可是第二次同等條件下查詢卻有 n+1 條記錄,這就好像產生了幻覺。發生幻讀的緣由也是另一個事務新增或者刪除或者修改了第一個事務結果集裏面的數據,同一個記錄的數據內容被修改了,全部數據行的記錄就變多或者變少了。
大多數Spring框架的用戶選擇聲明式事務管理,由於它對應用代碼的影響最小,所以更符合一個無侵入的輕量級容器的思想。聲明式事務管理要優於編程式事務管理,雖然比編程式事務管理(這種方式容許你經過代碼控制事務)少了一點靈活性。惟一不足地方是,最細粒度只能做用到方法級別,沒法作到像編程式事務那樣能夠做用到代碼塊級別。
OOP(Object-Oriented Programming)面向對象編程,容許開發者定義縱向的關係,但並適用於定義橫向的關係,致使了大量代碼的重複,而不利於各個模塊的重用。
AOP(Aspect-Oriented Programming),通常稱爲面向切面編程,做爲面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行爲和邏輯,抽取並封裝爲一個可重用的模塊,這個模塊被命名爲「切面」(Aspect),減小系統中的重複代碼,下降了模塊間的耦合度,同時提升了系統的可維護性。可用於權限認證、日誌、事務處理等。
AOP實現的關鍵在於 代理模式,AOP代理主要分爲靜態代理和動態代理。靜態代理的表明爲AspectJ;動態代理則以Spring AOP爲表明。
(1)AspectJ是靜態代理的加強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,所以也稱爲編譯時加強,他會在編譯階段將AspectJ(切面)織入到Java字節碼中,運行的時候就是加強以後的AOP對象。
(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是每次運行時在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理:
靜態代理與動態代理區別在於生成AOP代理對象的時機不一樣,相對來講AspectJ的靜態代理方式具備更好的性能,可是AspectJ須要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最終生成的代理實例; method 是被代理目標實例的某個具體方法; args 是被代理目標實例某個方法的具體入參, 在方法反射調用時使用。
將 Advice 應用於目標對象後建立的對象稱爲代理。在客戶端對象的狀況下,目標對象和代理對象是相同的。
Advice + Target Object = Proxy
(1)切面(Aspect):切面是通知和切點的結合。通知和切點共同定義了切面的所有內容。 在Spring AOP中,切面可使用通用類(基於模式的風格) 或者在普通類中以 @AspectJ 註解來實現。
(2)鏈接點(Join point):指方法,在Spring AOP中,一個鏈接點 老是 表明一個方法的執行。 應用可能有數以千計的時機應用通知。這些時機被稱爲鏈接點。鏈接點是在應用執行過程當中可以插入切面的一個點。這個點能夠是調用方法時、拋出異常時、甚至修改一個字段時。切面代碼能夠利用這些點插入到應用的正常流程之中,並添加新的行爲。
(3)通知(Advice):在AOP術語中,切面的工做被稱爲通知。
(4)切入點(Pointcut):切點的定義會匹配通知所要織入的一個或多個鏈接點。咱們一般使用明確的類和方法名稱,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點。
(5)引入(Introduction):引入容許咱們向現有類添加新方法或屬性。
(6)目標對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。它一般是一個代理對象。也有人把它叫作 被通知(adviced) 對象。 既然Spring AOP是經過運行時代理實現的,這個對象永遠是一個 被代理(proxied) 對象。
(7)織入(Weaving):織入是把切面應用到目標對象並建立新的代理對象的過程。在目標對象的生命週期裏有多少個點能夠進行織入:
經過在代理類中包裹切面,Spring在運行期把切面織入到Spring管理的bean中。代理封裝了目標類,並攔截被通知方法的調用,再把調用轉發給真正的目標bean。當代理攔截到方法調用時,在調用目標bean方法以前,會執行切面邏輯。
直到應用須要被代理的bean時,Spring才建立代理對象。若是使用的是ApplicationContext的話,在ApplicationContext從BeanFactory中加載全部bean的時候,Spring纔會建立被代理的對象。由於Spring運行時才建立代理對象,因此咱們不須要特殊的編譯器來織入SpringAOP的切面。
由於Spring基於動態代理,因此Spring只支持方法鏈接點。Spring缺乏對字段鏈接點的支持,並且它不支持構造器鏈接點。方法以外的鏈接點攔截功能,咱們能夠利用Aspect來補充。
關注點(concern)是應用中一個模塊的行爲,一個關注點可能會被定義成一個咱們想實現的一個功能。
橫切關注點(cross-cutting concern)是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,好比日誌,安全和數據傳輸,幾乎應用的每一個模塊都須要的功能。所以這些都屬於橫切關注點。
在AOP術語中,切面的工做被稱爲通知,其實是程序執行時要經過SpringAOP框架觸發的代碼段。
Spring切面能夠應用5種類型的通知:
同一個aspect,不一樣advice的執行順序:
①沒有異常狀況下的執行順序:
around before advice
before advice
target method 執行
around after advice
after advice
afterReturning②有異常狀況下的執行順序:
around before advice
before advice
target method 執行
around after advice
after advice
afterThrowing:異常發生
java.lang.RuntimeException: 異常發生
aspect 由 pointcount 和 advice 組成,切面是通知和切點的結合。 它既包含了橫切邏輯的定義, 也包括了鏈接點的定義. Spring AOP 就是負責實施切面的框架, 它將切面所定義的橫切邏輯編織到切面所指定的鏈接點中.
AOP 的工做重心在於如何將加強編織目標對象的鏈接點上, 這裏包含兩個工做:
能夠簡單地認爲, 使用 @Aspect 註解的類就是切面.
在這種狀況下,切面由常規類以及基於XML的配置實現。
在這種狀況下(基於@AspectJ的實現),涉及到的切面聲明的風格與帶有java5標註的普通java類一致。
BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
Metadata autoproxying
Spring MVC是一個基於Java的實現了MVC設計模式的請求驅動類型的輕量級Web框架,經過把模型-視圖-控制器分離,將web層進行職責解耦,把複雜的web應用分紅邏輯清晰的幾部分,簡化開發,減小出錯,方便組內開發人員之間的配合。
(1)能夠支持各類視圖技術,而不只僅侷限於JSP;
(2)與Spring框架集成(如IoC容器、AOP等);
(3)清晰的角色分配:前端控制器(dispatcherServlet) , 請求處處理器映射(handlerMapping), 處理器適配器(HandlerAdapter), 視圖解析器(ViewResolver)。
(4) 支持各類請求資源的映射策略。
(1)前端控制器 DispatcherServlet(不須要程序員開發)
做用:接收請求、響應結果,至關於轉發器,有了DispatcherServlet 就減小了其它組件之間的耦合度。
(2)處理器映射器HandlerMapping(不須要程序員開發)
做用:根據請求的URL來查找Handler
(3)處理器適配器HandlerAdapter
注意:在編寫Handler的時候要按照HandlerAdapter要求的規則去編寫,這樣適配器HandlerAdapter才能夠正確的去執行Handler。
(4)處理器Handler(須要程序員開發)
(5)視圖解析器 ViewResolver(不須要程序員開發)
做用:進行視圖的解析,根據視圖邏輯名解析成真正的視圖(view)
(6)視圖View(須要程序員開發jsp)
View是一個接口, 它的實現類支持不一樣的視圖類型(jsp,freemarker,pdf等等)
Spring的MVC框架是圍繞DispatcherServlet來設計的,它用來處理全部的HTTP請求和響應。
控制器提供一個訪問應用程序的行爲,此行爲一般經過服務接口實現。控制器解析用戶輸入並將其轉換爲一個由視圖呈現給用戶的模型。Spring用一個很是抽象的方式實現了一個控制層,容許用戶建立多種用途的控制器。
答:是單例模式,因此在多線程訪問的時候有線程安全問題,不要用同步,會影響性能的,解決方案是在控制器裏面不能寫字段。
(1)用戶發送請求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到請求後,調用HandlerMapping處理器映射器,請求獲取Handle;
(3)處理器映射器根據請求url找到具體的處理器,生成處理器對象及處理器攔截器(若是有則生成)一併返回給DispatcherServlet;
(4)DispatcherServlet 調用 HandlerAdapter處理器適配器;
(5)HandlerAdapter 通過適配調用 具體處理器(Handler,也叫後端控制器);
(6)Handler執行完成返回ModelAndView;
(7)HandlerAdapter將Handler執行結果ModelAndView返回給DispatcherServlet;
(8)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析;
(9)ViewResolver解析後返回具體View;
(10)DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)
(11)DispatcherServlet響應用戶。
mvc是一種設計模式(設計模式就是平常開發中編寫代碼的一種好的方法和經驗的總結)。模型(model)-視圖(view)-控制器(controller),三層架構的設計模式。用於實現前端頁面的展示與後端業務數據處理的分離。
mvc設計模式的好處
1.分層設計,實現了業務系統各個組件之間的解耦,有利於業務系統的可擴展性,可維護性。
2.有利於系統的並行開發,提高開發效率。
註解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動態代理類。咱們經過反射獲取註解時,返回的是Java運行時生成的動態代理對象。經過代理對象調用自定義註解的方法,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。
@RequestMapping:用於處理請求 url 映射的註解,可用於類或方法上。用於類上,則表示類中的全部響應請求的方法都是以該地址做爲父路徑。
@RequestBody:註解實現接收http請求的json數據,將json轉換爲java對象。
@ResponseBody:註解實現將conreoller方法返回對象轉化爲json對象響應給客戶。
答:通常用@Controller註解,也可使用@RestController,@RestController註解至關於@ResponseBody + @Controller,表示是表現層,除此以外,通常不用別的註解代替。
在Spring MVC 中,控制器Controller 負責處理由DispatcherServlet 分發的請求,它把用戶請求的數據通過業務處理層處理以後封裝成一個Model ,而後再把該Model 返回給對應的View 進行展現。在Spring MVC 中提供了一個很是簡便的定義Controller 的方法,你無需繼承特定的類或實現特定的接口,只需使用@Controller 標記一個類是Controller ,而後使用@RequestMapping 和@RequestParam 等一些註解用以定義URL 請求和Controller 方法之間的映射,這樣的Controller 就能被外界訪問到。此外Controller 不會直接依賴於HttpServletRequest 和HttpServletResponse 等HttpServlet 對象,它們能夠經過Controller 的方法參數靈活的獲取到。
@Controller 用於標記在一個類上,使用它標記的類就是一個Spring MVC Controller 對象。分發處理器將會掃描使用了該註解的類的方法,並檢測該方法是否使用了@RequestMapping 註解。@Controller 只是定義了一個控制器類,而使用@RequestMapping 註解的方法纔是真正處理請求的處理器。單單使用@Controller 標記在一個類上還不能真正意義上的說它就是Spring MVC 的一個控制器類,由於這個時候Spring 還不認識它。那麼要如何作Spring 才能認識它呢?這個時候就須要咱們把這個控制器類交給Spring 來管理。有兩種方式:
RequestMapping是一個用來處理請求地址映射的註解,可用於類或方法上。用於類上,表示類中的全部響應請求的方法都是以該地址做爲父路徑。
RequestMapping註解有六個屬性,下面咱們把她分紅三類進行說明(下面有相應示例)。
value, method
value: 指定請求的實際地址,指定的地址能夠是URI Template 模式(後面將會說明);
method: 指定請求的method類型, GET、POST、PUT、DELETE等;
consumes,produces
consumes: 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;
params,headers
params: 指定request中必須包含某些參數值是,才讓該方法處理。
headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求。
做用: 該註解用於將Controller的方法返回的對象,經過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區。
使用時機:返回的數據不是html標籤的頁面,而是其餘某種格式的數據時(如json、xml等)使用;
請求路徑上有個id的變量值,能夠經過@PathVariable來獲取 @RequestMapping(value = 「/page/{id}」, method = RequestMethod.GET)
@RequestParam用來得到靜態的URL請求入參 spring註解時action裏用到。
相同點
都是基於mvc的表現層框架,都用於web項目的開發。
不一樣點
1.前端控制器不同。Spring MVC的前端控制器是servlet:DispatcherServlet。struts2的前端控制器是filter:StrutsPreparedAndExcutorFilter。
2.請求參數的接收方式不同。Spring MVC是使用方法的形參接收請求的參數,基於方法的開發,線程安全,能夠設計爲單例或者多例的開發,推薦使用單例模式的開發(執行效率更高),默認就是單例開發模式。struts2是經過類的成員變量接收請求的參數,是基於類的開發,線程不安全,只能設計爲多例的開發。
3.Struts採用值棧存儲請求和響應的數據,經過OGNL存取數據,Spring MVC經過參數解析器是將request請求內容解析,並給方法形參賦值,將數據和視圖封裝成ModelAndView對象,最後又將ModelAndView中的模型數據經過reques域傳輸到頁面。Jsp視圖解析器默認使用jstl。
4.與spring整合不同。Spring MVC是spring框架的一部分,不須要整合。在企業項目中,Spring MVC使用更多一些。
(1)轉發:在返回值前面加"forward:",譬如"forward:user.do?name=method4"
(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"
經過Jackson框架就能夠把Java裏面的對象直接轉化成Js能夠識別的Json對象。具體步驟以下 :
(1)加入Jackson.jar
(2)在配置文件中配置json的映射
(3)在接受Ajax方法裏面能夠直接返回Object,List等,但方法前面要加上@ResponseBody註解。
(1)解決post請求亂碼問題:
在web.xml中配置一個CharacterEncodingFilter過濾器,設置成utf-8;
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(2)get請求中文參數出現亂碼解決方法有兩個:
①修改tomcat配置文件添加編碼與工程編碼一致,以下:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
②另一種方法對參數進行從新編碼:
String userName = new String(request.getParamter(「userName」).getBytes(「ISO8859-1」),「utf-8」)
ISO8859-1是tomcat默認編碼,須要將tomcat編碼後的內容按utf-8編碼。
答:能夠將異常拋給Spring框架,由Spring框架來處理;咱們只須要配置簡單的異常處理器,在異常處理器中添視圖頁面便可。
答:能夠在@RequestMapping註解裏面加上method=RequestMethod.GET。
答:直接在方法的形參中聲明request,Spring MVC就自動把request對象傳入。
答:直接在形參裏面聲明這個參數就能夠,但必須名字和傳過來的參數同樣。
答:直接在方法中聲明這個對象,Spring MVC就自動會把屬性賦值到這個對象裏面。
答:返回值能夠有不少類型,有String, ModelAndView。ModelAndView類把視圖和數據都合併的一塊兒的,但通常用String比較好。
答:經過ModelMap對象,能夠在這個對象裏面調用put方法,把對象加到裏面,前臺就能夠經過el表達式拿到。
答:能夠在類上面加上@SessionAttributes註解,裏面包含的字符串就是要放入session裏面的key。
有兩種寫法,一種是實現HandlerInterceptor接口,另一種是繼承適配器類,接着在接口方法當中,實現處理邏輯;而後在Spring MVC的配置文件中配置攔截器便可:
<!-- 配置Spring MVC的攔截器 --> <mvc:interceptors> <!-- 配置一個攔截器的Bean就能夠了 默認是對全部請求都攔截 --> <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean> <!-- 只針對部分請求攔截 --> <mvc:interceptor> <mvc:mapping path="/modelMap.do" /> <bean class="com.zwp.action.MyHandlerInterceptorAdapter" /> </mvc:interceptor> </mvc:interceptors>
WebApplicationContext 繼承了ApplicationContext 並增長了一些WEB應用必備的特有功能,它不一樣於通常的ApplicationContext ,由於它能處理主題,並找到被關聯的servlet。
Tomcat 服務器Apache軟件基金會項目中的一個核心項目,是一個免費的開放源代碼的Web 應用服務器,屬於輕量級應用服務器,在中小型系統和併發訪問用戶不是不少的場合下被廣泛使用,是開發和調試JSP 程序的首選。
<Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
下面,咱們先大體瞭解Tomcat Connector的三種運行模式。
配製項:protocol=」HTTP/1.1」
NIO:同步非阻塞IO
利用Java的異步IO處理,能夠經過少許的線程處理大量的請求,能夠複用同一個線程處理多個connection(多路複用)。
Tomcat8在Linux系統中默認使用這種方式。
Tomcat7必須修改Connector配置來啓動。
配製項:protocol=」org.apache.coyote.http11.Http11NioProtocol」
備註:咱們經常使用的Jetty,Mina,ZooKeeper等都是基於java nio實現.
APR:即Apache Portable Runtime,從操做系統層面解決io阻塞問題。AIO方式,****異步非阻塞IO(Java NIO2又叫AIO) 主要與NIO的區別主要是操做系統的底層區別.能夠作個比喻:比做快遞,NIO就是網購後要本身到官網查下快遞是否已經到了(多是屢次),而後本身去取快遞;AIO就是快遞員送貨上門了(不用關注快遞進度)。
配製項:protocol=」org.apache.coyote.http11.Http11AprProtocol」
備註:需在本地服務器安裝APR庫。Tomcat7或Tomcat8在Win7或以上的系統中啓動默認使用這種方式。Linux若是安裝了apr和native,Tomcat直接啓動就支持apr。
在Tomcat中部署Web應用的方式主要有以下幾種:
利用Tomcat的自動部署。
把web應用拷貝到webapps目錄。Tomcat在啓動時會加載目錄下的應用,並將編譯後的結果放入work目錄下。
使用Manager App控制檯部署。
在tomcat主頁點擊「Manager App」 進入應用管理控制檯,能夠指定一個web應用的路徑或war文件。
修改conf/server.xml文件部署。
修改conf/server.xml文件,增長Context節點能夠部署應用。
增長自定義的Web部署文件。
在conf/Catalina/localhost/ 路徑下增長 xyz.xml文件,內容是Context節點,能夠部署應用。
Tomcat做爲servlet容器,有三種工做模式:
進入Tomcat的請求能夠根據Tomcat的工做模式分爲以下兩類:
面試時問到Tomcat相關問題的概率並不高,正式由於如此,不少人忽略了對Tomcat相關技能的掌握,下面這一篇文章整理了Tomcat相關的系統架構,介紹了Server、Service、Connector、Container之間的關係,各個模塊的功能,能夠說把這幾個掌握住了,Tomcat相關的面試題你就不會有任何問題了!另外,在面試的時候你還要有意識無心識的往Tomcat這個地方引,就好比說常見的Spring MVC的執行流程,一個URL的完整調用鏈路,這些相關的題目你是能夠往Tomcat處理請求的這個過程去說的!掌握了Tomcat這些技能,面試官必定會佩服你的!
學了本章以後你應該明白的是:
俗話說,站在巨人的肩膀上看世界,通常學習的時候也是先總覽一下總體,而後逐個部分個個擊破,最後造成思路,瞭解具體細節,Tomcat的結構很複雜,可是 Tomcat 很是的模塊化,找到了 Tomcat 最核心的模塊,問題才能夠遊刃而解,瞭解了 Tomcat 的總體架構對之後深刻了解 Tomcat 來講相當重要!
先上一張Tomcat的頂層結構圖(圖A),以下:
Tomcat中最頂層的容器是Server,表明着整個服務器,從上圖中能夠看出,一個Server能夠包含至少一個Service,便可以包含多個Service,用於具體提供服務。
Service主要包含兩個部分:Connector和Container。從上圖中能夠看出 Tomcat 的心臟就是這兩個組件,他們的做用以下:
一個Tomcat中只有一個Server,一個Server能夠包含多個Service,一個Service只有一個Container,可是能夠有多個Connectors,這是由於一個服務能夠有多個鏈接,如同時提供Http和Https連接,也能夠提供向相同協議不一樣端口的鏈接,示意圖以下(Engine、Host、Context下面會說到):
多個 Connector 和一個 Container 就造成了一個 Service,有了 Service 就能夠對外提供服務了,可是 Service 還要一個生存的環境,必需要有人可以給她生命、掌握其生死大權,那就非 Server 莫屬了!因此整個 Tomcat 的生命週期由 Server 控制。
另外,上述的包含關係或者說是父子關係,均可以在tomcat的conf目錄下的server.xml配置文件中看出,下圖是刪除了註釋內容以後的一個完整的server.xml配置文件(Tomcat版本爲8.0)
詳細的配置文件內容能夠到Tomcat官網查看:Tomcat配置文件
上邊的配置文件,還能夠經過下邊的一張結構圖更清楚的理解:
Server標籤設置的端口號爲8005,shutdown=」SHUTDOWN」 ,表示在8005端口監聽「SHUTDOWN」命令,若是接收到了就會關閉Tomcat。一個Server有一個Service,固然還能夠進行配置,一個Service有多個Connector,Service左邊的內容都屬於Container的,Service下邊是Connector。
知道了整個Tomcat頂層的分層架構和各個組件之間的關係以及做用,對於絕大多數的開發人員來講Server和Service對咱們來講確實很遠,而咱們開發中絕大部分進行配置的內容是屬於Connector和Container的,因此接下來介紹一下Connector和Container。
由上述內容咱們大體能夠知道一個請求發送到Tomcat以後,首先通過Service而後會交給咱們的Connector,Connector用於接收請求並將接收的請求封裝爲Request和Response來具體處理,Request和Response封裝完以後再交由Container進行處理,Container處理完請求以後再返回給Connector,最後在由Connector經過Socket將處理的結果返回給客戶端,這樣整個請求的就處理完了!
Connector最底層使用的是Socket來進行鏈接的,Request和Response是按照HTTP協議來封裝的,因此Connector同時須要實現TCP/IP協議和HTTP協議!
Tomcat既然須要處理請求,那麼確定須要先接收到這個請求,接收請求這個東西咱們首先就須要看一下Connector!
Connector架構分析
Connector用於接受請求並將請求封裝成Request和Response,而後交給Container進行處理,Container處理完以後在交給Connector返回給客戶端。
所以,咱們能夠把Connector分爲四個方面進行理解:
首先看一下Connector的結構圖(圖B),以下所示:
Connector就是使用ProtocolHandler來處理請求的,不一樣的ProtocolHandler表明不一樣的鏈接類型,好比:Http11Protocol使用的是普通Socket來鏈接的,Http11NioProtocol使用的是NioSocket來鏈接的。
其中ProtocolHandler由包含了三個部件:Endpoint、Processor、Adapter。
至此,咱們應該很輕鬆的回答1,2,3的問題了,可是4仍是不知道,那麼咱們就來看一下Container是如何進行處理的以及處理完以後是如何將處理完的結果返回給Connector的?
Container用於封裝和管理Servlet,以及具體處理Request請求,在Container內部包含了4個子容器,結構圖以下(圖C):
4個子容器的做用分別是:
下面找一個Tomcat的文件目錄對照一下,以下圖所示:
Context和Host的區別是Context表示一個應用,咱們的Tomcat中默認的配置下webapps下的每個文件夾目錄都是一個Context,其中ROOT目錄中存放着主應用,其餘目錄存放着子應用,而整個webapps就是一個Host站點。
咱們訪問應用Context的時候,若是是ROOT下的則直接使用域名就能夠訪問,例如:www.baidu.com,若是是Host(webapps)下的其餘應用,則可使用www.baidu.com/docs進行訪問,固然默認指定的根應用(ROOT)是能夠進行設定的,只不過Host站點下默認的主應用是ROOT目錄下的。
看到這裏咱們知道Container是什麼,可是仍是不知道Container是如何進行請求處理的以及處理完以後是如何將處理完的結果返回給Connector的?別急!下邊就開始探討一下Container是如何進行處理的!
Container處理請求是使用Pipeline-Valve管道來處理的!(Valve是閥門之意)
Pipeline-Valve是責任鏈模式,責任鏈模式是指在一個請求處理的過程當中有不少處理者依次對請求進行處理,每一個處理者負責作本身相應的處理,處理完以後將處理後的結果返回,再讓下一個處理者繼續處理。
可是!Pipeline-Valve使用的責任鏈模式和普通的責任鏈模式有些不一樣!區別主要有如下兩點:
咱們知道Container包含四個子容器,而這四個子容器對應的BaseValve分別在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。
Pipeline的處理流程圖以下(圖D):