设为首页 收藏本站
查看: 349|回复: 0

[经验分享] tomcat源码解析--StandardWrapperValve

[复制链接]

尚未签到

发表于 2017-1-28 15:29:59 | 显示全部楼层 |阅读模式
  StandardWrapperValve wrapper的最后一个valve,进入servlet之前的最后一步
  invoke方法
  先判断context和wrapper的 是否可用

if (!context.getAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}
// Check for the servlet being marked unavailable
if (!unavailable && wrapper.isUnavailable()) {
container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
unavailable = true;
}
  加载servlet

if (!unavailable) {
servlet = wrapper.allocate();
}
  allocate方法

   boolean newInstance = false;
// If not SingleThreadedModel, return the same instance every time
if (!singleThreadModel) {
// 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);
}
}
}
}
  loadServlet 方法
  1. 对于JSP 的处理

String actualClass = servletClass;
if ((actualClass == null) && (jspFile != null)) {
Wrapper jspWrapper = (Wrapper)
((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
if (jspWrapper != null) {
actualClass = jspWrapper.getServletClass();
// Merge init parameters
String paramNames[] = jspWrapper.findInitParameters();
for (int i = 0; i < paramNames.length; i++) {
if (parameters.get(paramNames) == null) {
parameters.put
(paramNames,
jspWrapper.findInitParameter(paramNames));
}
}
}
  设置classloader,默认为loader的classloader,如果是 ContainerServlet 的子类或者 org.apache.catalina包下的,则设置当前的classloader

ClassLoader classLoader = loader.getClassLoader();
// Special case class loader for a container provided servlet
//  
if (isContainerProvidedServlet(actualClass) &&
! ((Context)getParent()).getPrivileged() ) {
// If it is a priviledged context - using its own
// class loader will work, since it's a child of the container
// loader
classLoader = this.getClass().getClassLoader();
}
  加载servlet class,如果是包限制的,则特殊处理

if (SecurityUtil.isPackageProtectionEnabled()){
final ClassLoader fclassLoader = classLoader;
final String factualClass = actualClass;
try{
classClass = (Class)AccessController.doPrivileged(
new PrivilegedExceptionAction(){
public Object run() throws Exception{
if (fclassLoader != null) {
return fclassLoader.loadClass(factualClass);
} else {
return Class.forName(factualClass);
}
}
});
} catch(PrivilegedActionException pax){
Exception ex = pax.getException();
if (ex instanceof ClassNotFoundException){
throw (ClassNotFoundException)ex;
} else {
getServletContext().log( "Error loading "
+ fclassLoader + " " + factualClass, ex );
}
}
} else {
if (classLoader != null) {
classClass = classLoader.loadClass(actualClass);
} else {
classClass = Class.forName(actualClass);
}
}
  创建servlet 实例,处理注解(StandardContext的AnnotationProcessor??)

servlet = (Servlet) classClass.newInstance();
// Annotation processing
if (!((Context) getParent()).getIgnoreAnnotations()) {
if (getParent() instanceof StandardContext) {
((StandardContext)getParent()).getAnnotationProcessor().processAnnotations(servlet);
((StandardContext)getParent()).getAnnotationProcessor().postConstruct(servlet);
}
}
  触发 before_init_event

instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
servlet);
  servlet init方法调用,对于设置SecurityManager的特殊对待(SecurityUtil???)

                if( Globals.IS_SECURITY_ENABLED) {
boolean success = false;
try {
Object[] args = new Object[]{ facade };
SecurityUtil.doAsPrivilege("init",
servlet,
classType,
args);
success = true;
} finally {
if (!success) {
// destroy() will not be called, thus clear the reference now
SecurityUtil.remove(servlet);
}
}
} else {
servlet.init(facade);
}
  JSP 处理,直接调用service了

if ((loadOnStartup >= 0) && (jspFile != null)) {
// Invoking jspInit
DummyRequest req = new DummyRequest();
req.setServletPath(jspFile);
req.setQueryString(Constants.PRECOMPILE + "=true");
DummyResponse res = new DummyResponse();
if( Globals.IS_SECURITY_ENABLED) {
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args);
args = null;
} else {
servlet.service(req, res);
}
}
  并且还会判断servlet是否 SingleThreadModel 子类,如果是会创建相关的instancePool

singleThreadModel = servlet instanceof SingleThreadModel;
if (singleThreadModel) {
if (instancePool == null)
instancePool = new Stack();
}
  触发load事件

fireContainerEvent("load", this);
  对于非多线程的servlet,池的处理

synchronized (instancePool) {
while (countAllocated.get() >= 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 (log.isTraceEnabled())
log.trace("  Returning allocated STM instance");
countAllocated.incrementAndGet();
return (Servlet) instancePool.pop();
}
  allocate 结束
  获取过滤器链

ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain =
factory.createFilterChain(request, wrapper, servlet);
  过滤器处理

if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (comet) {
filterChain.doFilterEvent(request.getEvent());
request.setComet(true);
} else {
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (comet) {
request.setComet(true);
filterChain.doFilterEvent(request.getEvent());
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
  ApplicationFilterChain.doFilter方法调用internalDoFilter方法处理
  filter 遍历处理

ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null;
try {
filter = filterConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
filter, request, response);
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege
("doFilter", filter, classType, args, principal);
args = null;
} else {  
filter.doFilter(request, response, this);
}
support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
filter, request, response);
  service 方法调用

support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
servlet, request, response);
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse)) {
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);   
args = null;
} else {  
servlet.service((HttpServletRequest) request,
(HttpServletResponse) response);
}
} else {
servlet.service(request, response);
}
support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
servlet, request, response);
  调用结束,开始善后
  过滤器标志回滚

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();
}
}
  如果有servlet 池,释放当前servlet

if (servlet != null) {
wrapper.deallocate(servlet);
}
  释放当前servlet在 wrapper中

if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-334604-1-1.html 上篇帖子: tomcat源码解析--StandardContextValve 下篇帖子: eclipse tomcat 内存溢出
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表