日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tomcat(11)org.apache.catalina.core.StandardWrapper源码剖析

發(fā)布時(shí)間:2023/12/3 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tomcat(11)org.apache.catalina.core.StandardWrapper源码剖析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
【0】README 0.0)本文部分文字描述轉(zhuǎn)自 “how tomcat works”,旨在學(xué)習(xí)?“tomcat(11)StandardWrapper源碼剖析” 的基礎(chǔ)知識; 0.1)StandardWrapper 是 Catalina中對Wrapper接口的標(biāo)準(zhǔn)實(shí)現(xiàn);要知道,tomcat 中有4種類型的容器:Engine,Host,Context 和 Wrapper;(干貨——review ?tomcat 中有4種類型的容器:Engine,Host,Context 和 Wrapper
【1】方法調(diào)用序列 1)對于每個(gè)引入的http 請求,連接器都會調(diào)用與其關(guān)聯(lián)的servlet容器的 invoke() 方法。然后,servlet容器會調(diào)用其所有子容器的invoke() 方法; 2)下圖展示了連接器接收到http 請求后的方法調(diào)用的協(xié)作圖;
3)上圖的具體steps 如下: step1)連接器創(chuàng)建 request 和 response對象; step2)連接器調(diào)用StandardContext.invoke()方法; step3)StandardContext.invoke()方法調(diào)用其管道的invoke() 方法。StandardContext的管道對象的基礎(chǔ)閥是 StandardCoantextValve類的實(shí)例,因此, StandardContext 的管道會調(diào)用 StandardContextValve.invoke()方法; step4)StandardContextValve.invoke()方法 獲取相應(yīng)的Wrapper 實(shí)例處理 http請求,調(diào)用Wrapper實(shí)例的invoke()方法; step5)StandardWrapper類是Wrapper接口的標(biāo)準(zhǔn)實(shí)現(xiàn),StandardWrapper.invoke()方法 會調(diào)用其管道對象的invoke()方法; step6)StandardWrapper的管道對象中的基礎(chǔ)閥是 StandardWrapperValve 類的實(shí)例,因此,會調(diào)用StandardWrapperValve.invoke()方法,StandardWrapperValve.invoke()方法會調(diào)用Wrapper實(shí)例的 allocate() 方法獲取servlet實(shí)例; step7)allocate()方法調(diào)用load() 方法載入相應(yīng)的servlet類,若已經(jīng)載入,則無需重復(fù)載入; step8)load()方法調(diào)用servlet實(shí)例的init()方法; step9)StandardWrapperValve調(diào)用servlet.service()方法; // Call the filter chain for this request// NOTE: This also calls the servlet's service() methodtry { // org.apache.catalina.core.StandardWrapperValve.invoke()String jspFile = wrapper.getJspFile();if (jspFile != null)sreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile);elsesreq.removeAttribute(Globals.JSP_FILE_ATTR);if ((servlet != null) && (filterChain != null)) {filterChain.doFilter(sreq, sres); // highlight line. doFilter() calls servlet.service()}sreq.removeAttribute(Globals.JSP_FILE_ATTR);} Attention)StandardContext類的構(gòu)造函數(shù)會設(shè)置StandardContextValve類的一個(gè)實(shí)例作為其基礎(chǔ)閥;? public StandardContext() { // org.apache.catalina.core.StardardContextsuper();pipeline.setBasic(new StandardContextValve());namingResources.setContainer(this); } Attention)StandardWrapper類的構(gòu)造函數(shù)也會設(shè)置一個(gè) StandardWrapperValve實(shí)例作為其基礎(chǔ)閥: public StandardWrapper() { // org.apache.catalina.core.StardardWrappersuper();swValve=new StandardWrapperValve();pipeline.setBasic(swValve); } 4)依據(jù)上述(3)小節(jié)中的 “處理http 請求的方法調(diào)用協(xié)作圖”,本文按照慣例給出了具體的調(diào)用過程,如下:
4.1)本文第一張是借用了 “tomcat(10)安全性中章節(jié)【6.4】中Supplement-補(bǔ)充模塊”的第2張圖;(for spec info,please visit tomcat(10)安全性),這旨在說明從HttpConnector -> StandardContext.invoke() -> StandardPipeline.invoke()的調(diào)用過程;
4.2)本文接著上面的調(diào)用過程繼續(xù)分析,調(diào)用過程如下圖;旨在說明? StandardPipeline.invoke() -> StandardContextValve.invoke() -> StandardWrapper.invoke() -> StandardPipeline.invoke() -> StandardWrapperValve.invoke() -> ApplicationFilterChain().doFilter()? ->?ApplicationFilterChain().internalDoFilter() -> HttpServlet(ModernServlet).service() -> ModernServlet->doGet() 的調(diào)用過程.(Bingo)

對上述協(xié)作圖和詳細(xì)調(diào)用過程圖的分析(Analysis): A0)要知道Tomcat中有4種容器:Engine,Host,Context 和 Wrapper;(干貨——本文一直強(qiáng)調(diào)這一點(diǎn),理解容器的層次結(jié)構(gòu)對于理解tomcat非常重要) A1)StandardContext 和 StandardWrapper 都是容器:他們都繼承自 ContainerBase,只不過StandardWrapper是StandardContext的子容器,而StandardWrapper是最小的容器,即它沒有子容器; A2)下面分別看StandardWrapper,StandardContext的構(gòu)造函數(shù)?和 ContainerBase 的變量定義; public final class StandardWrapper extends ContainerBase implements ServletConfig, Wrapper {public StandardWrapper() {super();swValve=new StandardWrapperValve();pipeline.setBasic(swValve);} } public class StandardContext extends ContainerBase implements Context {public StandardContext() { super();pipeline.setBasic(new StandardContextValve());namingResources.setContainer(this);} } public abstract class ContainerBase implements Container, Lifecycle, Pipeline {protected Pipeline pipeline = new StandardPipeline(this); // highlight line.protected HashMap children = new HashMap();protected int debug = 0; protected LifecycleSupport lifecycle = new LifecycleSupport(this); protected ArrayList listeners = new ArrayList(); protected Loader loader = null; protected Logger logger = null; protected Manager manager = null; protected Cluster cluster = null; protected Mapper mapper = null; protected HashMap mappers = new HashMap(); protected String mapperClass = null; protected String name = null; protected Container parent = null; protected ClassLoader parentClassLoader = null; protected Pipeline pipeline = new StandardPipeline(this); protected Realm realm = null; protected DirContext resources = null; protected static StringManager sm = StringManager.getManager(Constants.Package); protected boolean started = false; protected PropertyChangeSupport support = new PropertyChangeSupport(this); } A3)可以看到 父容器ContainerBase定義了管道StandardPipeline,而子容器StandardContext 設(shè)置StandardContextValve為基礎(chǔ)閥;而最小的容器StandardWrapper設(shè)置StandardWrapperValve為基礎(chǔ)閥; A4)也即 StandardContext 和?StandardWrapper 共用同一個(gè)管道,分別設(shè)置不同的基礎(chǔ)閥;(當(dāng)然,可以分別設(shè)置非基礎(chǔ)閥,非基礎(chǔ)閥在基礎(chǔ)閥被調(diào)用之前調(diào)用);
【2】SingleThreadModel(已經(jīng)被棄用了) 1)intro:servlet類可以實(shí)現(xiàn) javax.servlet.SingleThreadModel 接口,這樣的servlet類也稱為 SingleThreadModel(STM)servlet類。根據(jù)servlet規(guī)范,實(shí)現(xiàn)此接口的目的是保證 servlet實(shí)例一次只處理一個(gè)請求; Attention)若 servlet類實(shí)現(xiàn) SingleThreadModel接口,則可以保證絕不會有兩個(gè)線程同時(shí)執(zhí)行該servlet.service()方法。這一點(diǎn)由 servlet容器通過控制對單一 servlet實(shí)例的同步訪問實(shí)現(xiàn),或者維護(hù)一個(gè) servlet實(shí)例池,然后將每個(gè)新請求分派給一個(gè)空閑的servlet實(shí)例。該接口并不能防止servlet訪問共享資源造成的同步問題,例如訪問類的靜態(tài)變量或訪問servlet作用域之外的類; (干貨——有很多程序員哥哥沒有讀懂這段話,想當(dāng)然的認(rèn)為,實(shí)現(xiàn)了該接口的servlet就是線程安全的。這種想法是錯誤的,請?jiān)俣纫槐樯厦娴囊膬?nèi)容(原文作者說的,哈哈))
2)事實(shí)上,實(shí)現(xiàn)了 SingleThreadModel 接口的servlet類只能保證在同一時(shí)刻,只有一個(gè)線程在執(zhí)行該 servlet實(shí)例的service()方法。但,為了提高執(zhí)行 性能,servlet容器會創(chuàng)建多個(gè)STM servlet實(shí)例。也就是說,STM servlet.service()方法 會在多個(gè)STM?servlet實(shí)例中并發(fā)執(zhí)行。如果servlet實(shí)例需要靜態(tài)類變量或類外的某些資源的話,就有可能引起同步問題; Atttention)在servlet 2.4中,SingleThreadModel接口已經(jīng)被棄用了,因?yàn)樗鼤?servlet程序員誤以為該接口的servlet類就是多線程安全的;
【3】StandardWrapper 1)intro to?StandardWrapper:其主要任務(wù)是 載入它所代表的servlet類,并進(jìn)行實(shí)例化; 2)StandardWrapper并不調(diào)用servlet的service方法,該任務(wù)由 StandardWrapperValve對象(StandardWrapper實(shí)例的管道對象中的基礎(chǔ)閥)完成; 3)StandardWrapperValve對象通過調(diào)用allocate()方法從 StandardWrapper實(shí)例中獲取servlet實(shí)例,在獲得servlet實(shí)例后,StandardWrapperValve實(shí)例就會調(diào)用servlet實(shí)例的service()方法; 【3.1】分配servlet實(shí)例? 1)分配servlet實(shí)例是由 StandardWrapper.allocate()方法來完成的(allocate方法返回請求的servelt實(shí)例); 2)allocate()方法分為兩部分(parts): p1)第一部分:?allocate()首先檢查 instance是否為null,若是, 則allocate()方法調(diào)用 loadServlet()方法載入相關(guān)的servlet類,然后 整型變量countAllocated加1,返回instance的值; p2)第二部分: p2.1)若StandardWrapper表示的servlet是一個(gè)STM servlet類,則allocate()會試圖從對象池中返回一個(gè)servlet實(shí)例。變量 instancePool 是一個(gè) java.util.Stack類型的棧,其中保存了所有的STM servlet實(shí)例: private Stack instancePool = null; p2.2)只要STM servlet實(shí)例數(shù)不超過指定的最大值,allocate()方法會返回一個(gè) STM servlet實(shí)例。整型變量maxInstances 保存了在棧中存儲的 STM servlet實(shí)例的最大值,default value = 20; private int maxInstances = 20; p2.3)而 nInstances 保存了當(dāng)前 STM servlet實(shí)例的數(shù)量(初始為0);

