Java開發:開源框架面試總結

      此篇文章是應屆生臨時總結的Java開發面試開源框架部分:主要總結了主要的幾個點,便於回答,用於有一定Java基礎的同學面試所用,由於是面試問題,所以內容多有不詳盡之處。

      學習一個技術要明白幾個點:這個技術是什麼?有什麼特點?怎麼使用?什麼時候使用?這是學一個技術的態度問題。

      另外,大公司的面試官往往也很喜歡問這樣的籠統問題:可以談談你對Spring的理解麼!面對這種問題,初出茅廬的應屆生往往都啞口無言,如果想要回答的體面,可以從這四個點來回答,你回答的過程中,面試官可能一直在聽直到你講完,也可能讓你不用繼續說了,因為他已經明白了你懂這些內容,並且善於組織這些東西,也有所準備。無論是哪一種,都能給面試官留下一個好印象。

1 Tomcat

1.1 Tomcat介紹

Tomcat是什麼?

(是什麼)Tomcat是一個免費的開原始碼的輕量級Web應用伺服器;

(應用場合)一般在中小型系統和併發使用者不多的場合下使用於開發和除錯Jsp程式;

(使用目的)用來執行Jsp頁面和Servlet來響應HTML頁面請求。

 

1.2 元件等級劃分

            

Tomcat按功能劃分為許多不同的元件,並可通過/conf/server.xml檔案對其定義和配置,包括Server, Service, Connector,Engine,  Host,  Context……一般可分4個等級:

     1、頂級元件:位於配置層次的頂級,並且彼此間有著嚴格的對應關係,有Server和Service元件;

     2、聯結器:連線客戶端(瀏覽器或Web伺服器)請求至Servlet容器,如Connector元件,

     3、容器:功能是處理傳入請求的元件,並建立相應的響應。如Engine處理對一個Service的所有請求,Host處理對特定虛擬主機的所有請求,Context處理對特定web應用的所有請求;

     4、被巢狀的元件:位於一個容器當中,但不能包含其它元件;一些元件可以巢狀在任何Container中,而另一些只能巢狀在Context中。

1.3 元件間互聯關係

      如果把Tomcat比較一個框架類,那麼一個Server伺服器表示一個Tomcat例項,通常一個JVM也只包含一個Tomcat例項,一個Server中可以有多個Service服務,Service可以包含一個或多個Connector用於連線Container容器中的一個Engine,聯結器Connector通過特定埠接收客戶端請求,並將其轉發到關聯的Engine;

      而Engine作為Servlet容器引擎,包含多個Host元件和其他元件,引擎接收並處理來自一個或多個聯結器的請求,並辨別請求的HTTP首部資訊以便確定發往哪個Context或Host(客戶端通常使用主機名來標識他們希望連線的伺服器),並將完成的響應返回到聯結器,以便最終傳輸回客戶端。

      一個Context上下文對應一個Web應用程式,即一個Web project,而一個Web工程包含多一個Wrapper(Servlet應用程式的包裝類)。也就是說,在tomcat容器等級中,Context容器直接管理Servlet在容器中的包裝類Wrapper,所以Context容器如何執行將直接影響servlet的工作方式。

【可省略不看……

1 Server

      Server(伺服器)表示Tomcat的一個例項,因此,它必須是/conf / server.xml配置檔案中的單個最外層元素,它的屬性表示servlet容器的整體特性。通常一個JVM只能包含一個Tomcat例項。預設配置表示監聽在8005埠以接收shutdown命令,預設僅允許通過本機訪問。

2 Service

      Service(服務)主要用於關聯一個Engine和與此Engine相關的Connector,每個Connector通過一個特定的埠和協議接收請求,並將其轉發至關聯的Engine進行處理。

       因此,Service可以包含一個Engine、以有一個或多個Connector;而一個Server可以包含多個Service元件,但通常情下只為一個Server指派一個Service。通常需要給Service命名,可以方便管理員在日誌檔案中識別不同Service產生的日誌。

       如預設配置中server只包含一個名為”Catalina”的service,而service裡包含兩個Connector,其中一個監聽8080埠接收HTTP請求,另一個監聽8009埠接收AJP協議的請求。

3 Connector

       Connector(聯結器)通過一個特定的埠接收特定協議的客戶端請求,並將其轉發至關聯的Engine進行處理。一個Engine可以配置多個聯結器,但這些聯結器必須使用不同的埠。

      定義聯結器可以使用多種屬性,有些屬性也只適用於某特定的聯結器型別。一般說來,聯結器型別可以分為兩種:Http聯結器和AJP聯結器。

4 Engine 

     Engine(引擎)表示與特定Service相關聯的整個請求處理機制,即Servlet容器引擎。它接收和處理來自一個或多個聯結器的所有請求,並檢查每一個請求的HTTP首部資訊以辨別此請求應該發往哪個Host或Context,並將完成的響應返回到聯結器,以便最終傳輸回客戶端。

     一個Engine元素必須巢狀在Service元素內,它可以包含多個host元件,還可以包含Realm、Listener和Valve等子容器。

5 Host

      Host(虛擬主機)類似於Apache中的虛擬主機,但在Tomcat中只支援基於FQDN的”虛擬主機”。Host位於Engine容器中用於接收請求並進行相應處理,它是伺服器(例如”www.mycompany.com”)的網路名稱與執行Tomcat的特定伺服器的關聯。

      客戶端通常使用主機名來標識他們希望連線的伺服器,但要使客戶端能夠使用其網路名稱連線到Tomcat伺服器,此名稱必須在管理所屬的Internet域的域名服務(DNS)伺服器中註冊。

