第十一章:StandardWrapper
1.loadServlet方法:
if如果属性instance不为null则返回
else:
加载classClass = classLoader.loadClass(actualClass);
实例化servlet = (Servlet) classClass.newInstance();
调用init方法servlet.init(facade);
当if ((loadOnStartup > 0) && (jspFile != null))
{
调用service方法servlet.service(req, res);
}
(其中监听事件触发这里省略[有调用service方法servlet.service(req, res);])
返回return servlet;
2.allocate方法:
根据singleThreadModel值判断走不同分支:一不是stm子类,一是stm子类
instance = loadServlet();
instancePool.push(loadServlet());
(Servlet) instancePool.pop();
STM子类执行:(STM的思想作用)
synchronized (instancePool) {
//当同时挤进来多个连接(wraperValue.invole没有结束)
//当第一连接进来:
//maxInstances=2
//countAllocated=0
//nInstances=0
//第一次while后
//maxInstances=5
//countAllocated=0
//nInstances=1
//while条件不成立向下走:countAllocated(++)=1
//当第二连接进来:
//maxInstances=2
//countAllocated=1
//nInstances=1
//第二次while后
//maxInstances=2
//countAllocated=2
//nInstances=2
//while条件不成立向下走:countAllocated(++)=2
//当第三连接进来:
//maxInstances=2
//countAllocated=2
//nInstances=2
//没法进入if (nInstances < maxInstances) {}
//阻塞 当deallocate执行时
//maxInstances=2
//countAllocated=1
//nInstances=2
//while条件不成立向下走:countAllocated(++)=2
//再次阻塞可以说会一直阻塞;当执行unload时会等待(countAllocated是否为0)剩余执行完毕(此时countAllocated=0);
//最后wraperValue.invole结束
//nInstances当前STM 实例的个数
while (countAllocated >= nInstances){
// Allocate a new instance if possible, or else wait
if (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();
bug(或疑问):如上的“//当第三连接进来”只要nInstances的值达到maxInstances时说明本次invole只能等待结束,instancePool中的sevlet不能被继续使用。因为nInstances只有递增。只有结束才变为0(nInstances=0)
3.deallocate(servlet)方法:
主要instancePool.push(servlet)方法,进行回收;(适用stm子类)
4.unload();方法:
Thread.currentThread().setContextClassLoader(classLoader);
instance.destroy();
instance = null;
//如果是stm且instancePool池不为null
if (singleThreadModel && (instancePool != null))
{
((Servlet) instancePool.pop()).destroy();
instancePool = null;
}
问题:当StandardWrapperValve.invoke结束时:其他sevletclass(非STM)正在执行怎么办
答案:当执行unload时会等待(countAllocated是否为0)剩余执行完毕(此时countAllocated=0);
StandardWrapperValve
Invoke方法:
StandardWrapper wrapper = (StandardWrapper) getContainer();
servlet = wrapper.allocate();
ApplicationFilterChain filterChain = createFilterChain(request, servlet);
filterChain.doFilter(sreq, sres);
wrapper.deallocate(servlet);
wrapper.unload();
过滤器:
StandardWrapperValve.invoke():
调用createFilterChain方法生成ApplicationFilterChain filterChain;
调用filterChain.doFilter(sreq, sres);
createFilterChain:
获得所有的ApplicationFilterConfigs
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
遍历ApplicationFilterConfigs
筛选合适的ApplicationFilterConfig
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
把合适的ApplicationFilterConfig放入filterChain中
filterChain.addFilter(filterConfig);
doFilter,internalDoFilter:
从ApplicationFilterConfig中获得Filter
filter = filterConfig.getFilter();通过FilterDef的描述生成new filter
执行Filter的doFilter方法
filter.doFilter(request, response, this);
最后执行servlet.service(request, response);
web.xml:
<filter>
<filter-name>httpOnlyFilter</filter-name>
<filter-class>..cn.filter.HttpOnlyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpOnlyFilter</filter-name>
<url-pattern>/vl/*</url-pattern>
</filter-mapping>
HttpOnlyFilter 实现Filter接口 。FilterDef一一对应的是web.xml中<filter>
Realm(138)
http://www.cnblogs.com/ansen/articles/2017360.html
LoginConfig和下面一一对应
• <login-config>
• <auth-method>FORM</auth-method>
• <form-login-config>
• <form-login-page>/login/a.html
• </form-login-page>
• <form-error-page>/login/error.html
• </form-error-page>
• </form-login-config>
• </login-config>
AuthenticatorBase 继承ValveBase
SimpleRealm中缓存ArrayList users数据
SimpleContextConfig监听器(context的监听器)加载阀门BasicAuthenticator
在BasicAuthenticator.invoke()中调用authenticate(hrequest, hresponse, config)
通过context.getRealm().authenticate(username, password) 进行获取Principal.如果存在进行register缓存失败根据LoginConfig中设置的数据进行处理
SecurityConstraint.addAuthRole("manager")加入授权角色, authConstraint的标志就变为true
Bootstrap1的main()中在Realm realm = new SimpleRealm(); context.setRealm(realm);
在SimpleRealm已经创建了数据并缓存在ArrayList users 属性中
private void createUserDatabase() {
User user1 = new User("ken", "blackcomb");
user1.addRole("manager");
user1.addRole("programmer");
User user2 = new User("cindy", "bamboo");
user2.addRole("programmer");
users.add(user1);
users.add(user2);
}
1.先在缓存中查找。
2.在BasicAuthenticator.invoke()中checkUserData方法
protected SecurityConstraint = findConstraint(HttpRequest request) {
SecurityConstraint constraints[] = context.findConstraints();
}
if ((constraint == null) /* &&//如果为null进入下一个阀门
(!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) {
if (debug >= 1)
log(" Not subject to any constraint");
context.invokeNext(request, response);
return;
}
在BasicAuthenticator.invoke()中
if (!checkUserData(hrequest, hresponse, constraint)) {
if (debug >= 1)
log(" Failed checkUserData() test");
// ASSERT: Authenticator already set the appropriate
// HTTP status code, so we do not have to do anything special
return;
}
在checkUserData方法中进行userdataconstraint验证如果ok返回true 否则sendRedirect重定向
3.在BasicAuthenticator.invoke()中调用authenticate(hrequest, hresponse, config)方法
Bootstrap1的main()中constraint.addAuthRole("manager");
if (constraint.getAuthConstraint()) {//返回true
if (debug >= 1)
log(" Calling authenticate()");
if (!authenticate(hrequest, hresponse, config)) {
if (debug >= 1)
log(" Failed authenticate() test");
// ASSERT: Authenticator already set the appropriate
// HTTP status code, so we do not have to do anything special
return;
}
}
在authenticate(hrequest, hresponse, config)方法中通过context.getRealm().authenticate(username, password) 进行获取Principal.如果存在进行register缓存失败根据LoginConfig中设置的数据进行处理
4.在BasicAuthenticator.invoke()中accessControl方法
accessControl(hrequest, hresponse, constraint){
LoginConfig config = context.getLoginConfig()
Constants.FORM_METHOD.equals(config.getAuthMethod()
Principal principal =
((HttpServletRequest) request.getRequest()).getUserPrincipal();
hasRole(Principal principal, String role)
}
tomcat study 第十一章
最新推荐文章于 2024-02-13 19:10:23 发布