3)源碼如下

public Servlet allocate() throws ServletException { //org.apache.catalina.core.StandardWrapper.allocate() // part 1 begins.if (debug >= 1) log("Allocating an instance");// If we are currently unloading this servlet, throw an exceptionif (unloading)throw new ServletException(sm.getString("standardWrapper.unloading", getName()));// If not SingleThreadedModel, return the same instance every timeif (!singleThreadModel) {// Load and initialize our instance if necessaryif (instance == null) {synchronized (this) {if (instance == null) {try {instance = loadServlet();} catch (ServletException e) {throw e;} catch (Throwable e) {throw new ServletException(sm.getString("standardWrapper.allocate"), e);}}}}if (!singleThreadModel) {if (debug >= 2)log(" Returning non-STM instance");countAllocated++;return (instance);}} // part1 ends. // part2 starts.synchronized (instancePool) {while (countAllocated >= nInstances) {// Allocate a new instance if possible, or else waitif (nInstances < maxInstances) {try {instancePool.push(loadServlet());nInstances++;} catch (ServletException e) {throw e;} catch (Throwable e) {throw new ServletException(sm.getString("standardWrapper.allocate"), e);}} else {try {instancePool.wait();} catch (InterruptedException e) {;}}}if (debug >= 2)log(" Returning allocated STM instance");countAllocated++;return (Servlet) instancePool.pop();}}// part2 ends.

【3.2】載入servlet類 1)StandardWrapper類實(shí)現(xiàn)了Wrapper接口的 load() 方法,load() 方法調(diào)用loadServlet()方法載入某個(gè)servlet類,并調(diào)用其 init() 方法,此時(shí)要傳入一個(gè) javax.servlet.ServletConfig實(shí)例作為參數(shù); 2)loadServlet() 方法是如何工作的 public synchronized void load() throws ServletException { // org.apache.catalina.core.StandardWrapper.load()instance = loadServlet(); }public synchronized Servlet loadServlet() throws ServletException { // org.apache.catalina.core.StandardWrapper.loadServlet()// Nothing to do if we already have an instance or an instance poolif (!singleThreadModel && (instance != null))return instance;PrintStream out = System.out;if (swallowOutput) {SystemLogHandler.startCapture();}Servlet servlet = null;try {// If this "servlet" is really a JSP file, get the right class.// HOLD YOUR NOSE - this is a kludge that avoids having to do special// case Catalina-specific code in Jasper - it also requires that the// servlet path be replaced by the <jsp-file> element content in// order to be completely effectiveString actualClass = servletClass;if ((actualClass == null) && (jspFile != null)) {Wrapper jspWrapper = (Wrapper)((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);if (jspWrapper != null)actualClass = jspWrapper.getServletClass();}// Complain if no servlet class has been specifiedif (actualClass == null) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.notClass", getName()));} // Acquire an instance of the class loader to be usedLoader loader = getLoader();if (loader == null) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.missingLoader", getName()));} ClassLoader classLoader = loader.getClassLoader(); // Special case class loader for a container provided servletif (isContainerProvidedServlet(actualClass)) {classLoader = this.getClass().getClassLoader();log(sm.getString("standardWrapper.containerServlet", getName()));} // Load the specified servlet class from the appropriate class loaderClass classClass = null;try {if (classLoader != null) {classClass = classLoader.loadClass(actualClass);} else {classClass = Class.forName(actualClass);}} catch (ClassNotFoundException e) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass),e);}if (classClass == null) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass));} // Instantiate and initialize an instance of the servlet class itselftry {servlet = (Servlet) classClass.newInstance();} catch (ClassCastException e) {unavailable(null);// Restore the context ClassLoaderthrow new ServletException(sm.getString("standardWrapper.notServlet", actualClass), e);} catch (Throwable e) {unavailable(null);// Restore the context ClassLoaderthrow new ServletException(sm.getString("standardWrapper.instantiate", actualClass), e);} // Check if loading the servlet in this web application should be// allowedif (!isServletAllowed(servlet)) {throw new SecurityException(sm.getString("standardWrapper.privilegedServlet",actualClass));} // Special handling for ContainerServlet instancesif ((servlet instanceof ContainerServlet) &&isContainerProvidedServlet(actualClass)) {((ContainerServlet) servlet).setWrapper(this);} // Call the initialization method of this servlettry {instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,servlet);servlet.init(facade);// Invoke jspInit on JSP pagesif ((loadOnStartup >= 0) && (jspFile != null)) {// Invoking jspInitHttpRequestBase req = new HttpRequestBase();HttpResponseBase res = new HttpResponseBase();req.setServletPath(jspFile);req.setQueryString("jsp_precompile=true");servlet.service(req, res);}instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet);} catch (UnavailableException f) {instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet, f);unavailable(f);throw f;} catch (ServletException f) {instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet, f);// If the servlet wanted to be unavailable it would have// said so, so do not call unavailable(null).throw f;} catch (Throwable f) {instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet, f);// If the servlet wanted to be unavailable it would have// said so, so do not call unavailable(null).throw new ServletException(sm.getString("standardWrapper.initException", getName()), f);} // Register our newly initialized instancesingleThreadModel = servlet instanceof SingleThreadModel;if (singleThreadModel) {if (instancePool == null)instancePool = new Stack();}fireContainerEvent("load", this);} finally {if (swallowOutput) {String log = SystemLogHandler.stopCapture();if (log != null && log.length() > 0) {if (getServletContext() != null) {getServletContext().log(log);} else {out.println(log);}}}}return servlet;}
step1)檢查當(dāng)前的StandardWrapper類是否表示的是一個(gè) STM servlet類,若不是,且變量instance不為null(表示以前已經(jīng)載入過這個(gè)servlet),它就直接返回該實(shí)例; // Nothing to do if we already have an instance or an instance poolif (!singleThreadModel && (instance != null))return instance; step2)獲得 System.out 和 System.err 的輸出,便于它使用 javax.servlet.ServletConfig.log() 方法記錄日志消息: PrintStream out = System.out;if (swallowOutput) {SystemLogHandler.startCapture();} step3)定義類型為javax.servlet.Servlet 名為servlet 的變量,其表示已載入的servlet實(shí)例,會由 loadServlet()方法返回; Servlet servlet = null; step4)由于Catalina是一個(gè)JSP容器,故loadServlet()方法必須檢查請求的servlet是不是一個(gè)jsp 頁面。若是,則loadServlet() 方法需要獲取代表該jsp 頁面的實(shí)際servlet類; String actualClass = servletClass;if ((actualClass == null) && (jspFile != null)) {Wrapper jspWrapper = (Wrapper)((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);if (jspWrapper != null)actualClass = jspWrapper.getServletClass(); } // public static final String JSP_SERVLET_NAME = "jsp";<span style="font-family: SimSun; line-height: 1.5; background-color: inherit;">? ? ? ? ? ?</span> step5)如果找不到該jsp 頁面的servlet類,則會使用變量 servletClass(actualClass)的值。若沒有調(diào)用StandardWrapper.serServletClass() 方法設(shè)置servletClass的值,則會拋出異常,并停止執(zhí)行后續(xù)方法; // Complain if no servlet class has been specifiedif (actualClass == null) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.notClass", getName()));}<span style="font-family: SimSun; background-color: rgb(255, 255, 255);">? ? ? ? ? ?</span> step6)這時(shí),要載入的servlet類名已經(jīng)解析完了,loadServlet()方法會獲取載入器 Loader loader = getLoader();public Loader getLoader() { // org.apache.catalina.core.ContainerBase.getLoader();if (loader != null)return (loader);if (parent != null)return (parent.getLoader());return (null);} step7)若找到載入器(loader),則loadServlet()方法調(diào)用getClassLoader()方法獲取一個(gè)ClassLoader; ClassLoader classLoader = loader.getClassLoader(); step8)Catalina提供了一些用于訪問servlet容器內(nèi)部數(shù)據(jù)的專用servlet類。如果某個(gè)servlet類是這種專用的servlet,即若isContainerProvidedServlet()方法返回true,則變量 classLoader被賦值為另一種ClassLoader實(shí)例,如此一來,這個(gè)servlet實(shí)例就可以訪問Catalina的內(nèi)部數(shù)據(jù)了; // Special case class loader for a container provided servletif (isContainerProvidedServlet(actualClass)) {classLoader = this.getClass().getClassLoader();log(sm.getString("standardWrapper.containerServlet", getName()));} step9)準(zhǔn)備好類載入器和準(zhǔn)備載入的servlet類名后,loadServlet()方法就可以載入servlet類了; // Load the specified servlet class from the appropriate class loaderClass classClass = null;try {if (classLoader != null) {classClass = classLoader.loadClass(actualClass);} else {classClass = Class.forName(actualClass);}} catch (ClassNotFoundException e) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass),e);} if (classClass == null) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass));} step10)實(shí)例化該servlet ? ? ? // Instantiate and initialize an instance of the servlet class itselftry {servlet = (Servlet) classClass.newInstance();} catch (ClassCastException e) {unavailable(null);// Restore the context ClassLoaderthrow new ServletException(sm.getString("standardWrapper.notServlet", actualClass), e);} catch (Throwable e) {unavailable(null);// Restore the context ClassLoaderthrow new ServletException(sm.getString("standardWrapper.instantiate", actualClass), e);}
step11)在loadServlet()方法實(shí)例化這個(gè)servlet之前,它會調(diào)用 isServletAllowed()方法檢查該servlet 類是否允許載入:? ? ? // Check if loading the servlet in this web application should be// allowedif (!isServletAllowed(servlet)) {throw new SecurityException(sm.getString("standardWrapper.privilegedServlet",actualClass));}
step12)若通過了安全檢查,它還會繼續(xù)檢查該servlet類是否是一個(gè) ContainerServlet類型的servlet(實(shí)現(xiàn)了 org.apache.catalina.ContainerServlet接口的 servlet可以訪問Catalina的內(nèi)部功能)。若該servlet類是一個(gè) ContainerServlet,loadServlet()方法會調(diào)用 ContainerServlet.setWrapper(),傳入StandardWrapper實(shí)例;? // Special handling for ContainerServlet instancesif ((servlet instanceof ContainerServlet) &&isContainerProvidedServlet(actualClass)) {((ContainerServlet) servlet).setWrapper(this);} step13)觸發(fā)BEFORE_INIT_EVENT事件,調(diào)用servlet實(shí)例的 init()方法(init()方法傳入了javax.servlet.ServletConfig外觀對象):? // Call the initialization method of this servlettry {instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,servlet);servlet.init(facade); // highlight line. step14)若變量 loadOnStartup 大于0, 且被請求的servlet類實(shí)際上是一個(gè)jsp 頁面,則servlet實(shí)例的service()方法;? if ((loadOnStartup >= 0) && (jspFile != null)) {// Invoking jspInitHttpRequestBase req = new HttpRequestBase();HttpResponseBase res = new HttpResponseBase();req.setServletPath(jspFile);req.setQueryString("jsp_precompile=true");servlet.service(req, res); // highlight line.}instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,servlet); step15)觸發(fā)AFTER_INIT_EVENT事件 instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, step16)若StandardWrapper對象表示的servlet類是一個(gè)STM servlet,則將該servlet實(shí)例添加到servlet實(shí)例池中。因此會判斷 instancePool 是否為null,若是,則要給他賦值一個(gè)Stack 對象;? // Register our newly initialized instancesingleThreadModel = servlet instanceof SingleThreadModel;if (singleThreadModel) {if (instancePool == null)instancePool = new Stack(); // highlight line. } step17)在finally代碼塊中,loadServlet()方法停止捕獲System.out 和 System.err 對象,記錄在載入 ServletContext.log()方法的過程中產(chǎn)生的日志消息; finally {if (swallowOutput) {String log = SystemLogHandler.stopCapture();if (log != null && log.length() > 0) {if (getServletContext() != null) {getServletContext().log(log); // highlight line.} else {out.println(log);}}}} public ServletContext getServletContext() { org.apache.catalina.core.StandardWrapper.getServletContext()if (parent == null)return (null);else if (!(parent instanceof Context))return (null);elsereturn (((Context) parent).getServletContext());} step18)最后返回已載入的servlet實(shí)例; return servlet; 【3.3】ServletConfig對象 1)intro:在上述step13)中提到了 servlet.init(facade),而facade 是 javax.servlet.ServletConfig對象的一個(gè)外觀變量; 2)StandardWrapper對象是如何獲取 servletConfig 對象的?答案就在 StandardWrapper中,該類不僅實(shí)現(xiàn)了 Wrapper接口,還實(shí)現(xiàn)了 javax.servlet.ServletConfig 接口; public final class StandardWrapper extends ContainerBase implements ServletConfig, Wrapper { // org.apache.catalina.core.StandardWrapper // ...... } public interface ServletConfig { // javax.servlet.ServletConfig public String getServletName();public ServletContext getServletContext(); public String getInitParameter(String name);public Enumeration getInitParameterNames(); } 3)javax.servlet.ServletConfig 接口有4個(gè)方法:getServletContext() , getServletName(), ?getInitParameter(), ?getInitParameterNames()方法;下面對這4個(gè)方法進(jìn)行說明; method1)getServletConfig()方法: public ServletContext getServletContext() { // org.apache.catalina.core.StandardWrapper.getServletContext()if (parent == null)return (null);else if (!(parent instanceof Context))return (null);elsereturn (((Context) parent).getServletContext());}/*** Return the servlet context for which this Context is a facade.*/public ServletContext getServletContext() { // org.apache.catalina.core.StandardContext.getServletContext()if (context == null)context = new ApplicationContext(getBasePath(), this);return (context);} Attention)正如以上代碼所展示的那樣,無法單獨(dú)使用一個(gè)Wrapper實(shí)例來表示一個(gè) servlet 類的定義。Wrapper 實(shí)例必須駐留在某個(gè) Context 容器中,這樣,當(dāng)調(diào)用其父容器的getServletConfig()方法時(shí),才能返回ServletContext類的一個(gè)實(shí)例; method2)getServletName()方法:該方法返回 servlet類的名字,該方法的簽名如下: ?public String getServletName() { // org.apache.catalina.core.StandardWrapper.getServletName()return (getName());} public String getName() { // org.apache.catalina.core.ContainerBase.getName(). // 因?yàn)?public final class StandardWrapper extends ContainerBasereturn (name);} method3)getInitParameter()方法:該方法返回指定初始參數(shù)的值 public String getInitParameter(String name) { // org.apache.catalina.core.StandardWrapper.getInitParameter()return (findInitParameter(name));} public String findInitParameter(String name) { // org.apache.catalina.core.StandardWrapper.findInitParameter()synchronized (parameters) {return ((String) parameters.get(name));}} 對getInitParameter()方法的分析(Analysis): A1)在StandardWrapper類中,初始化參數(shù) parameters 存儲在一個(gè) HashMap類型中; private HashMap parameters = new HashMap(); A2)通過addInitParameter()方法,傳入?yún)?shù)的名字 和 對應(yīng)的值 來填充變量 parameters 的值: public void addInitParameter(String name, String value) { // org.apache.catalina.core.StandardWrapper.addInitParameter().synchronized (parameters) {parameters.put(name, value);}fireContainerEvent("addInitParameter", name); // highlight line.} public void fireContainerEvent(String type, Object data) {// org.apache.catalina.core.ContainerBase.fireContainerEvent().if (listeners.size() < 1)return;ContainerEvent event = new ContainerEvent(this, type, data);ContainerListener list[] = new ContainerListener[0];synchronized (listeners) {list = (ContainerListener[]) listeners.toArray(list);}for (int i = 0; i < list.length; i++)((ContainerListener) list[i]).containerEvent(event);} A3)StandardWrapper.getInitParameter()方法的實(shí)現(xiàn)如下:? public String getInitParameter(String name) {return (findInitParameter(name));} A4)findInitParameter()方法接收一個(gè)指定的初始化參數(shù)名的字符串變量,調(diào)用HashMap 變量 parameters的get()方法獲取初始化參數(shù)的值; public String findInitParameter(String name) { // org.apache.catalina.core.StandardWrapper.findInitParameter()synchronized (parameters) {return ((String) parameters.get(name)); // highlight line.}} method4)getInitParameterNames()方法: 該方法返回所有初始化參數(shù)的名字的集合,實(shí)際上是 java.util.Enumeration的實(shí)例;? public Enumeration getInitParameterNames() {synchronized (parameters) {return (new Enumerator(parameters.keySet()));}} 【3.4】servlet容器的父子關(guān)系 1)intro to StandardWrapper:Wrapper實(shí)例代表一個(gè)servlet實(shí)例,是最低級的容器,故Wrapper不能再有子容器,不應(yīng)該調(diào)用addChild()方法添加子容器,否則拋出 java.lang.IllegalStateException 異常;(干貨review——Wrapper實(shí)例代表一個(gè)servlet實(shí)例,是最低級的容器,故Wrapper不能再有子容器 2)org.apache.catalina.core.StandardWrapper.addChild()方法實(shí)現(xiàn)如下: public void addChild(Container child) {throw new IllegalStateException (sm.getString("standardWrapper.notChild"));} Attention)Wrapper容器的父容器只能是 Context 容器;若我們在設(shè)置父容器的時(shí)候,傳入了非Context容器,則拋出 java.lang.IllegalArgumentException 異常; public void setParent(Container container) { // org.apache.catalina.core.StandardWrapper.setParent().if ((container != null) && !(container instanceof Context)) throw new IllegalArgumentException(sm.getString("standardWrapper.notContext"));if (container instanceof StandardContext) {swallowOutput = ((StandardContext)container).getSwallowOutput();}super.setParent(container); // highlight line.} public void setParent(Container container) { // org.apache.catalina.core.ContainerBase.setParent().Container oldParent = this.parent;this.parent = container;support.firePropertyChange("parent", oldParent, this.parent);}