6 Context元件

      Context(上下文)表示在特定虛擬主機中執行的Web應用程式,一個Context對應一個Web應用程式(Web工程),而裡面的Wrapper可以理解為一個Servlet程式

      Context需要根據其定義的上下文路徑(path)匹配請求URI的最長字首(除主機名外)來選擇。一旦選擇,可以由docBase來找到該上下文將對應的web應用程式部署目錄,由目錄中web.xml定義的servlet對映選擇一個合適的servlet來處理傳入的請求。            】

1.4 Tomcat與Jetty的比較

     Tomcat和Jetty都是一種應用的比較廣泛的Servlet引擎,但是相比較於Jetty,Tomcat更加穩定成熟,其市場霸主地位仍然難以撼動。但是兩者各有優劣,現對其進行綜合比較:

(1)架構方面

      Jetty所有元件都是基於Handler來實現的,是一種面向Handler的架構。(Spring是一種面向Bean的架構,IBatis是一種面向Statement的架構)         

從設計模式角度來看:一、Handler採用責任鏈設計模式:HandlerCollection可以幫助開發者構建一個鏈,介面類ScopeHandler可以幫助開發者控制這個鏈的訪問順序;二、採用了觀察者設計模式,物件只要繼承了LifeCycle介面就可以被Jetty管理控制整個生命週期。

     Tomcat則是一種多級容器的構建模式,所有元件依附於其構建骨架;其核心就是容器設計,設計臃腫複雜,是為了更好擴充套件,但是將內部結構暴露給了外部使用者,學習難度變大,增加學習成本,其難度。

 

     Jetty講的是做某件事的規範,即告訴你應該怎麼做,如果做由開發者自己實現;

     Tomcat則是已經做了很多的工作,你要先理解這些工作,然後在此基礎上做額外的工作。 

(2)效能方面

     Tomcat和Jetty的使用場景不盡相同,即對相同的使用場景,兩者效能各有優劣。

     Jetty可以同時處理並保持大量的連線,適合生命週期長的;按需載入元件,使用NIO技術,處理I/O請求上更具優勢。例如,淘寶Web旺旺使用的就是Jetty作為Servlet引擎。

     Tomcat適合處理少數頻繁並且生命週期短的連線;使用BIO技術,處理靜態資源時效能較差。

(3)特性方面

      Jetty和Tomcat都支援標準的Servlet規範、JavaEE規範。

      只不過Tomcat更加成熟,支援的更加全面而已,整合了很多這些規範的特性;整體結構複雜,修改功能緩慢,不易擴充套件。

      而Jetty輕便靈敏(因為其開發社群更加靈活,修改更加簡單),整體結構簡單易用,元件可替換,功能修改較快,容易擴充套件。

2 Servlet容器

2.1 Servlet介紹

根據自己的理解,Servlet是什麼?作用?

     (是什麼?)Servlet是實現了Servlet介面,並通過“請求-響應”模式來訪問的服務端Java程式;

     (幹什麼的)主要用於開發動態Web資源;互動式的瀏覽和修改資料,動態的擴充套件Server的能力。

(1)接受請求,並與伺服器資源進行通訊;

(2)建立並返回一個基於客戶端請求性質的動態內容HTML頁面給客戶端。

 

下面是一段Servlet的具體定義:

     Servlet是sun公司提供的一種用於開發動態web資源的技術,其API提供了servlet介面,若使用者想要開發一個動態web資源,需要:
  1、編寫一個實現servlet介面的Java類。
  2、把開發好的Java類部署到web伺服器中。
  通常,按照習慣把實現了Servlet介面的java程式,稱為Servlet。

    Servlet依賴於Servlet容器,兩者類似於槍和子彈,相互依存、相互增強,但又相互獨立,通過標準化介面進行協調工作

    Servlet容器獨立發展,種類很多,各有定位,各有特點,比較流行的有Jetty、Tomcat等,其中以Tomcat佔據市場主流。

2.2 Servlet生命週期

      servlet始於裝入web伺服器記憶體,並在web伺服器終止或重灌servlet時結束。servlet一旦被裝入web伺服器,一般不會從web伺服器記憶體中刪除,直至web伺服器關閉或重灌才會結束。
      (1)初始化:web伺服器啟動時或web伺服器接收到請求時載入Servlet。執行init();

      (2)呼叫:執行service()方法,service()自動派遣執行與請求相對應的doGet()或doPost()方法;

      (3)銷燬:停止伺服器時呼叫destroy()方法,銷燬例項。  

2.3 Servlet呼叫流程

     結合著生命週期說,Servlet程式是由WEB伺服器呼叫,web伺服器收到客戶端的Servlet訪問請求後:
   (1)Web伺服器接收到瀏覽器傳送的請求之後,首先檢查是否已經裝載並建立了該Servlet的例項物件。

   (2)如果沒有Servlet實物件,裝載並建立該Servlet的一個例項物件,呼叫Servlet例項物件的init()方法初始化。

   (3)建立一個用於封裝HTTP請求訊息的HttpServletRequest物件和一個代表HTTP響應訊息的HttpServletResponse物件,然後呼叫Servlet的service()方法並將請求和響應物件作為引數傳遞進去。
   (4)WEB應用程式被停止或重新啟動之前,Servlet引擎將解除安裝Servlet,並在解除安裝之前呼叫Servlet的destroy()方法。

