下面接著分析Context容器,該接口最重要的方法是addWrapper()方法與creatWrapper()方法,添加具體的子容器,這里是Wrapper容器實例
這里要分析的是一個簡單的Context容器,它針對特定的客戶端請求,通過映射器找到要處理該特定請求的子容器實例(Wrapper)
具體流程是,Context容器首先調用額外的閥,最后調用基礎閥(這里是SimpleContextValve),在基礎閥里面通過映射器找到要 處理該請求的子容器Wrapper實例,然后再調用子容器Wrapper實例的各個閥(本示例的Wrapper只有基礎閥)(類似于composte模式 迭代)
下面是SimpleContext類的實現,SimpleContext實現org.apache.catalina.Context接口和org.apache.catalina.Pipeline接口
public
class
SimpleContext
implements
Context, Pipeline {
public
SimpleContext() {
pipeline.setBasic(
new
SimpleContextValve());
}
//
子容器名稱與子容器實例映射
protected
HashMap children =
new
HashMap();
protected
Loader loader =
null
;
protected
SimplePipeline pipeline =
new
SimplePipeline(
this
);
//
servlet模式與子容器名稱映射
protected
HashMap servletMappings =
new
HashMap();
//
映射器
protected
Mapper mapper =
null
;
//
映射器協議與映射器實例映射
protected
HashMap mappers =
new
HashMap();
private
Container parent =
null
;
/**
* 添加servlet模式與子容器名稱(wrapper)到HashMap servletMappings容器
*
@param
pattern
*
@param
name
*/
public
void
addServletMapping(String pattern, String name) {
synchronized
(servletMappings) {
servletMappings.put(pattern, name);
}
}
/**
* 根據servlet模式找到對應的子容器名稱(wrapper)(供映射器調用)
*
@param
pattern
*
@return
*/
public
String findServletMapping(String pattern) {
synchronized
(servletMappings) {
return
((String) servletMappings.get(pattern));
}
}
/**
* 獲取加載器
*
@return
*/
public
Loader getLoader() {
if
(loader !=
null
)
return
(loader);
if
(parent !=
null
)
return
(parent.getLoader());
return
(
null
);
}
/**
* 設置加載器
*
@param
loader
*/
public
void
setLoader(Loader loader) {
this
.loader =
loader;
}
/**
* 添加子容器實例(wrapper)名稱與子容器實例(wrapper)到HashMap children容器
*
@param
child
*/
public
void
addChild(Container child) {
child.setParent((Container)
this
);
children.put(child.getName(), child);
}
/**
* 根據名稱查找子容器實例wrapper(供映射器調用)
*
@param
name
*
@return
*/
public
Container findChild(String name) {
if
(name ==
null
)
return
(
null
);
synchronized
(children) {
//
Required by post-start changes
return
((Container) children.get(name));
}
}
/**
* 查找子容器數組
*
@return
*/
public
Container[] findChildren() {
synchronized
(children) {
Container results[]
=
new
Container[children.size()];
return
((Container[]) children.values().toArray(results));
}
}
/**
* 添加映射器實例
*
@param
mapper
*/
public
void
addMapper(Mapper mapper) {
//
this method is adopted from addMapper in ContainerBase
//
the first mapper added becomes the default mapper
mapper.setContainer((Container)
this
);
//
May throw IAE
this
.mapper =
mapper;
synchronized
(mappers) {
if
(mappers.get(mapper.getProtocol()) !=
null
)
throw
new
IllegalArgumentException("addMapper: Protocol '"
+ mapper.getProtocol() + "' is not unique"
);
mapper.setContainer((Container)
this
);
//
May throw IAE
mappers.put(mapper.getProtocol(), mapper);
if
(mappers.size() == 1
)
this
.mapper =
mapper;
else
this
.mapper =
null
;
}
}
/**
* 根據協議查找映射器實例
*
@param
protocol
*
@return
*/
public
Mapper findMapper(String protocol) {
//
the default mapper will always be returned, if any,
//
regardless the value of protocol
if
(mapper !=
null
)
return
(mapper);
else
synchronized
(mappers) {
return
((Mapper) mappers.get(protocol));
}
}
public
Mapper[] findMappers() {
return
null
;
}
/**
* 根據請求找到子容器實例wrapper (供基礎閥調用該方法)
*
@param
request
*
@param
update
*
@return
*/
public
Container map(Request request,
boolean
update) {
//
this method is taken from the map method in
//
org.apache.cataline.core.ContainerBase
//
the findMapper method always returns the default mapper, if any,
//
regardless the
//
request's protocol
Mapper mapper =
findMapper(request.getRequest().getProtocol());
if
(mapper ==
null
)
return
(
null
);
//
Use this Mapper to perform this mapping
//
具體過程 (回調該對象下面方法)
//
根據request找到處理該請求的子容器wrapper名稱 調用方法 String findServletMapping(String pattern)
//
根據上面的子容器wrapper名稱找到子容器wrapper 調用方法 Container findChild(String name)
return
(mapper.map(request, update));
}
public
void
invoke(Request request, Response response)
throws
IOException,
ServletException {
pipeline.invoke(request, response);
}
//
method implementations of Pipeline
public
Valve getBasic() {
return
pipeline.getBasic();
}
public
void
setBasic(Valve valve) {
pipeline.setBasic(valve);
}
public
synchronized
void
addValve(Valve valve) {
pipeline.addValve(valve);
}
public
Valve[] getValves() {
return
pipeline.getValves();
}
public
void
removeValve(Valve valve) {
pipeline.removeValve(valve);
}
}
下面我們來分析映射器SimpleContextMapper的實現
public
class
SimpleContextMapper
implements
Mapper {
/**
* The Container with which this Mapper is associated.
*/
private
SimpleContext context =
null
;
public
Container getContainer() {
return
(context);
}
public
void
setContainer(Container container) {
if
(!(container
instanceof
SimpleContext))
throw
new
IllegalArgumentException
(
"Illegal type of container"
);
context
=
(SimpleContext) container;
}
public
String getProtocol() {
return
null
;
}
public
void
setProtocol(String protocol) {
}
/**
* Return the child Container that should be used to process this Request,
* based upon its characteristics. If no such child Container can be
* identified, return <code>null</code> instead.
*
*
@param
request Request being processed
*
@param
update Update the Request to reflect the mapping selection?
*
*
@exception
IllegalArgumentException if the relative portion of the
* path cannot be URL decoded
*/
public
Container map(Request request,
boolean
update) {
//
Identify the context-relative URI to be mapped
String contextPath =
((HttpServletRequest) request.getRequest()).getContextPath();
String requestURI
=
((HttpRequest) request).getDecodedRequestURI();
String relativeURI
=
requestURI.substring(contextPath.length());
//
Apply the standard request URI mapping rules from the specification
Wrapper wrapper =
null
;
String servletPath
=
relativeURI;
String pathInfo
=
null
;
String name
=
context.findServletMapping(relativeURI);
if
(name !=
null
)
wrapper
=
(Wrapper) context.findChild(name);
return
(wrapper);
}
}
映射器SimpleContextMapper最重要的方法是Container map(Request request, boolean update)
即根據客戶端請求找到對應的子容器實例wrapper,里面關鍵代碼是回調context容器實例的方法(持有對SimpleContext實例的引用)
接下里分析基礎閥的關鍵代碼(管道持有對基礎閥的引用)
public
class
SimpleContextValve
implements
Valve, Contained {
protected
Container container;
public
void
invoke(Request request, Response response, ValveContext valveContext)
throws
IOException, ServletException {
//
Validate the request and response object types
if
(!(request.getRequest()
instanceof
HttpServletRequest) ||
!(response.getResponse()
instanceof
HttpServletResponse)) {
return
;
//
NOTE - Not much else we can do generically
}
//
Disallow any direct access to resources under WEB-INF or META-INF
HttpServletRequest hreq =
(HttpServletRequest) request.getRequest();
String contextPath
=
hreq.getContextPath();
String requestURI
=
((HttpRequest) request).getDecodedRequestURI();
String relativeURI
=
requestURI.substring(contextPath.length()).toUpperCase();
Context context
=
(Context) getContainer();
//
Select the Wrapper to be used for this Request
Wrapper wrapper =
null
;
try
{
wrapper
= (Wrapper) context.map(request,
true
);
}
catch
(IllegalArgumentException e) {
badRequest(requestURI, (HttpServletResponse) response.getResponse());
return
;
}
if
(wrapper ==
null
) {
notFound(requestURI, (HttpServletResponse) response.getResponse());
return
;
}
//
Ask this Wrapper to process this Request
response.setContext(context);
wrapper.invoke(request, response);
}
public
Container getContainer() {
return
container;
}
public
void
setContainer(Container container) {
this
.container =
container;
}
private
void
badRequest(String requestURI, HttpServletResponse response) {
try
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST, requestURI);
}
catch
(IllegalStateException e) {
;
}
catch
(IOException e) {
;
}
}
private
void
notFound(String requestURI, HttpServletResponse response) {
try
{
response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI);
}
catch
(IllegalStateException e) {
;
}
catch
(IOException e) {
;
}
}
}
基礎閥持有對Context容器實例(SimpleContext)的引用,在它的關鍵方法void invoke(Request request, Response response, ValveContext valveContext)里面,先調用Context容器實例的Container map(Request request, boolean update)方法獲取子容器實例wrapper,最后調用子容器實例wrapper的invoke(Request request, Response response)方法
至于管道類SimplePipeline與上文相同,此處不再描述
---------------------------------------------------------------------------?
本系列How Tomcat Works系本人原創?
轉載請注明出處 博客園 刺猬的溫馴?
本人郵箱: chenying998179 # 163.com ( #改為@ )
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