【4】 StandardWrapperFacade類?(干貨——應(yīng)用了設(shè)計(jì)模式中的外觀模式) 1)problem+solution: 1.1)problem:StandardWrapper實(shí)例會調(diào)用它所載入的servlet類的實(shí)例的init()方法。init()方法需要一個(gè)javax.servlet.ServletConfig 實(shí)例,而StandardWrapper了本身也實(shí)現(xiàn)了 javax.servlet.ServletConfig 接口,所以,理論上 StandardWrapper需要將其中大部分公共方法對servlet程序員隱藏起來; 1.2)solution:為了實(shí)現(xiàn)這個(gè)目的,StandardWrapper類將自身實(shí)例包裝成 StandardWrapperFacade類的一個(gè)實(shí)例;
2)StandardWrapper類創(chuàng)建StandardWrapperFacade對象,并將自身作為參數(shù)傳入StandardWrapperFacade的構(gòu)造器; private StandardWrapperFacade facade = new StandardWrapperFacade(this); // defined in StandardWrapper.java 3)StandardWrapperFacade的構(gòu)造函數(shù); public StandardWrapperFacade(StandardWrapper config) {super();this.config = (ServletConfig) config; // private ServletConfig config = null;} 4)因此當(dāng)創(chuàng)建StandardWrapper對象調(diào)用servlet實(shí)例的 init()方法時(shí),它會傳入StandardWrapperFacade類的一個(gè)實(shí)例。這樣,在servlet實(shí)例內(nèi)調(diào)用 ServletConfig.getServletName(),ServletConfig.getInitParameter(), getInitParameterNames() ,getServletContext()方法會直接傳遞給 StandardWrapper類的相應(yīng)方法; 5)org.apache.catalina.core.StandardWrapperFacade 的定義如下: public final class StandardWrapperFacade implements ServletConfig {public StandardWrapperFacade(StandardWrapper config) {super();this.config = (ServletConfig) config;}public String getServletName() {return config.getServletName();}public ServletContext getServletContext() {ServletContext theContext = config.getServletContext();if ((theContext != null) &&(theContext instanceof ApplicationContext))theContext = ((ApplicationContext) theContext).getFacade();return (theContext);}public String getInitParameter(String name) {return config.getInitParameter(name);}public Enumeration getInitParameterNames() {return config.getInitParameterNames();} }

