wrapper是什麼
wrapper是包裝了一個應用實現Servlet類的容器的包裝類,管理了這個Servlet的實例化和,初始化,調用及銷燬。
介紹Wrapper之前我要先說明一下我要過濾掉的幾個比較重要的內容
1、SingleThreadMode
實現了這個類的Servlet,tomcat保證不會有兩個線程同時調用同一個該servlet實例,現在已經棄用,因其有誤導性,導致很多人以爲這個是線程安全的,
wrapper中涉及這一塊的我會去掉
2、Jsp
這塊的處理目前也不會在今天的文章中講解,我也會處理掉
wrapper怎麼工作
我們假設wrapper完全正常啓動,我們根據之前管道的內容,我們需要找到StandardWrapper中的基礎閥StandardWrapperValve的invoke
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// 這個變量類型是volatile,這樣子使用在併發編程中是不安全的不是原子操作,在之後的
//版本中改爲atomicLong,當然這個在這裏不重要,與我們的流程無關
requestCount++;
//獲取Wrapper容器
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = null;
//獲取父Context容器
Context context = (Context) wrapper.getParent();
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
// 獲取Servlet實例,實例化過一次之後,保存在Wrapper的instance中
servlet = wrapper.allocate();
}
}
// Acknowledge the request
try {
response.sendAcknowledgement();
}
request.setAttribute
(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
ApplicationFilterFactory.REQUEST_INTEGER);
request.setAttribute
(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB);
// Create the filter chain for this request
ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance();
// 創建過濾器
ApplicationFilterChain filterChain =
factory.createFilterChain(request, wrapper, servlet);
// Reset comet flag value after creating the filter chain
request.setComet(false);
// 調用過濾器和servlet
filterChain.doFilter
(request.getRequest(), response.getResponse()
// Release the filter chain (if any) for this request
if (filterChain != null) {
if (request.isComet()) {
// If this is a Comet request, then the same chain will be used for the
// processing of all subsequent events.
filterChain.reuse();
} else {
filterChain.release();
}
}
// 這裏其實沒有做啥
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
}
}
這個閥主要做了兩個我們需要關注的重要工作
1、 創建容器實例
2、 調用實例的service,在這裏是放在過濾器中處理的,先執行所有過濾,再調用service。
我們是否應該有個問題,Servlet的實例類並不在tomcat這個系統中,tomcat是怎麼加載的
我們首先想到的是不是反射,我們來看看tomcat是怎麼加載Servlet實現類的
public Servlet allocate() throws ServletException {
// If we are currently unloading this servlet, throw an exception
if (unloading)
throw new ServletException
(sm.getString("standardWrapper.unloading", getName()));
boolean newInstance = false;
// Load and initialize our instance if necessary
if (instance == null) {
synchronized (this) {
if (instance == null) {
try {
if (log.isDebugEnabled())
log.debug("Allocating non-STM instance");
//沒有實例化開始實例化
instance = loadServlet();
// For non-STM, increment here to prevent a race
// condition with unload. Bug 43683, test case #3
if (!singleThreadModel) {
newInstance = true;
countAllocated.incrementAndGet();
}
} catch (ServletException e) {
throw e;
} catch (Throwable e) {
throw new ServletException
(sm.getString("standardWrapper.allocate"), e);
}
}
}
}
//如果已經實例化,返回已經實例化的類
if (!newInstance) {
countAllocated.incrementAndGet();
}
return (instance);
}
}
}
public synchronized Servlet loadServlet() throws ServletException {
// Nothing to do if we already have an instance or an instance pool
if (!singleThreadModel && (instance != null))
return instance;
PrintStream out = System.out;
if (swallowOutput) {
SystemLogHandler.startCapture();
}
Servlet servlet;
try {
// 獲取容器中servletClass全限定名
String actualClass = servletClass;
// 獲取該容器的加載器,整個容器的加載器會找一篇來講解
Loader loader = getLoader();
// 獲取類加載器
ClassLoader classLoader = loader.getClassLoader();
Class classClass = null;
//加載類對象
if (classLoader != null) {
classClass = classLoader.loadClass(actualClass);
} else {
classClass = Class.forName(actualClass);
}
//實例化servlet實例
servlet = (Servlet) classClass.newInstance();
// 第一次創建servlet的時候會執行一次init,所以servlet的初始化僅執行一次
servlet.init(facade);
return servlet;
}
這塊代碼我們知道爲什麼servlet的init爲什麼只執行一次,也就是servlet的類實例化之後是保存在wrapper容器中的。
也瞭解到我們tomcat的一個Servlet類,是單例的,所以存在併發安全問題。
這裏基本上就是wrapper容器的功能了,下一篇講解的容器是context