IE瀏覽器:http://localhost:8080/Demo/function.do 這個過程都經歷了什麼?

     (1)連線上web伺服器

     (2)傳送http請求

           GET/FirstServlet/first.do HTTP/1.1
           Accept: image/gif,image/jpeg, image/pjpeg, image/pjpeg, application/xaml xml,application/x-ms-xbap, application/x- ms-application,application/vnd.ms-xpsdocument, */*
           Accept-Language:zh-cn,en-US;q=0.7,ar-OM;q=0.3
           User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C;.NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
           Accept-Encoding:gzip, deflate
           Host:localhost:8080
           Connection:Keep-Alive

web伺服器(Tomcat)

     (3)解析出想訪問的主機名

     (4)解析出想訪問的web應用

     (5)解析出想訪問的web資源

FirstServlet.java

      (6)第一次則建立servlet例項物件

      (7)第一次的話,則呼叫servlet的init方法完成物件初始化

      (8)建立代表請求request和代表響應的response物件,然後呼叫servlet的service方法響應客戶端的請求

      (9)service方法執行,向代表客戶端響應的response物件寫入了要輸出的資料

      (10)伺服器從response中取出資料,構建出一個http響應,回寫給客戶機

       HTTP/1.1 200 OK

        Server: Apache-Coyote/1.1

        Content-Length: 14

        Date: Sat, 24 Dec 2011 04:00:55 GMT

        hello servlet!

     (11)瀏覽器解析http響應,提取資料顯示

     (12)WEB應用程式被停止或重新啟動之前,Servlet引擎將解除安裝Servlet,並在解除安裝之前呼叫Servlet的destroy()方法。

2.4 Servlet執行緒安全問題

1)實現 SingleThreadModel介面;(不一定安全)

        針對Service()方法

2)使用Syncronized關鍵字實現資料共享;

3)避免使用例項變數;

2.5 Servlet 通訊

        Web容器在啟動的時候為每個應用建立一個ServletContext物件,ServletConfig物件中維護了ServletContext的引用,開發人員在編寫servlet時,可以通過ServletConfig.getServletContext方法獲取到ServletContext物件。由於一個web應用中的所有servlet共享一個ServletContext物件,因此servlet物件之間可以通過ServletContext物件來實現通訊。ServletContext物件也通常被稱為Context域物件。

1.多個servlet通過ServletContext物件實現資料共享。Initservlet的Service方法中利用ServletContext物件存入需要共享的資料

ServletContext context=this.getServletContext();

Context.setAttribute(“name”,“Lucy”);

    在其他的servlet中利用ServletContext物件獲取共享資料

ServletContext context =this.getServletContext();

String name =context.getAttribute(“name”);

2.獲取web應用的初始化引數。在DemoServlet的doPost方法中獲取初始化引數的步驟如下:

ServletContextcontext=this.getServlenContext();

String url=context.getInitParmeter(“url”); 

2.6 Servlet 工作原理、如何實現

1:使用者通過瀏覽器向伺服器傳送一個請求url: 
http://hostname:port/contextpath/servletpath;
 其中,hostname和port用來與伺服器簡歷TCP連線,contextpaht和servletpath路徑用於選擇伺服器中對應子容器服務請求

2:如何選擇子容器?使用org.apache.tomcat.util.http.mapper這個對映類儲存Container容器中所有子容器資訊,  org.apache.tomcat.catalina.connector.Request請求類進入Container容器之前,Mapper類就根據hostname和contextpath在mappingData屬性中儲存了host和Container容器之間的關係,可以根據這個對映關係選擇子容器。

3:Mapper類又如何儲存這個對映關係呢?使用類似於觀察者模式的方法,將MapperListener作為一個監聽者加入Container容器的每個子容器,一旦容器發生變化,儲存容器關係的MapperListener類的mapper屬性也會修改更新

2.7 寫一個Servlet例子和配置Servlet

public class SecondServlet extends HttpServlet {
@Override
public void init() throws ServletException {        System.out.println("這是init()方法...");    }
@Override
Public void doGet(HttpServletRequest req, HttpServletResponse resp)  throws ServletException, IOException {
System.out.println("這是doGet()方法...");
// 設定內容型別
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<html><head><title>Hello World Sample</title></head>");
out.println("<body><h1>Hello World Title<h1><h2>"  new Date().toLocaleString()   "</h2></body></html>");
out.flush();         }
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("這是doPost()方法...");
}
Public void service(){};
@Override
public void destroy() {        System.out.println("這是destroy()方法..."); }
}

除了Servlet的書寫,還有Servlet配置:

            

2.8 Filter 和其工作原理

     對於一個web應用程式來說,過濾器是處於web容器內的一個元件,它會過濾特定請求資源請求資訊和響應資訊。一個請求來到時,web容器會判斷是否有過濾器與該資訊資源相關聯,如果有則交給過濾器處理,然後再交給目標資源,響應的時候則以相反的順序交給過濾器處理,最後再返回給使用者瀏覽器。

     過濾器類需要實現javax.servlet.Filter,該介面的doFilter()方法是業務處理的核心程式碼區,類似於servlet的service()方法。doFilter()方法的引數列表有一個FilterChain介面的實現物件,它只有一個方法doFilter(),在呼叫該方法之前的程式碼會在達到目標資源前執行,之後的程式碼會在目標資源已經響應後執行。

工作原理:

        當客戶端發出Web資源的請求時,Web伺服器根據應用程式配置檔案設定的過濾規則進行檢查,若客戶請求滿足過濾規則,則對客戶請求/響應進行攔截,對請求頭和請求資料進行檢查或改動,並依次通過過濾器鏈,最後把請求/響應交給請求的Web資源處理。請求資訊在過濾器鏈中可以被修改,也可以根據條件讓請求不發往資源處理器,並直接向客戶機發回一個響應。當資源處理器完成了對資源的處理後,響應資訊將逐級逆向返回。同樣在這個過程中,使用者可以修改響應資訊,從而完成一定的任務。

  兩個過濾器同時過濾一個請求時,就要用到過濾鏈FilterChain.Filter的FilterChain中,伺服器會按照web.xml中過濾器定義的先後循序組裝成一條鏈,然後一次執行其中的doFilter()方法。執行的順序就如下圖所示,執行第一個過濾器的chain.doFilter()之前的程式碼,第二個過濾器的chain.doFilter()之前的程式碼,請求的資源,第二個過濾器的chain.doFilter()之後的程式碼,第一個過濾器的chain.doFilter()之後的程式碼,最後返回響應。

2.9 寫一個Filter和配置Filter

public class EncodingFilterTest implementsFilter {
public void destroy(){      // TODO Auto-generated method stub  }
public void doFilter(ServletRequestrequest,ServletResponse response,FilterChain chain) throws IOException,  //三個引數比較重要
ServletException  {
System.out.println("encodingFilterdoFilter-----");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
chain.doFilter(request,response);
}
public void init(FilterConfigarg0) throws ServletException {  System.out.println("過濾器初始化");  }
}

配置:

             

 

3 Spring

3.0框架基礎概念

1、應用程式:是能完成我們所需要功能的成品,比如購物網站、OA系統。

2、框架:是能完成一定功能的半成品,比如我們可以使用框架進行購物網站開發;框架做一部分功能,我們自己做一部分功能,這樣應用程式就建立出來了。而且框架規定了你在開發應用程式時的整體架構,提供了一些基礎功能,還規定了類和物件的如何建立、如何協作等,從而簡化我們開發,讓我們專注於業務邏輯開發。

3、非侵入式設計:從框架角度可以這樣理解,無需繼承框架提供的類,這種設計就可以看作是非侵入式設計,如果繼承了這些框架類,就是侵入設計,如果以後想更換框架之前寫過的程式碼幾乎無法重用,如果非侵入式設計則之前寫過的程式碼仍然可以繼續使用。

4、輕量級及重量級:輕量級是相對於重量級而言的,輕量級一般就是非入侵性的、所依賴的東西非常少、資源佔用非常少、部署簡單等等,其實就是比較容易使用,而重量級正好相反。

5、POJO:POJO(Plain Old Java Objects)簡單的Java物件,它可以包含業務邏輯或持久化邏輯,但不擔當任何特殊角色且不繼承或不實現任何其它Java框架的類或介面。

6、容器:在日常生活中容器就是一種盛放東西的器具,從程式設計角度看就是裝物件的的物件,因為存在放入、拿出等操作,所以容器還要管理物件的生命週期。

7、控制反轉:即Inversion of Control,縮寫為IoC,控制反轉還有一個名字叫做依賴注入(DependencyInjection),就是由容器控制程式之間的關係,而非傳統實現中,由程式程式碼直接操控。

8、Bean:一般指容器管理物件,在Spring中指Spring IoC容器管理物件。

3.1 Spring簡介

Spring是什麼?

             Spring是一個開源的輕量級Java SE(Java 標準版本)/Java EE(Java 企業版本)開發應用框架,其目的是用於簡化企業級應用程式開發。

幹什麼的,優點?

(1)通過配置方式來建立物件,並自動管理物件之間依賴關係(IOC控制反轉); 【輕量級容器】

(比起傳統方式避免了原始碼修改,重新編譯和部署,減少工作,加速開發,節省時間)

(2)除此之外,還提供像通用日誌記錄、效能統計、安全控制、異常處理等面向切面的能力;將這些常用功能從業務邏輯中分離出來,通過面向切面程式設計,在需要這些功能的地方動態新增這些功能,無需滲透到各個需要的方法或物件中;【AOP面向切面】

(相比較於傳統程式碼使用物件呼叫或代理等,這種面向切面的能力避免了程式碼重複,實現了零耦合

(3)還能繁瑣的資料庫事務;Spring本身提供了一套簡單的JDBC訪問實現;【簡單的資料庫事務管理】

(相比於傳統程式碼管理事務的“獲取連線,執行SQL,提交或回滾事務,關閉連線”一系列繁瑣操作,使用Spring,我們只需獲取連線並執行SQL,其他的一切都交給Spring管理)

(4)Spring還提供與第三方資料訪問框架(如Hibernate、JPA)無縫整合的能力;提供JDBC訪問模板。【JDBC抽象及ORM框架支援】

(5)與各種Java EE技術整合(如JavaMail、任務排程等等),提供一套自己的web層框架SpringMVC、而且還能非常簡單的與第三方web框架整合;

3.2 Spring設計思想

                    

       從圖中可以看出,Spring的核心元件為:Core、Context、Beans,他們三個構成Spring的基礎骨架,其他功能元件的使用都依賴於這三個核心元件,其實Spring可以看做是一個面向Bean的程式設計

參考連結:

http://blog.csdn.net/lp1052843207/article/details/51253071

https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/

      

     Spring在IOC容器中根據配置檔案來管理物件之間的依賴關係,即依賴注入機制。

      把Bean比作演員,Context就是演出的舞臺背景,Core相當於演出的道具;Bean包裝了Object,Context則給這些Bean提供生存環境,並利用Core工具(類似於Utils)發現每個Bean之間的關係,並建立和維護這種關係;所以,可以說Context是一個Bean關係的集合,又叫IOC容器

 

Bean元件:

        在org.springframework.beans包下,主要用來解決:Bean的定義、Bean的建立、Bean的解析。

        Bean的建立使用了工廠模式,頂級介面是BeanFactory,BeanFactory有三個子類:ListableBeanFactory(可列表)、  HierarchicalBeanFactory(有繼承關係)、AutowirecapableBeanFactory(自動裝配),三者各有自己的使用場合,在Spring內部物件傳遞和轉化過程中,對物件資料訪問進行限制。

       Bean的定義主要由BeanDefinition描述,完整的描述了在Spring的配置檔案中定義的<bean/>節點中所有的資訊,包括裡面的子節點。當Spring成功的解析一個節點後,在Spring的內部轉化成BeanDefinition物件。

      Bean的解析主要是對Spring配置檔案的解析,依賴於LoadBeanDefinition。

 

Context元件:

      在org.springframework.context包下,給Spring提供一個執行時環境,用以儲存各物件狀態。

      ApplicationContext是Context的頂級父類,它繼承了BeanFactory和ResourceLoader(使得Spring可以 訪問外部資源),前者用於執行主體物件Bean,後者用於訪問任何外部資源。

      ApplicationContext派發的兩個子類:ConfigurableApplicationContext和WebApplicationContext前者用於使用者動態的修改或新增配置資訊,後者用於為Web準備的Context,可直接訪問ServletContext;

     總體來講ApplicationContext主要完成了:

     標識一個應用環境;利用BeanFactory建立Bean物件;儲存物件關係表;捕捉各種事件

 

Core元件:

     包含了很多關鍵類,比較重要的是定義了資源的訪問方式。把所有資源都抽象成一個介面用於訪問。

     Resource介面封裝了資源型別,遮蔽了檔案型別的不同。

    Resource介面的父介面InputStreamSource介面,可利用getInputInstream()直接得到資源InputStream類,遮蔽了資源提供者。

    Resource派發的子介面ResourceSourceLoader介面,可遮蔽所有資源載入者的差異。

3.3 Spring IOC

1 何為控制反轉?

     控制反轉:即Inversionof Control,縮寫為IOC;依賴注入(DependencyInjection)可以認為是IOC的實現。

     將控制權交給IOC容器來掌管,通過控制物件之間的關係來管理程式,而非像傳統實現中,由程式程式碼直接操控。

2 為什麼把這種方式叫做控制反轉?

    如果物件存在組合關係,傳統的程式碼程式中,物件之間相互依賴,需要用的時候,自己必須主動建立物件或者使用已經建立好的物件;控制權都在我們自己手上;

    但是,如果軟體系統引入了Ioc容器之後,物件之間失去了直接聯絡,一個物件例項化或執行時,如果需要用到另外的物件,IoC容器會主動建立這個物件並注入到使用的物件中,這種控制權的主動行為變成被動行為,控制轉發生轉移,我們把它叫做控制反轉。控制反轉帶來的一個直觀的好處就是低耦合,元件之間相互獨立。

3 IOC如何實現控制反轉或控制反轉原理?

【主要利用 工廠模式 反射技術

     IOC中最基本的技術就是“反射(Reflection)”程式設計:Spring在配置檔案中給出了要生成物件的定義,利用反射技術根據配置檔案給出的類名(字串方式)來動態地生成物件,這種程式設計方式可以讓物件在生成時才決定到底是哪一種物件;目的就是提高靈活性和可維護性。

    IOC容器的工作模式可以看做是一個工廠模式,IOC容器就像一個工廠,這個工廠要生成的物件都在配置檔案中已經給出定義,然後利用程式語言的的反射技術 ,根據配置檔案中給出的類名生成相應的物件;在實現上,IOC是把以前在工廠方法裡寫死的物件生成程式碼,改變為由配置檔案來定義,實現了工廠和物件生成的分離,目的就是提高靈活性和可維護性。

   【具體請看設計模式之工廠模式反射技術

4 IOC容器如何工作:

    IOC實際是Context利用Core構建的一個Bean關係網。構建的入口在AbstractApplicationContext類的refresh方法中,功能有:1.構建BeanFactory,便於生產bean;2.註冊可能感興趣的事件;3.建立Bean例項物件;4.觸發被監聽的事件。

    LoadBeanDefinition(beanFactory)完成載入、解析Bean的定義,把使用者的資料轉換成 Ioc中的BeanDefinition結構。

Bean的生命週期:

    1.Bean的建立:由BeanFactory讀取Bean定義檔案配置檔案,並生成各個例項

    2.Setter注入:執行Bean的屬性依賴注入

    3.BeanNameAwaer的SetBeanName:如果Bean實現了該介面,就執行該方法

     BeanFactoryAware的setBeanFactory:如果Bean實現了該介面,則執行方法。

    4.Bean定義檔案中定義的init-method屬性用於設定方法名稱,初始化時會執行init-method方法,無參。

           

DisposableBean的destroy() 在容器關閉時,執行實現類Bean的destroy()方法。

    5.Bean檔案中定義的destory-method,在容器關閉的時候使用dstory-method方法,不帶引數。

          

總結:

Bean的完整生命週期從 spring 容器開始例項化bean 開始,到銷燬。可以從三點來理解

       1、 bean自身的方法:包括構造方法、set 方法、 init-method 指定的方法、destroy-method 指定的方法

        2、 Bean級生命週期介面方法:如 BeanNameAware 、 BeanFactoryAware 等這些介面方法由 bean類實現。

        3、 容器級生命週期介面方法:上圖中帶星的。有InstantiationAwareBeanPostProcessor 、 BeanPostProcessor 等。一般稱為後處理 器。他們一般不由bean 本身實現,獨立存在,註冊到spring 容器中。Spring 通過介面反射預先知道,當spring 容器建立任何bean 時,這些後處理器都會發生作用。所以他們是全域性的,使用者可以通過編碼對只感興趣的bean 進行處理。

5 使用IOC的好處、優勢?

        (1)【測試除錯】可維護性比較好,非常便於進行單元測試,便於除錯程式和診斷故障。程式碼中的每一個Class都可以單獨測試,彼此之間互不影響,只要保證自身的功能無誤即可,這就是元件之間低耦合或者無耦合帶來的好處。

        (2)【分工明確】IOC可使任務獨立,各自進行單元測試,每個團隊只需要關注自己的業務邏輯即可,分工明確,責任明晰,提高效率。

        (3)【元件複用】IoC獨立了元件單元,使得元件可複用性好,可把具有普遍性的常用元件獨立出來,反覆應用;

        (4)【修改維護】IoC把物件的生成放在配置檔案裡進行定義,更換實現子類時更加簡單,只要修改配置檔案即可,完全具有熱插撥特性。

6 使用IOC容器應該注意的地方?

        (1)軟體系統中由於引入了第三方IOC容器,生成物件的步驟變得有些複雜。不太直觀。

        (2)由於IOC容器生成物件是通過反射方式,在執行效率上有一定的損耗。

        (3)需要進行大量的配製工作,比較繁瑣,對小專案而言可能加大一些工作成本。

        (4)IOC框架產品本身的成熟度需要進行評估,存在隱性風險。

3.4 Spring AOP

3.4.1 Spring AOP是什麼,用來幹什麼的?

        AOP是一種面向切面的程式設計技術,主要用來通過預編譯方式和執行期動態代理實現程式功能的統一維護的技術。

        AOP是對OOP的補充和完善。OOP引入了封裝、繼承、多型等概念來建立一種物件層次結構,用於開發者定義一種縱向關係,但並不適合定義橫向的關係。例如日誌功能,日誌程式碼往往橫向地散佈在各個層次中,但是卻對該層對應的物件沒有什麼關係。在OOP中,這種散佈在各處的無關程式碼橫切(cross cutting)了對應層次物件,但是卻導致了程式碼重複,不利於模組複用。

        AOP則是利用”橫切”技術,剖解開封裝的物件,抽取出那些散落在各個層次中但和縱向業務無關的重複呼叫的功能,並將其封裝為一個可重用模組,並將其命名為”Aspect”,即切面。降低了模組之間的耦合度,並有利於未來的可操作性和可維護性。

        AOP把軟體系統分為兩個部分:核心關注點橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處基本相似,比如許可權認證、日誌、事物。

        AOP的作用就在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。

3.4.2 AOP核心概念

1、橫切關注點

        對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之為橫切關注點

2、切面(aspect)

        類是對物體特徵的抽象,切面就是對橫切關注點的抽象

3、連線點(joinpoint)

        被攔截到的點,因為Spring只支援方法型別的連線點,所以在Spring中連線點指的就是被攔截到的方法,實際上連線點還可以是欄位或者構造器

4、切入點(pointcut)

        對連線點進行攔截的定義

5、通知(advice)

        所謂通知指的就是指攔截到連線點之後要執行的程式碼,通知分為前置、後置、異常、最終、環繞通知五類

6、目標物件

        代理的目標物件

7、織入(weave)

        將切面應用到目標物件並導致代理物件建立的過程

8、引入(introduction)

        在不修改程式碼的前提下,引入可以在執行期為類動態地新增一些方法或欄位

 

3.4.3 Spring AOP如何實現?

        Spring中AOP代理由Spring的IOC容器負責生成、管理,其依賴關係也由IOC容器負責管理。因此,AOP代理可以直接使用容器中的其它bean例項作為目標,這種關係可由IOC容器的依賴注入提供;

第一、SPring AOP預設使用Java動態代理,載入一個動態代理類來代理介面並實現一些自定義操作。

        1、SPringAOP 利用JDK環境下java.lang.reflect包下的Proxy類來構造代理類。

        2、具體建立:呼叫Proxy類下的static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法建立代理物件;

引數1 ClassLoader –用於載入代理類的Loader類;

引數2 Interfaces–被代理介面;

引數3 InvocationHandler –用於執行除了代理介面中定義的方法外的其他的自定義操作,這些操作都定義在該類的invoke()方法

        3、newProxyInstance(ClassLoaderloader,Class<?>[] interfaces,InvocationHandler h)主要業務程式碼:

    Class c1=getProxyClass(loader,interfaces);           //1:構造代理類名
Constructorcons=c1.getConstructor(constructorParams);// 2建立建構函式類
return(Object)cons.newInstance(new Object[] {h});  //建立代理物件(引數傳入)

意思就是:

        1:呼叫getProxyClass方法把載入類和被代理介面作為引數傳入來構建代理類名;

         2:呼叫代理類名的getConstructor建立建構函式類。

         3:利用建構函式類的newInstance()方法,並傳入實現了自定義操作的類物件h,建立Spring AOP的代理類。(會自動將方法對應屬性引數傳給invoke()方法的Method引數並執行)

 

第二、當需要代理的類不是代理介面的時候,Spring會切換為使用CGLIB代理,也可強制使用CGLIB

         AOP程式設計其實是很簡單的事情,縱觀AOP程式設計,程式設計師只需要參與三個部分:         

1:定義普通業務元件

2:定義切入點,一個切入點可能橫切多個業務元件

3:定義增強處理,增強處理就是在AOP框架為普通業務元件織入的處理動作

       所以進行AOP程式設計的關鍵就是定義切入點和定義增強處理,一旦定義了合適的切入點和增強處理,AOP框架將自動生成AOP代理,即:代理物件的方法=增強處理 被代理物件的方法。 

<bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" /> 普通業務實現類
<bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" /> 普通業務實現類
<bean id="timeHandler" class="com.xrq.aop.TimeHandler" />           增強處理
<aop:config>
<aop:aspect id="time" ref="timeHandler">                    定義切入點
<aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
<aop:before method="printTime" pointcut-ref="addAllMethod" />
<aop:after method="printTime" pointcut-ref="addAllMethod" />
</aop:aspect>
</aop:config> 

        如果一個切入點要執行多個方法,可以通過order屬性定義橫切關注點的順序。

3.4.4 動態代理

      在程式執行時,運用反射機制動態建立而成。

動態代理的作用:

       主要用來做方法的增強,讓你可以在不修改原始碼的情況下,增強一些方法,在方法執行前後做任何你想做的事情(甚至根本不去執行這個方法),因為在InvocationHandler的invoke這個方法中,你可以直接獲取正在呼叫方法對應的Method物件,具體應用,比如,新增日誌,做事物控制等。

 

4 Spring MVC                                    

4.1 SpringMVC介紹

是什麼?

提供了一個經典架構MVC(Model-View-Controller),使程式分層,既相互獨立,又協同工作。

View檢視層:為使用者提供UI,重點關注資料的呈現,負責佈局問題;

Model模型層:業務資料的資訊標識,關注支撐業務的資訊構成,通常是多個業務實體的組合;負責需要將什麼資訊展示給使用者。

Controller控制層:通過呼叫業務邏輯產生合適的資料Model,傳遞資料給檢視層用於呈現,負責呼叫哪些業務邏輯。

幹什麼的?

MVC的本質,及其核心思想就是業務資料抽取業務資料呈現相分離。

 

4.2 原理過程

                      

Spring MVC框架,主要利用中央控制器DispatcherServlet完成客戶端傳送的請求。

SpringMVC的工作原理:

        1、客戶端發出一個http請求給web伺服器,web伺服器對http請求進行解析,如果匹配DispatcherServlet的請求對映路徑(在web.xml中指定),web容器將請求轉交給DispatcherServlet.

        2、DipatcherServlet接收到這個請求之後將根據請求的資訊(包括URL、Http方法、請求報文頭和請求引數Cookie等)以及HandlerMapping的配置找到處理請求的處理器(Handler)。

       3-4、DispatcherServlet根據HandlerMapping找到對應的Handler,將處理權交給Handler(Handler將具體的處理進行封裝),再由具體的HandlerAdapter對Handler進行具體的呼叫。

        5、Handler對資料處理完成以後將返回一個ModelAndView()物件給DispatcherServlet,為頁面呈現做準備。

        6、Handler返回的ModelAndView()只是一個邏輯檢視並不是一個正式的檢視,DispatcherSevlet通過ViewResolver將邏輯檢視轉化為真正的檢視View。

        7、Dispatcher通過model解析出ModelAndView()中的引數進行解析最終展現出完整的view並返回給客戶端。

4.3 寫 MVC類

寫一個Spring MVC框架的Controller類:

@Controller
@RequestMapping ( "/test" )
public class MyController {
@Autowaired
private DAO dao; 
@RequestMapping ( "/showView" )
public ModelAndView showView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName( "viewName" );
modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對應的屬性值,它是一個物件 " );
return modelAndView;
}
@RequestMapping ( "/func" )
public void func(@RequestParam(value="id")  int id) {
//operation……
}
}

    有幾個地方需要注意:@Controller   @Autowaired    @RequestMapping ( “/showView” )    @RequestParam  等這些註解、路徑格式、路參繫結等都需要寫出來。

   有的面試官會讓寫現場擼程式碼,不過他們會讓你寫經典常用的程式碼,比如寫一個Servlet,寫一個Controller,寫一個Singleton單例,筆者就曾經遇到了類似的題目。

4.4 Struts2框架

         Struts2框架是一個輕量級的MVC流程框架,輕量級是指程式的程式碼不是很多,執行的時候佔用的資源不是很多,MVC流程框架就是說它支援分層開發,控制資料的流程。

升級的改善:

Struts1的缺點:

1.struts框架基於servlet進行開發的,所以servlet的問題在這個框中都能體現出來

2.struts框架的流程是固定的,想要擴充套件業務流程非常的不方便。

3.只支援動態檢視JSP展現資料,對於現在的SEO(搜尋引擎優化)支援不好

Struts2框架改善的地方:

1.核心基於Filter

2.流程可以動態擴充套件

3.多例建立物件

4.支援多種檢視展現技術(JSP,Freemarker,Volicity)

4.6 Struts2和SpringMVC的區別

1. 機制:spring mvc的入口是servlet,而struts2是filter,這樣就導致了二者的機制不同。

2. 效能

      spring會稍微比struts快。spring mvc是基於方法的設計,而sturts是基於類,每次發一次請求都會例項一個action,每個action都會被注入屬性,而spring基於方法,粒度更細,但要小心把握像在servlet控制資料一樣。spring3mvc是方法級別的攔截,攔截到方法後根據引數上的註解,把request資料注入進去,在spring3 mvc中,一個方法對應一個request上下文。而struts2框架是類級別的攔截,每次來了請求就建立一個Action,然後呼叫setter
getter方法把request中的資料注入;struts2實際上是通 setter getter方法與request打交道的;struts2中,一個Action物件對應一個request上下文。 

3. 引數傳遞:struts是在接受引數的時候,可以用屬性來接受引數,這就說明引數是讓多個方法共享的。

4. 設計思想上:struts更加符合oop(物件導向程式設計)的程式設計思想, spring就比較謹慎,在servlet上擴充套件。  

5. intercepter的實現機制

        struts有自己的interceptor機制,spring mvc用的是獨立的AOP方式。這樣導致struts的配置檔案量還是比spring mvc大,雖然struts的配置能繼承,所以我覺得論使用上來講,spring mvc使用更加簡潔,開發效率SpringMVC確實比struts2高。spring mvc是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從架構本身上spring3 mvc就容易實現restful url。struts2是類級別的攔截,一個類對應一個request上下文;實現restful
url要費勁,因為struts2action的一個方法可以對應一個url;而其類屬性卻被所有方法共享,這也就無法用註解或其他方式標識其所屬方法了。spring3 mvc的方法之間基本上獨立的,獨享requestresponse資料,請求資料通過引數獲取,處理結果通過ModelMap交回給框架方法之間不共享變數,而struts2搞的就比較亂,雖然方法之間也是獨立的,但其所有Action變數是共享的,這不會影響程式執行,卻給我們編碼,讀程式時帶來麻煩。 

        另外,spring3 mvc的驗證也是一個亮點,支援JSR303,處理ajax的請求更是方便,只需一個註解@ResponseBody,然後直接返回響應文字即可。

5 Mybatis

5.1 Mybatis簡介

是什麼,幹什麼用的?

         mybatis是一個優秀的基於java的持久層框架,它內部封裝了jdbc,使開發者只需關注sql本身,而不需要花費精力去處理載入驅動、建立連線、建立statement等繁雜的過程。

        mybatis通過xml註解的方式將要執行的各種statement配置起來,並通過java物件和statement中sql的動態引數進行對映生成最終執行的sql語句,最後由mybatis框架執行sql並將結果對映為java物件並返回,消除了幾乎所有的JDBC程式碼引數的手工設定結果集的檢索

        主要用來通過XML配置或註解提供一種Java Bean和資料庫記錄的ORM對映。

什麼是hibernate?

       hibernate是資料訪問層的框架,對jdbc進行了封裝,可以直接訪問物件,hibernate自動將此訪問轉換為sql執行,從而達到間接訪問資料庫的目的,簡化了資料訪問層的程式碼開發。

hibernate和mybatis對比:

      共性:採用ORM思想解決了實體和資料庫對映的問題,對jdbc進行了封裝,遮蔽了jdbc api底層訪問細節,使我們不用與jdbc api打交道,就可以完成對資料庫的持久化操作。

    Hibernate是全自動化ORM的對映工具,Mybatis實現業務程式碼和SQL的分離採用了面向介面程式設計的技術,是一種半自動化的對映工具,介面中定義的方法(方法返回型別,方法名,方法引數)對應了配置檔案dao.xml中對應的SQL執行返回型別、SQL配置名稱、傳輸引數。

 

5.2 設計思想、實現原理?

5.3優缺點?

1.sql語句與程式碼分離,存放於Dao.xml配置檔案中;

優點:便於維護管理,不用在java程式碼中找這些語句;

缺點: JDBC方式可以用用打斷點的方式除錯,但是Mybatis不能,需要通過log4j日誌輸出日誌資訊幫助除錯,然後在配置檔案中修改。

2.用邏輯標籤控制動態SQL的拼接

優點:用標籤代替編寫邏輯程式碼;

缺點:拼接複雜SQL語句時沒有程式碼靈活,拼寫比較複雜。不要使用變通手段來應對這種複雜的語句。

3.查詢的結果集與java物件自動對映

優點:保證名稱相同,配置好對映關係即可自動對映或者,不配置對映關係,通過配置列名=欄位名也可完成自動對映。

缺點:對開發人員所寫的SQL依賴很強。 

4.編寫原聲SQL

優點:接近JDBC,比較靈活。

缺點:對SQL語句依賴程度很高;並且屬於半自動,資料庫移植比較麻煩,比如mysql資料庫程式設計Oracle資料庫,部分的sql語句需要調整。

5.4 Mybatis和Hibernate比較

兩者相同點

       Hibernate與MyBatis都可以是通過SessionFactoryBuider由XML配置檔案生成SessionFactory,然後由SessionFactory 生成Session,最後由Session來開啟執行事務和SQL語句。其中SessionFactoryBuider,SessionFactory,Session的生命週期都是差不多的。

       Hibernate和MyBatis都支援JDBC和JTA事務處理。

Mybatis優勢

      MyBatis可以進行更為細緻的SQL優化,可以減少查詢欄位。

      MyBatis容易掌握,而Hibernate門檻較高。

Hibernate優勢

      Hibernate的DAO層開發比MyBatis簡單,Mybatis需要維護SQL和結果對映。

      Hibernate對物件的維護和快取要比MyBatis好,對增刪改查的物件的維護要方便。

      Hibernate資料庫移植性很好,MyBatis的資料庫移植性不好,不同的資料庫需要寫不同SQL。

      Hibernate有更好的二級快取機制,可以使用第三方快取。MyBatis本身提供的快取機制不佳。

他人總結

       Hibernate功能強大,資料庫無關性好,O/R對映能力強,如果你對Hibernate相當精通,而且對Hibernate進行了適當的封裝,那麼你的專案整個持久層程式碼會相當簡單,需要寫的程式碼很少,開發速度很快,非常爽。 

       Hibernate的缺點就是學習門檻不低,要精通門檻更高,而且怎麼設計O/R對映,在效能和物件模型之間如何權衡取得平衡,以及怎樣用好Hibernate方面需要你的經驗和能力都很強才行。 

      iBATIS入門簡單,即學即用,提供了資料庫查詢的自動物件繫結功能,而且延續了很好的SQL使用經驗,對於沒有那麼高的物件模型要求的專案來說,相當完美。 

      iBATIS的缺點就是框架還是比較簡陋,功能尚有缺失,雖然簡化了資料繫結程式碼,但是整個底層資料庫查詢實際還是要自己寫的,工作量也比較大,而且不太容易適應快速資料庫修改。