【5】StandardWrapperValve類 1)StandardWrapperValve類是 StandardWrapper實(shí)例中的基礎(chǔ)閥,要完成兩個(gè)操作(Operations): public StandardWrapper() { // StandardWrapper的構(gòu)造函數(shù);super();swValve=new StandardWrapperValve();pipeline.setBasic(swValve);} O1)執(zhí)行與該servlet實(shí)例關(guān)聯(lián)的全部過濾器;(干貨——這里引入了過濾器) O2)調(diào)用servlet實(shí)例的service()方法; 2)完成上述任務(wù)后,在 StandardWrapperValve.invoke()方法實(shí)現(xiàn)中會執(zhí)行以下操作(Operations): O1)調(diào)用StandardWrapper.allocate()方法獲取該StandardWrapper實(shí)例所表示的 servlet實(shí)例; public void invoke(Request request, Response response,ValveContext valveContext)throws IOException, ServletException {long t1=System.currentTimeMillis();requestCount++;// Initialize local variables we may needboolean unavailable = false;Throwable throwable = null;StandardWrapper wrapper = (StandardWrapper) getContainer();ServletRequest sreq = request.getRequest();ServletResponse sres = response.getResponse();Servlet servlet = null;HttpServletRequest hreq = null;if (sreq instanceof HttpServletRequest)hreq = (HttpServletRequest) sreq;HttpServletResponse hres = null;if (sres instanceof HttpServletResponse)hres = (HttpServletResponse) sres;// Check for the application being marked unavailableif (!((Context) wrapper.getParent()).getAvailable()) {hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,sm.getString("standardContext.isUnavailable"));unavailable = true;}// Check for the servlet being marked unavailableif (!unavailable && wrapper.isUnavailable()) {log(sm.getString("standardWrapper.isUnavailable",wrapper.getName()));if (hres == null) {; // NOTE - Not much we can do generically} else {long available = wrapper.getAvailable();if ((available > 0L) && (available < Long.MAX_VALUE))hres.setDateHeader("Retry-After", available);hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,sm.getString("standardWrapper.isUnavailable",wrapper.getName()));}unavailable = true;}// Allocate a servlet instance to process this requesttry {if (!unavailable) {servlet = wrapper.allocate(); // highlight line.} // ...... O2)調(diào)用私有方法 createFilterChain(),創(chuàng)建過濾器鏈; // Create the filter chain for this request ApplicationFilterChain filterChain = createFilterChain(request, servlet); // for create FilterChain方法,本章節(jié)末尾; private ApplicationFilterChain createFilterChain(Request request, Servlet servlet) { if (servlet == null)return (null);ApplicationFilterChain filterChain = new ApplicationFilterChain(); filterChain.setServlet(servlet);StandardWrapper wrapper = (StandardWrapper) getContainer();filterChain.setSupport(wrapper.getInstanceSupport());// Acquire the filter mappings for this ContextStandardContext context = (StandardContext) wrapper.getParent();FilterMap filterMaps[] = context.findFilterMaps();// If there are no filter mappings, we are doneif ((filterMaps == null) || (filterMaps.length == 0))return (filterChain);// Acquire the information we will need to match filter mappingsString requestPath = null;if (request instanceof HttpRequest) {HttpServletRequest hreq =(HttpServletRequest) request.getRequest();String contextPath = hreq.getContextPath();if (contextPath == null)contextPath = "";String requestURI = ((HttpRequest) request).getDecodedRequestURI();if (requestURI.length() >= contextPath.length())requestPath = requestURI.substring(contextPath.length());}String servletName = wrapper.getName();int n = 0;// Add the relevant path-mapped filters to this filter chainfor (int i = 0; i < filterMaps.length; i++) {if (!matchFiltersURL(filterMaps[i], requestPath))continue;ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName());if (filterConfig == null) {continue;}filterChain.addFilter(filterConfig);n++;}// Add filters that match on servlet name secondfor (int i = 0; i < filterMaps.length; i++) {if (!matchFiltersServlet(filterMaps[i], servletName))continue;ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName());if (filterConfig == null) {continue;}filterChain.addFilter(filterConfig);n++;}return (filterChain);} O3)調(diào)用過濾器鏈的 doFilter()方法,其中包括調(diào)用servlet實(shí)例的service()方法; try {String jspFile = wrapper.getJspFile();if (jspFile != null)sreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile);elsesreq.removeAttribute(Globals.JSP_FILE_ATTR);if ((servlet != null) && (filterChain != null)) {filterChain.doFilter(sreq, sres); // hightlight line.}sreq.removeAttribute(Globals.JSP_FILE_ATTR); // ......public void doFilter(ServletRequest request, ServletResponse response) //org.apache.catlina.core.ApplicationFilterChain.doFileter()throws IOException, ServletException {if( System.getSecurityManager() != null ) {final ServletRequest req = request;final ServletResponse res = response;try {java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction(){public Object run() throws ServletException, IOException {internalDoFilter(req,res); // highlight line. internalDoFilter() 參見文末.return null;}});} catch( PrivilegedActionException pe) {Exception e = pe.getException();if (e instanceof ServletException)throw (ServletException) e;else if (e instanceof IOException)throw (IOException) e;else if (e instanceof RuntimeException)throw (RuntimeException) e;elsethrow new ServletException(e.getMessage(), e);}} else {internalDoFilter(request,response);}} private void internalDoFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException { //org.apache.catalina.core.ApplicationFilterChain.internalDoFilter().// Construct an iterator the first time this method is calledif (this.iterator == null)this.iterator = filters.iterator();// Call the next filter if there is oneif (this.iterator.hasNext()) {ApplicationFilterConfig filterConfig =(ApplicationFilterConfig) iterator.next();Filter filter = null;try {filter = filterConfig.getFilter();support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,filter, request, response);filter.doFilter(request, response, this);support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,filter, request, response);} //......return;}// We fell off the end of the chain -- call the servlet instancetry {support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,servlet, request, response);if ((request instanceof HttpServletRequest) &&(response instanceof HttpServletResponse)) { servlet.service((HttpServletRequest) request, (HttpServletResponse) response); // 這不就是你夢寐以求的service()方法嗎?哈哈。} else {servlet.service(request, response); // and this highlight line.}support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,servlet, request, response);} //......} O4)釋放過濾器鏈; try {if (filterChain != null)filterChain.release(); // highlight line.} catch (Throwable e) {log(sm.getString("standardWrapper.releaseFilters",wrapper.getName()), e);if (throwable == null) {throwable = e;exception(request, response, e);}} void release() { //org.apache.catalina.core.ApplicationFilterChain.release()this.filters.clear();this.iterator = iterator;this.servlet = null;} O5)調(diào)用Wrapper實(shí)例的 deallocate()方法; // Deallocate the allocated servlet instancetry {if (servlet != null) {wrapper.deallocate(servlet); // highlight line.}} catch (Throwable e) {log(sm.getString("standardWrapper.deallocateException",wrapper.getName()), e);if (throwable == null) {throwable = e;exception(request, response, e);}}public void deallocate(Servlet servlet) throws ServletException { //org.apache.catalina.core.StandardWrapper.deallocate()// If not SingleThreadModel, no action is requiredif (!singleThreadModel) {countAllocated--;return;}synchronized (instancePool) {countAllocated--;instancePool.push(servlet);instancePool.notify();}} O6)若該servlet類再也不會被使用到,調(diào)用Wrapper實(shí)例的unload()方法; // If this servlet has been marked permanently unavailable,// unload it and release this instancetry {if ((servlet != null) &&(wrapper.getAvailable() == Long.MAX_VALUE)) {wrapper.unload(); // highlight line.}} // ......long t2=System.currentTimeMillis();long time=t2-t1;processingTime+=time;if( time > maxTime ) maxTime=time;} Attention)以上調(diào)用過程中,最重要的是對 createFilterChain()方法和過濾器鏈的 doFilter()方法的調(diào)用。createFilterChain()方法創(chuàng)建一個(gè) ApplicationFilterChain實(shí)例,并將所有需要應(yīng)用到該Wrapper實(shí)例所代表的servlet實(shí)例的過濾器添加到其中; private ApplicationFilterChain createFilterChain(Request request,Servlet servlet) {if (servlet == null)return (null);ApplicationFilterChain filterChain =new ApplicationFilterChain();filterChain.setServlet(servlet);StandardWrapper wrapper = (StandardWrapper) getContainer();filterChain.setSupport(wrapper.getInstanceSupport());StandardContext context = (StandardContext) wrapper.getParent();FilterMap filterMaps[] = context.findFilterMaps();if ((filterMaps == null) || (filterMaps.length == 0))return (filterChain);// Acquire the information we will need to match filter mappingsString requestPath = null;if (request instanceof HttpRequest) {HttpServletRequest hreq =(HttpServletRequest) request.getRequest();String contextPath = hreq.getContextPath();if (contextPath == null)contextPath = "";String requestURI = ((HttpRequest) request).getDecodedRequestURI();if (requestURI.length() >= contextPath.length())requestPath = requestURI.substring(contextPath.length());}String servletName = wrapper.getName();int n = 0; // Add the relevant path-mapped filters to this filter chainfor (int i = 0; i < filterMaps.length; i++) {if (!matchFiltersURL(filterMaps[i], requestPath)) continue;ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName());if (filterConfig == null) {continue; }filterChain.addFilter(filterConfig); n++;}// Add filters that match on servlet name secondfor (int i = 0; i < filterMaps.length; i++) {if (!matchFiltersServlet(filterMaps[i], servletName)) continue;ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName());if (filterConfig == null) {continue;}filterChain.addFilter(filterConfig);n++;}return (filterChain); } public synchronized void unload() throws ServletException {if (!singleThreadModel && (instance == null))return;unloading = true;if (countAllocated > 0) {int nRetries = 0;while (nRetries < 10) {if (nRetries == 0) {log("Waiting for " + countAllocated +" instance(s) to be deallocated");}try {Thread.sleep(50);} catch (InterruptedException e) {;}nRetries++;}}ClassLoader oldCtxClassLoader =Thread.currentThread().getContextClassLoader();ClassLoader classLoader = instance.getClass().getClassLoader();PrintStream out = System.out;if (swallowOutput) {SystemLogHandler.startCapture();}try {instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_DESTROY_EVENT, instance);Thread.currentThread().setContextClassLoader(classLoader);instance.destroy();instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_DESTROY_EVENT, instance);} catch (Throwable t) {instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_DESTROY_EVENT, instance, t);instance = null;instancePool = null;nInstances = 0;fireContainerEvent("unload", this);unloading = false;throw new ServletException(sm.getString("standardWrapper.destroyException", getName()),t);} finally {Thread.currentThread().setContextClassLoader(oldCtxClassLoader);if (swallowOutput) {String log = SystemLogHandler.stopCapture();if (log != null && log.length() > 0) {if (getServletContext() != null) {getServletContext().log(log);} else {out.println(log);}}}}instance = null;if (singleThreadModel && (instancePool != null)) {try {Thread.currentThread().setContextClassLoader(classLoader);while (!instancePool.isEmpty()) {((Servlet) instancePool.pop()).destroy();}} catch (Throwable t) {instancePool = null;nInstances = 0;unloading = false;fireContainerEvent("unload", this);throw new ServletException(sm.getString("standardWrapper.destroyException",getName()), t);} finally {Thread.currentThread().setContextClassLoader(oldCtxClassLoader);}instancePool = null;nInstances = 0;}singleThreadModel = false;unloading = false;fireContainerEvent("unload", this); }
【6】 FilterDef類(org.apache.catalina.deploy.FilterDef) 1)intro:FilterDef 是一個(gè)過濾器的定義; 2)FilterDef類中的每個(gè)屬性表示在定義filter元素時(shí)聲明的子元素。其中Map 類型的變量parameters 存儲了初始化過濾器時(shí)所需要的所有參數(shù)。addInitParameter()方法用于向parameters 中添加新的 name/value 形式的參數(shù)名和對應(yīng)的值; 3)其定義源碼如下: public final class FilterDef { // org.apache.catalina.deploy.FilterDef private String description = null;public String getDescription() {return (this.description);}public void setDescription(String description) {this.description = description;} private String displayName = null;public String getDisplayName() {return (this.displayName);}public void setDisplayName(String displayName) {this.displayName = displayName;}private String filterClass = null;public String getFilterClass() {return (this.filterClass);}public void setFilterClass(String filterClass) {this.filterClass = filterClass;} private String filterName = null;public String getFilterName() {return (this.filterName);}public void setFilterName(String filterName) {this.filterName = filterName;} private String largeIcon = null;public String getLargeIcon() {return (this.largeIcon);}public void setLargeIcon(String largeIcon) {this.largeIcon = largeIcon;} private Map parameters = new HashMap();public Map getParameterMap() {return (this.parameters);}private String smallIcon = null;public String getSmallIcon() {return (this.smallIcon);}public void setSmallIcon(String smallIcon) {this.smallIcon = smallIcon;} public void addInitParameter(String name, String value) {parameters.put(name, value);}public String toString() {StringBuffer sb = new StringBuffer("FilterDef[");sb.append("filterName=");sb.append(this.filterName);sb.append(", filterClass=");sb.append(this.filterClass);sb.append("]");return (sb.toString());} }

【7】ApplicationFilterConfig類(org.apache.catalina.core.ApplicationFilterConfig-應(yīng)用過濾器配置類) 1)intro:ApplicationFilterConfig類實(shí)現(xiàn)了 javax.servlet.FilterConfig接口,該類用于管理web 應(yīng)用程序第1次啟動時(shí)創(chuàng)建的所有過濾器實(shí)例; 2)類簽名:final class ApplicationFilterConfig implements FilterConfig? 3)可以通過把一個(gè) org.apache.catalina.Context對象和 一個(gè) FilterDef對象傳遞給 ApplicationFilterConfig類的構(gòu)造函數(shù)來創(chuàng)建一個(gè) ApplicationFilterConfig對象:? public ApplicationFilterConfig(Context context, FilterDef filterDef)throws ClassCastException, ClassNotFoundException,IllegalAccessException, InstantiationException,ServletException {super();this.context = context;setFilterDef(filterDef);} 對以上代碼的分析(Analysis): A1)Context對象表示一個(gè)web 應(yīng)用程序; A2)FilterDef對象表示一個(gè)過濾器的定義; 4)ApplicationFilterConfig.getFilter()方法:會返回一個(gè) javax.servlet.Filter對象,該方法負(fù)責(zé)載入并實(shí)例化一個(gè)過濾器類;? public String getFilterName() { // org.apache.catalina.core.ApplicationFilterConfig.getFilterName().return (filterDef.getFilterName()); }
【8】ApplicationFilterChain類(org.apache.catalina.core.ApplicationFilterChain) 1)intro:?ApplicationFilterChain類實(shí)現(xiàn)了 javax.servlet.FilterChain接口,StandardWrapperValve.invoke() 方法會創(chuàng)建 ApplicationFilterChain類的一個(gè)實(shí)例,并調(diào)用其 doFilter()方法; 2)Filter接口的doFilter()方法的簽名如下: public interface Filter { // javax.servlet.Filterpublic void init(FilterConfig filterConfig) throws ServletException; public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException; public void destroy(); }3)ApplicationFilterChain.doFilter()方法會將?ApplicationFilterChain 類自身作為第3個(gè)參數(shù)傳遞給過濾器的 doFilter()方法; public void doFilter(ServletRequest request, ServletResponse response) //org.apache.catalina.ApplicationFilterChain.doFileter().throws IOException, ServletException {if( System.getSecurityManager() != null ) {final ServletRequest req = request;final ServletResponse res = response;try {java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction(){public Object run() throws ServletException, IOException {internalDoFilter(req,res);return null;}});} catch( PrivilegedActionException pe) {Exception e = pe.getException();if (e instanceof ServletException)throw (ServletException) e;else if (e instanceof IOException)throw (IOException) e;else if (e instanceof RuntimeException)throw (RuntimeException) e;elsethrow new ServletException(e.getMessage(), e);}} else {internalDoFilter(request,response);}} 4)在Filter.doFilter()方法中, 可以通過顯示地調(diào)用 FileterChain.doFilter()方法來調(diào)用另一個(gè)過濾器。
對以上代碼的分析(Analysis): A1)正如你所看到的,在doFilter()方法的最后一行會調(diào)用FilterChain.doFilter()方法; A2)如果某個(gè)過濾器時(shí)過濾器鏈中的最后一個(gè)過濾器,則會調(diào)用被請求的 servlet類的 service()方法。如果過濾器沒有調(diào)用chain.doFilter()方法,則不會調(diào)用后面的過濾器;
【9】應(yīng)用程序 0)servlet文件目錄
1)程序源代碼 public final class Bootstrap {public static void main(String[] args) {//invoke: http://localhost:8080/Modern or http://localhost:8080/PrimitiveSystem.setProperty("catalina.base", System.getProperty("user.dir"));Connector connector = new HttpConnector();Wrapper wrapper1 = new StandardWrapper();wrapper1.setName("Primitive");wrapper1.setServletClass("servlet.PrimitiveServlet"); // attention for servlet class,要與你的servlet目錄相對應(yīng);Wrapper wrapper2 = new StandardWrapper();wrapper2.setName("Modern");wrapper2.setServletClass("servlet.ModernServlet"); // attention for servlet class,要與你的servlet目錄相對應(yīng);Context context = new StandardContext();// StandardContext's start method adds a default mappercontext.setPath("/myApp");context.setDocBase("myApp");LifecycleListener listener = new SimpleContextConfig();((Lifecycle) context).addLifecycleListener(listener);context.addChild(wrapper1);context.addChild(wrapper2);// for simplicity, we don't add a valve, but you can add// valves to context or wrapper just as you did in Chapter 6Loader loader = new WebappLoader();context.setLoader(loader);// context.addServletMapping(pattern, name);context.addServletMapping("/Primitive", "Primitive");context.addServletMapping("/Modern", "Modern");// add ContextConfig. This listener is important because it configures// StandardContext (sets configured to true), otherwise StandardContext// won't startconnector.setContainer(context);try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) context).start();// make the application wait until we press a key.System.in.read();((Lifecycle) context).stop();}catch (Exception e) {e.printStackTrace();}} } 2)打印結(jié)果 E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common. jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/;lib/catalina.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com.tomca t.chapter11.startup.Bootstrap HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread WebappLoader[/myApp]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\_\myApp StandardManager[/myApp]: Seeding random number generator class java.security.SecureRandom StandardManager[/myApp]: Seeding of random number generator has been completed StandardManager[/myApp]: IOException while loading persisted sessions: java.io.EOFException // // 這是從文件中加載 session對象到內(nèi)存,由于沒有相關(guān)文件,所以加載失敗,拋出異常,但這不會影響我們訪問servlet,大家不要驚慌; java.io.EOFExceptionat java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)at java.io.ObjectInputStream.readStreamHeader(Unknown Source)at java.io.ObjectInputStream.<init>(Unknown Source)at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103)at org.apache.catalina.session.StandardManager.load(StandardManager.java:408)at org.apache.catalina.session.StandardManager.start(StandardManager.java:655)at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570)at com.tomcat.chapter11.startup.Bootstrap.main(Bootstrap.java:55) StandardManager[/myApp]: Exception loading sessions from persistent storage java.io.EOFExceptionat java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)at java.io.ObjectInputStream.readStreamHeader(Unknown Source)at java.io.ObjectInputStream.<init>(Unknown Source)at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103)at org.apache.catalina.session.StandardManager.load(StandardManager.java:408)at org.apache.catalina.session.StandardManager.start(StandardManager.java:655)at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570)at com.tomcat.chapter11.startup.Bootstrap.main(Bootstrap.java:55) ModernServlet -- init


總結(jié)

以上是生活随笔為你收集整理的tomcat(11)org.apache.catalina.core.StandardWrapper源码剖析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

黄色av一级片 | 日本在线观看中文字幕无线观看 | 国产综合在线视频 | 成片免费观看视频大全 | 999视频网 | 不卡的av在线| 伊人热 | 国产精品久久久视频 | 精品一区二区在线免费观看 | 在线观看免费高清视频大全追剧 | 国产精品久久99综合免费观看尤物 | avav片| 国产精品色 | 日韩av中文在线观看 | 国产麻豆传媒 | 狠狠色丁香 | 亚洲情影院 | 久久6精品 | 国产亚洲精品久久久久久大师 | 毛片二区 | 国产亚洲精品久久久久久电影 | 中文字幕在线视频一区二区三区 | 成人国产电影在线观看 | 国产成人av网 | 免费在线观看一区二区三区 | 99久久激情 | 91免费视频黄 | 六月丁香婷婷在线 | 国产在线精品视频 | 69久久夜色精品国产69 | 91在线视频网址 | 国产成人精品一区二区 | 日韩精品一区二区三区在线播放 | 欧美日韩亚洲在线观看 | 国产高清视频在线播放一区 | 国产精品一区二区吃奶在线观看 | 久久久精品综合 | 亚洲综合欧美日韩狠狠色 | 亚一亚二国产专区 | 成人精品一区二区三区中文字幕 | 日韩高清免费观看 | 精品久久久久久国产91 | 欧美在线观看禁18 | 亚洲欧美国产精品va在线观看 | 在线免费看片 | 91免费观看视频网站 | 在线黄av | 国产成人综合精品 | 精品国产免费一区二区三区五区 | 91视频首页 | 婷婷九月丁香 | 久久国产品 | 久久激情日本aⅴ | www久久久| 91丨九色丨国产丨porny精品 | 国产精品久久久久国产a级 激情综合中文娱乐网 | 色七七亚洲影院 | 色午夜影院 | 手机看片1042 | 美女视频黄在线 | 玖玖玖影院 | 日韩xxxx视频 | 亚洲国产中文字幕 | 麻豆精品国产传媒 | 性色在线视频 | 香蕉在线观看 | 成人cosplay福利网站 | 欧美日韩国产在线精品 | 十八岁免进欧美 | 国产精品va最新国产精品视频 | 91在线看视频 | 青青草视频精品 | 一区二区三区在线免费播放 | 久热电影| 国产成人黄色av | 中文字幕一区二区在线观看 | 国产精品嫩草影院123 | 在线免费视频 你懂得 | 91成人午夜 | 69人人| 色综合天天视频在线观看 | 人人澡人人爱 | 黄色一级在线视频 | 97狠狠干| 中文字幕国语官网在线视频 | 丁香婷婷在线观看 | 99视频免费看 | 天天爽天天爽夜夜爽 | www.久久91 | 中文字幕在线播放视频 | 99国产免费网址 | 四虎影视成人 | 欧美淫视频 | 日韩av男人的天堂 | 日韩免费大片 | 国产一区免费在线观看 | 91精品影视 | 最新av在线网站 | 999成人免费视频 | 狠狠色丁香婷婷综合久小说久 | 福利视频午夜 | 国产精品免费久久久久 | 国产精品久久久久三级 | 成年人在线观看视频免费 | 91精品国 | 99久久日韩精品免费热麻豆美女 | 玖玖视频精品 | av丝袜在线 | 中国一区二区视频 | 九九综合久久 | 日韩美女高潮 | 免费在线观看成人小视频 | 操久| 久久精品国产成人 | 亚洲精品国偷拍自产在线观看 | 婷婷色影院 | 午夜久久 | 国产精品久久久久久久久久 | 免费在线观看国产精品 | 亚洲激情视频在线 | av在线看网站 | 久久久91精品国产 | 九九热精品视频在线观看 | 深爱激情亚洲 | 欧洲激情综合 | 91精品国产三级a在线观看 | 免费观看91视频 | 亚洲一区在线看 | 国产日韩欧美中文 | 国产精品18久久久久久不卡孕妇 | 婷婷.com| 久久er99热精品一区二区 | 五月天综合网站 | 日日操天天射 | 97电影院网| 国产一级淫片在线观看 | 国产美女精品 | 亚洲视频免费在线观看 | 丁香亚洲 | 97超碰资源总站 | 国产尤物在线观看 | 人人爽人人香蕉 | www.天天成人国产电影 | 午夜在线免费视频 | 久久在线免费视频 | 久久少妇免费视频 | 成人a毛片 | 国产美女被啪进深处喷白浆视频 | 国产资源网 | 久久任你操 | 亚洲国产69 | 91成人免费看 | 欧美一级片在线免费观看 | 最近中文字幕国语免费av | 天天色天天射天天综合网 | 天天操天天干天天操天天干 | 91精品久久久久久久久久入口 | 亚洲狠狠婷婷综合久久久 | 在线观看色视频 | 特级免费毛片 | 97视频一区 | 91人人爽人人爽人人精88v | 久久精品系列 | 亚洲一二三区精品 | 最近乱久中文字幕 | 91黄色成人| 国产一区二区免费 | 久久亚洲综合国产精品99麻豆的功能介绍 | 中文字幕二区在线观看 | 精品国产一区二区三区男人吃奶 | 毛片基地黄久久久久久天堂 | 天天干人人插 | 在线成人国产 | 久久综合久久八八 | 亚洲欧美日韩在线一区二区 | 91在线一区二区 | 欧美福利视频 | 久久成人高清 | 欧美激情视频一区二区三区免费 | 国产精品一区二区三区在线播放 | 亚洲精品一区中文字幕乱码 | 婷婷激情av| 69av视频在线观看 | 国产不卡免费视频 | 91亚·色 | 免费在线观看不卡av | 国产精品精| 欧美一级久久久 | 国产福利一区二区三区在线观看 | 五月婷婷六月综合 | 亚洲欧美视频网站 | 久久久久久久久国产 | 911国产| 国产不卡在线播放 | 九九九免费视频 | 五月天亚洲综合小说网 | 天天综合狠狠精品 | 亚洲色图激情文学 | 国产精品免费视频一区二区 | 九九免费观看全部免费视频 | 天天夜操 | 91精品一区二区在线观看 | 国产精品99久久久精品免费观看 | 蜜桃av久久久亚洲精品 | 欧美成人高清 | av久久在线| 国产精品免费观看久久 | 久久都是精品 | 日韩精品在线一区 | 久久免费美女视频 | 成人三级网站在线观看 | 国产露脸91国语对白 | 五月婷婷丁香在线观看 | 91精品国产欧美一区二区成人 | 色天天久久 | 91插插插网站 | 国产亚洲精品久久久久秋 | 天天干天天干天天干天天干天天干天天干 | 中文字幕资源网 | 国产日韩欧美在线一区 | 天天操天天色天天射 | 欧美日韩不卡在线观看 | 国产精品s色 | 国产九九热 | 国产视频精选在线 | 免费av大全| 久久久污 | av丝袜在线 | 国产一二区视频 | 国产精品久久久久久久久久久久 | 久久视频中文字幕 | 正在播放国产一区二区 | 日韩精品中文字幕一区二区 | 天天干天天搞天天射 | 在线成人免费电影 | 亚洲精品在线免费播放 | 国内99视频 | 日韩天天综合 | 九九免费精品视频 | 91在线视频| 五月天网站在线 | 久久久久久久久久久影院 | 国产成人精品一区二区三区免费 | 婷婷国产在线观看 | 久久国产精品久久精品国产演员表 | 天堂av在线7 | 色噜噜在线观看视频 | 天天插日日操 | 狠狠躁天天躁综合网 | 中文字幕亚洲欧美日韩2019 | 蜜臀av性久久久久蜜臀aⅴ流畅 | 色成人亚洲 | 天天射综合 | 国产精品11 | 99视频偷窥在线精品国自产拍 | 亚洲aⅴ久久精品 | 色妞色视频一区二区三区四区 | 久久久污 | 日本久久91 | 在线激情小视频 | 欧美色图88 | 国产精品一区在线 | 99热999| 黄在线 | av噜噜噜在线播放 | 人人爽人人爽人人片 | 91高清视频在线 | 亚洲精品美女久久17c | 中文字幕a在线 | 成人免费在线视频 | 天天干夜夜夜操天 | 亚洲国产日韩精品 | 久久久资源网 | 国产精品剧情在线亚洲 | 国产在线播放一区二区 | 精品在线视频一区 | 超级碰碰碰免费视频 | 天天躁日日 | 久久艹欧美 | 日韩久久精品一区二区三区 | www.日日日.com| 国产精品自产拍在线观看蜜 | 久久免费激情视频 | 日韩在线视频网址 | 丰满少妇在线观看 | 久久伊99综合婷婷久久伊 | 日韩视频一区二区三区 | 91精品国产自产在线观看 | 欧美人操人 | av片一区二区 | 久热精品国产 | 午夜私人影院 | 国产精品国产三级国产aⅴ入口 | 国产午夜在线观看 | 99激情网 | 国产黄色看片 | 99久久精品无免国产免费 | 久色网| 免费视频一区 | 国产一区二区三区免费观看视频 | 日韩在线免费视频 | 国产裸体无遮挡 | 久久第四色 | 99精品视频观看 | 天天综合91 | 久草在线费播放视频 | 午夜精品影院 | 手机看国产毛片 | 亚洲伦理一区二区 | 91系列在线观看 | 91久久丝袜国产露脸动漫 | 成年人视频在线观看免费 | 在线看日韩 | 99r在线播放 | 欧美色黄 | 国产精品久久久久久久久久免费 | 亚洲一区二区三区在线看 | 国产又粗又硬又长又爽的视频 | 欧美日韩免费观看一区二区三区 | 精品人人人人 | 中文字幕视频一区二区 | 国产精品永久久久久久久www | 黄色av电影| 国产黄色在线网站 | 久久激情视频 久久 | 国产尤物一区二区三区 | 成人av影视在线 | 99久久精品国产一区二区成人 | 欧美一级片免费在线观看 | 色综合天天干 | 人人澡人人添人人爽一区二区 | 色婷婷欧美 | 99中文字幕视频 | 手机看国产毛片 | 久久精品欧美一区二区三区麻豆 | 综合色中文 | 91在线一区二区 | 亚洲精品一区二区三区新线路 | 激情五月婷婷综合网 | 亚洲精品av中文字幕在线在线 | 99国产精品| 日本精品久久久久 | 日韩精品一二三 | 亚洲精品18日本一区app | 国产精品高潮呻吟久久av无 | 爱爱一区 | 国产精彩视频一区二区 | 亚洲精品一区二区三区四区高清 | 国产色女人| 国产精品自产拍 | 探花视频在线版播放免费观看 | www.夜色.com| 在线成人小视频 | 偷拍区另类综合在线 | 日韩动漫免费观看高清完整版在线观看 | 狠狠的干 | av免费看在线 | 日韩欧美高清不卡 | 国内丰满少妇猛烈精品播放 | 91精彩视频在线观看 | 午夜影视av| 欧美日韩二区三区 | 日韩精品久久久久久中文字幕8 | www.com.日本一级 | 日本不卡123区 | 大荫蒂欧美视频另类xxxx | 成人久久视频 | 外国av网| 国产一区二区三区四区大秀 | 九九视频在线 | 91免费版在线观看 | 丁香婷婷综合激情五月色 | 国产高清网站 | 99免费在线视频 | 97人人模人人爽人人喊网 | 日韩欧美中文 | 中文字幕在线不卡国产视频 | 亚洲综合在线视频 | 国内免费的中文字幕 | 久久国产福利 | www.久久久.com | 国产99久久久国产精品免费看 | 国产视频在线免费观看 | 国内少妇自拍视频一区 | 国产成人高清 | aaawww| 久久精品人 | 欧美一区二区三区在线看 | 超碰在线观看av.com | 日韩大片免费观看 | 色综合久久中文字幕综合网 | 国内精品视频在线 | 午夜精品久久久久久久99 | 久久国产精品99久久久久久丝袜 | 999ZYZ玖玖资源站永久 | 日韩欧美高清一区二区 | 久久无码av一区二区三区电影网 | 亚洲影院色 | 免费高清国产 | 天天插天天操天天干 | 国内精品久久久久影院一蜜桃 | 黄污在线看 | 在线亚洲观看 | 97精品免费视频 | 亚洲精品三级 | 超碰在线94 | 国产呻吟在线 | 99久热在线精品视频观看 | 欧美日韩一区二区久久 | 国产福利一区二区三区视频 | 久久视频一区二区 | 福利一区二区在线 | 久久99精品国产麻豆婷婷 | 亚洲理论视频 | 安徽妇搡bbbb搡bbbb | 婷婷色伊人 | 成人av电影在线播放 | 国产精品毛片一区 | 久久99热国产 | 久久久久在线观看 | 黄色一级在线观看 | 九九色网 | 视频精品一区二区三区 | wwwwww国产| 精品视频久久 | 超碰在线97国产 | 99视频国产在线 | 在线观看成人av | 久久99网站 | 天天插天天干天天操 | 成人丁香花 | 久久美女电影 | 香蕉久久久久久av成人 | 国产黄影院色大全免费 | 欧美日韩精品在线免费观看 | 一级片视频在线 | 色婷婷精品大在线视频 | 亚洲成成品网站 | 九色精品 | 日韩中文在线视频 | 成年人视频在线免费播放 | 亚洲成av人影院 | 2019国产精品 | 国产日韩在线视频 | 久久在线视频在线 | 香蕉影视在线观看 | 日韩视频一区二区在线 | 最近高清中文字幕 | 一区二区三区精品在线视频 | 4hu视频| 成人黄色在线 | 久久亚洲精品电影 | 久久综合狠狠综合久久综合88 | 免费视频资源 | 成人毛片一区 | 久久久久久久久久久影院 | 天天操比| 日韩区在线观看 | 波多野结衣电影一区 | 午夜视频在线观看网站 | 成人黄色电影在线观看 | 欧美日韩一区二区三区在线免费观看 | 色婷婷在线观看视频 | 五月天久久婷 | 婷婷丁香狠狠爱 | 91精品推荐| 久久 在线 | 91av在 | 中文字幕一区二区三区精华液 | 天天插视频 | 天天曰天天爽 | 免费看的黄色网 | 日日日天天天 | 亚洲 欧美 91| 天天操 夜夜操 | 亚洲国产剧情av | 久草久草在线 | 国产一区二区在线免费播放 | 精品一区二区综合 | 久草9视频| 岛国一区在线 | 久草在线手机视频 | 国产精品久久久久久a | 国产精品系列在线播放 | 中国黄色一级大片 | 亚洲精品国偷自产在线91正片 | 精品一区二区三区电影 | 亚洲色视频 | 国产无限资源在线观看 | 高清av免费观看 | 中文字幕视频一区 | 91精品在线麻豆 | 欧美日韩在线观看一区二区三区 | 亚洲美女精品区人人人人 | 国产综合在线视频 | 视频二区在线视频 | 免费美女av | 国产福利一区二区三区视频 | av短片在线观看 | 久久手机视频 | 在线观看免费黄色 | 综合精品久久久 | 麻豆传媒视频在线免费观看 | 久久国产精品久久w女人spa | 九草在线观看 | 91最新地址永久入口 | 人人天天夜夜 | 91香蕉久久 | 免费色视频 | 亚洲国产日韩精品 | 一区在线电影 | 亚洲撸撸 | 亚洲国产伊人 | 在线免费中文字幕 | 激情综合亚洲精品 | 亚洲国产片 | 免费av网址大全 | 国产精品久久久久永久免费观看 | 久久永久免费 | 99久久精品免费看国产一区二区三区 | 欧美一二三视频 | 99久久99久久精品国产片 | 欧美成年人在线观看 | 美女视频是黄的免费观看 | 久久精品久久久久电影 | 黄色av三级在线 | 国产+日韩欧美 | 深爱激情综合 | 丁香婷婷亚洲 | 日韩精品一区二区三区中文字幕 | 国产91对白在线播 | 国产午夜三级一区二区三桃花影视 | 精品亚洲午夜久久久久91 | 国产99色| 免费人成在线观看网站 | 丁香六月激情 | 激情网站免费观看 | 97电影院在线观看 | 天天射天天舔天天干 | 国产视频 久久久 | 久草在线手机观看 | 亚洲夜夜网 | 国产精品久久网 | 国产在线2020 | 91网页版免费观看 | 亚洲伦理精品 | 成人av在线亚洲 | 日韩在线观看a | 中文字幕av在线播放 | 天天操夜夜操夜夜操 | 日韩激情小视频 | 久久香蕉国产精品麻豆粉嫩av | 国产精品美女久久久久久久久久久 | 在线免费视频 你懂得 | 精品成人国产 | 久久午夜色播影院免费高清 | a级片在线播放 | 在线观看成人网 | 久久精品精品电影网 | 91精品国产成人 | 久久精品这里都是精品 | 日韩特级毛片 | 豆豆色资源网xfplay | 欧美久久久一区二区三区 | 国产精品精品久久久久久 | 人人草在线视频 | 久久五月情影视 | 四虎精品成人免费网站 | 不卡的av在线播放 | 亚洲综合色激情五月 | 国产精品美女免费看 | 久久毛片网 | 97人人模人人爽人人少妇 | 亚洲国产精品999 | 国产 日韩 欧美 自拍 | 蜜臀久久99精品久久久无需会员 | 国产涩图| 国产理论在线 | 日韩成人精品在线观看 | 91九色精品 | 黄色毛片观看 | 在线观看完整版免费 | 蜜臀久久99精品久久久无需会员 | 午夜天天操 | 日精品 | av网站在线观看免费 | 中文字幕黄色网 | 久久久久国产精品一区二区 | 九九热在线视频 | 五月天亚洲激情 | 碰天天操天天 | 免费看的黄色小视频 | 永久黄网站色视频免费观看w | 在线韩国电影免费观影完整版 | 欧美日韩xx | 国产成人精品一区在线 | 一区二区视频电影在线观看 | 超碰97网站| 97成人在线观看 | 天天干天天插伊人网 | 国产中文字幕在线观看 | www.午夜 | 午夜视频免费在线观看 | 日韩一二三在线 | 特级xxxxx欧美 | 免费黄色av| 亚洲精品9 | 大片网站久久 | 成年人在线观看 | 欧美电影在线观看 | 国产精品九九视频 | 欧美男女爱爱视频 | 日韩啪视频 | 香蕉影院在线播放 | 六月丁香综合 | 综合色影院 | 99精品国产99久久久久久福利 | 99视频这里只有 | 国产精品一区二区在线播放 | 精品国内自产拍在线观看视频 | а天堂中文最新一区二区三区 | 色综合综合 | 狠狠的干狠狠的操 | 天堂激情网 | 二区三区视频 | 久久久久久久久久福利 | 在线播放日韩av | 四虎在线影视 | 中文字幕资源网 | 一本到视频在线观看 | 国产中文字幕视频在线 | 美女中文字幕 | 毛片视频电影 | 日本大片免费观看在线 | 91你懂的| 国产一级二级三级视频 | 成人中文字幕在线 | 美女亚洲精品 | 夜夜夜夜操 | 中文字幕av在线不卡 | 国产精品每日更新 | 九九热视频在线 | 日日干影院 | 欧美一级日韩三级 | 欧美综合久久久 | 成人欧美在线 | 波多野结衣电影一区二区三区 | 中文字幕乱码视频 | 青青看片 | 免费看的视频 | 国产一级免费av | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 欧美最猛性xxx| 色噜噜日韩精品欧美一区二区 | 狠狠操狠狠插 | 久久综合欧美精品亚洲一区 | 国产日产精品一区二区三区四区 | 亚洲人成免费 | 免费成人av | 国产一区在线免费观看 | 国内丰满少妇猛烈精品播放 | 日韩高清免费无专码区 | 又黄又爽又湿又无遮挡的在线视频 | 黄毛片在线观看 | 国产福利一区二区在线 | 免费福利在线播放 | 日韩精品不卡在线 | 中文字幕字幕中文 | 午夜性生活片 | 天天天色综合 | 欧美福利片在线观看 | 成人国产精品电影 | 日韩午夜在线播放 | 国产免费一区二区三区网站免费 | 精品一二 | 麻豆视频国产 | 一区二区三区精品久久久 | 中文字幕欧美日韩va免费视频 | 日韩一区二区久久 | 一区二区中文字幕在线播放 | 国产一区在线播放 | 国产精品永久免费 | 色爱成人网| 日韩一区二区三免费高清在线观看 | 色搞搞 | 日韩久久精品一区二区三区 | 国产色道 | 成人网页在线免费观看 | 国产99久久久久 | 中文字幕在线免费97 | www.色五月.com| 91av久久 | 久久久久综合精品福利啪啪 | 午夜色影院| 99久久精品国产系列 | 精品久久久久久久久久久院品网 | 五月婷色| 欧美午夜a | 91精品国产综合久久福利 | 六月天综合网 | 天天亚洲| 免费在线观看一区二区三区 | 中文字幕丝袜制服 | 免费亚洲精品视频 | 973理论片235影院9 | 午夜视频黄 | 一区二区三区污 | 96久久欧美麻豆网站 | 精品日本视频 | 久久免费视频在线 | 国产精品一区二区三区在线看 | 日韩理论电影在线观看 | 国产精品99在线播放 | 久久久久久久久久久久久久电影 | 911久久香蕉国产线看观看 | 国产999精品久久久久久 | 美女久久久久 | 91亚洲欧美激情 | 亚洲人精品午夜 | 91网站观看| 激情伊人五月天久久综合 | 久久麻豆精品 | 亚洲另类交 | 97精品国产97久久久久久久久久久久 | 亚洲精品美女免费 | 国产在线精品一区二区三区 | 日日干视频| 嫩模bbw搡bbbb搡bbbb | 欧美色伊人 | 黄色特级片 | 久久激情片 | 成年人看片网站 | 免费av网站观看 | 久久久精品视频网站 | 婷婷色视频 | 午夜精品一区二区国产 | 一区二区三区在线不卡 | 麻豆系列在线观看 | 99热最新精品 | 亚洲精品国内 | 五月婷婷六月丁香 | 91视频com | 91视频电影 | 亚洲日本一区二区在线 | 日本精品在线 | 欧美综合色在线图区 | 狠狠久久婷婷 | 色婷婷综合久久久久中文字幕1 | 三级黄色在线 | 中文字幕一区二区在线播放 | 中文字幕久久网 | 中文字幕久久网 | 欧美精品免费在线观看 | 日韩免费网站 | 美女视频永久黄网站免费观看国产 | 日韩欧美在线视频一区二区三区 | 国产精品毛片久久久久久久 | 天天操天天干天天插 | 精品国产精品国产偷麻豆 | 深爱五月激情网 | 亚洲第一av在线播放 | 欧美老女人xx | 国产一区二区三区在线 | 免费a v网站 | 久久久久国产一区二区 | 久久久久久影视 | 91麻豆精品久久久久久 | 99久久免费看 | 久久国产三级 | 国产成人精品999在线观看 | 亚洲精品免费在线播放 | 久久精品一区二区三区中文字幕 | 亚洲精品在线二区 | 国产精品9999久久久久仙踪林 | 麻豆精品国产传媒 | 亚洲在线视频免费 | 天天鲁一鲁摸一摸爽一爽 | 九九久久精品 | 99久久精品国产亚洲 | 超碰97中文 | 日日操日日插 | 国产精品久久久久久久久免费 | 97电影手机版 | 日本精品中文字幕在线观看 | 成人黄色电影在线播放 | 在线视频专区 | 国产在线色| 久久伦理电影 | 国产一级视屏 | 日韩电影在线观看中文字幕 | 成人h在线 | 国产粉嫩在线观看 | 日日天天干| 五月天婷亚洲天综合网鲁鲁鲁 | 操夜夜操| 久久精品视频网 | 久久精品美女视频 | 久久久99精品免费观看乱色 | 久久精品99久久 | 欧美午夜激情网 | 中文字幕在线视频网站 | 精品视频免费在线 | 欧美精品在线观看一区 | 天天爱av导航 | 女人18片毛片90分钟 | 高清国产午夜精品久久久久久 | 久久精品国产99国产 | www九九热 | 国产精品情侣视频 | 欧美 日韩 国产 中文字幕 | 手机看片久久 | 国产一级不卡视频 | 日韩理论片中文字幕 | 成人黄色小说在线观看 | 婷婷激情综合五月天 | 中文在线√天堂 | 国产亚洲综合在线 | 久久精品毛片基地 | 91精品久久久久久久99蜜桃 | 青春草免费在线视频 | 美女网站免费福利视频 | 99一区二区三区 | 精品在线观看国产 | 激情av综合 | 国产成人99av超碰超爽 | 国产成人99av超碰超爽 | 一区三区在线欧 | 日批视频在线 | 日韩av美女| 中国美女一级看片 | 青青河边草免费视频 | 丝袜+亚洲+另类+欧美+变态 | 欧美日韩高清在线一区 | 国产香蕉视频 | 欧美日韩在线观看不卡 | 麻豆果冻剧传媒在线播放 | 久草网视频 | 欧美日韩精品久久久 | 午夜国产福利视频 | www激情久久 | 国产精品一区二区中文字幕 | 久久狠狠亚洲综合 | 成人黄色毛片视频 | 日韩在线免费看 | 射射射av| 色综合久久99 | 9在线观看免费高清完整版在线观看明 | 久草99| 国产一区成人在线 | 国产麻豆视频在线观看 | 久久婷婷国产色一区二区三区 | 亚洲另类久久 | 一区二区三区动漫 | 日韩免费观看视频 | 丁香九月婷婷 | 久久久免费高清视频 | 日批视频 | 99视频精品 | 91亚洲网站 | 国产一级片视频 | 中文字幕日本电影 | 欧美日韩一级久久久久久免费看 | 久久久亚洲麻豆日韩精品一区三区 | 国产福利一区二区三区视频 | 日韩区欠美精品av视频 | 天天做天天看 | 国产精品视频永久免费播放 | 成人小视频在线免费观看 | 99re6热在线精品视频 | 这里有精品在线视频 | 最近日本字幕mv免费观看在线 | 久久久久久久久久久久久影院 | 五月婷婷六月丁香 | 国产在线免费观看 | 99热精品在线观看 | 最近中文字幕国语免费av | 欧美亚洲另类在线视频 | 九九视频精品免费 | 日韩欧美成 | 欧洲精品一区二区 | 天天色天天干天天色 | 日日夜夜爱 | 在线天堂亚洲 | 怡春院av| 欧美日韩精品免费观看 | 免费av片在线 | 果冻av在线 | 狠狠操导航 | 国产精品99蜜臀久久不卡二区 | 中文字幕亚洲情99在线 | 亚洲精品国偷拍自产在线观看蜜桃 | 免费黄在线观看 | 国产伦精品一区二区三区无广告 | 天天操天天操天天爽 | 亚洲伊人婷婷 | 中文字幕黄网 | 在线免费视频a | 欧美一级日韩免费不卡 | 中文字幕频道 | 欧美日一级片 | 久久久av电影 | 丁香花中文字幕 | 久草视频精品 | 久久看片网 | 久久精品一二三区 | 伊人天天狠天天添日日拍 | 在线a亚洲视频播放在线观看 | 欧美久久电影 | 久久综合精品一区 | 成人h在线播放 | 日韩欧美成人网 | 国产在线国偷精品产拍 | 日日爱夜夜爱 | 天堂在线免费视频 | 国产精品久久久久久一区二区 | 婷婷国产精品 | 国产精品一区二区在线播放 | 国产香蕉视频 | 欧美一二区在线 | 日韩精品一区二区免费 | 国产精品一区二区在线观看免费 | 精品久久久成人 | 91成人精品 | 日本三级在线观看中文字 | 国产剧情亚洲 | av黄色免费看 | 在线中文字幕电影 | 69视频网站 | 国产麻豆视频免费观看 | 日韩免费在线看 | 在线观看视频一区二区三区 | 国产精品短视频 | 中文国产在线观看 | 黄色在线看网站 | 五月综合在线观看 | 日韩亚洲国产中文字幕 | 成人 国产 在线 | 激情中文在线 | 午夜国产福利视频 | 99精品国产福利在线观看免费 | 成人av在线播放网站 | 亚洲精品午夜国产va久久成人 | 深爱综合网| 国产亚洲精品久久久久久久久久久久 | 亚洲成色777777在线观看影院 | 国产精品v欧美精品 | 国产精品久久久久永久免费看 | 久久精品a | 国产免费久久久久 | 国产在线a | 高清一区二区三区av | 亚洲精选在线观看 | 国产毛片aaa| 免费网站黄色 | 亚州精品在线视频 | 在线小视频你懂得 | 国产中文字幕视频在线观看 | 超碰成人免费电影 | 亚洲综合成人在线 | 丁香花五月| 黄色小说18 | 日韩精品中文字幕在线播放 | 国产免费a| 91视频网址入口 | 成人a级大片| 亚洲精品国产精品久久99 | 久久久久看片 | 中文字幕在线国产精品 | 国产午夜麻豆影院在线观看 | 992tv人人草 黄色国产区 | 日韩精品一区二区免费 | 国产精品久久久久久久免费 | 亚洲激情国产精品 | wwwav视频| 国产成人精品久久久久蜜臀 | 午夜狠狠操| 国产91成人| 久草在| 一级黄色网址 | 91看片成人 | 精品久久久久久久久久久院品网 | 99精品免费久久久久久日本 | 天堂av最新网址 | 日日夜夜免费精品视频 | 精品国产精品久久 | 久久久久久高潮国产精品视 | 色视频在线观看 | 欧美激情视频一二区 | 人人艹视频 | 麻豆影视在线免费观看 | 久久99精品久久久久久三级 | 国产精品丝袜久久久久久久不卡 | 正在播放久久 | 天天色天天干天天 | 久久久久久国产一区二区三区 | 亚洲婷婷丁香 | 天天操天天插 | 黄a在线观看|