首先,来看一下Servlet的载入过程。
具体是在org.apache.catalina.core.StandardWrapper#allocate()这个方法中,源代码如下:
这段代码分两种情况来载入Servlet实例,一种是singleThreadModel的,每个请求都要创建一个实例,这些实例是放到instancePool中的,另外一种是非singleThreadModel的,它对每一个请求线程都使用同一个实例。对于非singleThreadModel的Servlet,当第一次载入之后就不需要再次构建了。
下边来大概的看一下具体的载入Servelt的过程,就是#loadServlet()这个方法。方法的细节比较多,大致了解下,主要就是ClassLoader的构建,Servlet实例的创建和Servlet初始化方法的调用3个大的部分。源代码如下:
另外,在载入JSP文件时,Servlet是org.apache.jasper.servlet.JspServlet的实例,载入静态资源时,Servlet用的是org.apache.catalina.servlets.DefaultServlet实例。
而JSP页面在后边还有编译等操作,后边还要继续详述。
具体是在org.apache.catalina.core.StandardWrapper#allocate()这个方法中,源代码如下:
public Servlet allocate() throws ServletException { if (unloading) throw new ServletException(sm.getString("standardWrapper.unloading", getName())); // 是否创建了新的实例 boolean newInstance = false; // 对非singleThreadModel的Servlet的处理 // 如果不是SingleThreadedModel,每次都返回相同的实例 if (!singleThreadModel) { // 初始化Servlet实例 if (instance == null) { synchronized (this) { if (instance == null) { try { if (log.isDebugEnabled()) log.debug("Allocating non-STM instance"); // 载入新的实例 instance = loadServlet(); if (!singleThreadModel) { newInstance = true; // 计数器自增 countAllocated++; } } catch (ServletException e) { throw e; } catch (Throwable e) { throw new ServletException(sm.getString("standardWrapper.allocate"), e); } } } } if (!singleThreadModel) { if (log.isTraceEnabled()) log.trace(" Returning non-STM instance"); if (!newInstance) {// 没有创建新实例的时候的计数器自增 countAllocated++; } // 直接返回Servlet实例 return (instance); } } // 下边是对singleThreadModel的Servlet的处理 synchronized (instancePool) { while (countAllocated >= nInstances) { // Allocate a new instance if possible, or else wait if (nInstances < maxInstances) { try { // 将Servlet实例入栈 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++; return (Servlet) instancePool.pop(); } }
这段代码分两种情况来载入Servlet实例,一种是singleThreadModel的,每个请求都要创建一个实例,这些实例是放到instancePool中的,另外一种是非singleThreadModel的,它对每一个请求线程都使用同一个实例。对于非singleThreadModel的Servlet,当第一次载入之后就不需要再次构建了。
下边来大概的看一下具体的载入Servelt的过程,就是#loadServlet()这个方法。方法的细节比较多,大致了解下,主要就是ClassLoader的构建,Servlet实例的创建和Servlet初始化方法的调用3个大的部分。源代码如下:
public synchronized Servlet loadServlet() throws ServletException { // 非singleThreadModel模式并且instance已经实例化过的情况直接返回 if (!singleThreadModel && (instance != null)) return instance; PrintStream out = System.out; if (swallowOutput) { SystemLogHandler.startCapture(); } Servlet servlet; try { long t1 = System.currentTimeMillis(); // Servlet的完整类名 String actualClass = servletClass; if ((actualClass == null) && (jspFile != null)) {// 如果是JSP文件 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[i]) == null) { parameters.put(paramNames[i], jspWrapper.findInitParameter(paramNames[i])); } } } } // Complain if no servlet class has been specified if (actualClass == null) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.notClass", getName())); } // 构建ClassLoader Loader loader = getLoader(); if (loader == null) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.missingLoader", getName())); } ClassLoader classLoader = loader.getClassLoader(); if (isContainerProvidedServlet(actualClass) && !((Context) getParent()).getPrivileged()) { classLoader = this.getClass().getClassLoader(); } Class classClass = null; try { 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); } } } catch (ClassNotFoundException e) { unavailable(null); getServletContext().log("Error loading " + classLoader + " " + actualClass, e); throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass), e); } if (classClass == null) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass)); } // 生成Servlet实例 try { servlet = (Servlet) classClass.newInstance(); if (!((Context) getParent()).getIgnoreAnnotations()) { if (getParent() instanceof StandardContext) { ((StandardContext) getParent()).getAnnotationProcessor().processAnnotations(servlet); ((StandardContext) getParent()).getAnnotationProcessor().postConstruct(servlet); } } } catch (ClassCastException e) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.notServlet", actualClass), e); } catch (Throwable e) { unavailable(null); if (log.isDebugEnabled()) { log.debug(sm.getString("standardWrapper.instantiate", actualClass), e); } throw new ServletException(sm.getString("standardWrapper.instantiate", actualClass), e); } if (!isServletAllowed(servlet)) { throw new SecurityException(sm.getString("standardWrapper.privilegedServlet", actualClass)); } if ((servlet instanceof ContainerServlet) && (isContainerProvidedServlet(actualClass) || ((Context) getParent()).getPrivileged())) { ((ContainerServlet) servlet).setWrapper(this); } classLoadTime = (int) (System.currentTimeMillis() - t1); // 调用Servelt的初始化方法 try { instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet); if (Globals.IS_SECURITY_ENABLED) { Object[] args = new Object[] { ((ServletConfig) facade) }; SecurityUtil.doAsPrivilege("init", servlet, classType, args); args = null; } else { servlet.init(facade); } // Invoke jspInit on JSP pages if ((loadOnStartup >= 0) && (jspFile != null)) { // 调用jspInit() DummyRequest req = new DummyRequest(); req.setServletPath(jspFile); req.setQueryString("jsp_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); } } 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); throw f; } catch (Throwable f) { getServletContext().log("StandardWrapper.Throwable", f); instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); throw new ServletException(sm.getString("standardWrapper.initException", getName()), f); } singleThreadModel = servlet instanceof SingleThreadModel; if (singleThreadModel) { if (instancePool == null) instancePool = new Stack(); } fireContainerEvent("load", this); loadTime = System.currentTimeMillis() - t1; } 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; }
另外,在载入JSP文件时,Servlet是org.apache.jasper.servlet.JspServlet的实例,载入静态资源时,Servlet用的是org.apache.catalina.servlets.DefaultServlet实例。
而JSP页面在后边还有编译等操作,后边还要继续详述。
发表评论
-
出现java.lang.UnsupportedClassVersionError 错误的原因
2010-08-16 23:11 871出现java.lang.UnsupportedClassVer ... -
Tomcat请求处理(七) - Servlet实例的调用
2009-05-07 11:36 1131Tomcat请求处理中Servlet实例的调用是和Filter ... -
Tomcat请求处理(五) -- 请求在容器间的流动
2009-05-07 11:34 1433请求在Tomcat中传到了CoyoteAdapter的#ser ... -
Tomcat请求处理(四) -- Request, Response, 和Pipeline
2009-05-07 11:33 12841. Request和Response 当处理请求的时候,To ... -
Tomcat请求处理(三) -- coyote请求处理
2009-05-07 11:32 1325在上一篇文章文章中,Tomcat的请求处理到了JIoEndpo ... -
Tomcat请求处理(二) -- 请求处理框架
2009-05-07 11:30 991书接上文。 当Tomcat的Acceptor监听到有请求到来时 ... -
Tomcat请求处理(一) -- 服务器端口监听
2009-05-07 11:29 1402其实tomcat在哪个类中监听请求的代码很容易找到: 在org ... -
Tomcat启动部分源代码分析(五) -- 应用程序加载
2009-05-07 11:28 1200前面所叙述的tomcat启动 ... -
Tomcat启动部分源代码分析(四) -- 开启容器
2009-05-07 11:27 1205四. 开启容器 最后是Bootstrap#start()方法的 ... -
Tomcat启动部分源代码分析(三) -- 载入
2009-05-07 11:23 1195二. 载入 2. Bootstrap的#Bootstrap#l ... -
Tomcat启动部分源代码分析(二) -- 初始化
2009-05-07 11:20 1098二. 初始化 1. 首先是Bootstrap的#init()操 ... -
Tomcat启动部分源代码分析(一) -- 概览
2009-05-07 11:17 1433一. 概览 本文所涉及的Tomcat为6.0版本。 Tomca ... -
Tomcat的Session管理(二) - Session后台处理
2009-05-07 10:10 973Tomcat会开启一个后台线程每隔一段时间检查Session的 ... -
Tomcat的Session管理(一) - Session的生成
2009-05-07 10:02 1499Session对象的创建一般是源于这样的一条语句: Sessi ...
相关推荐
在Tomcat中,HTTP请求的处理流程是一个复杂的过程,涉及到多个组件之间的交互。为了更好地理解这个过程,我们可以利用UML(Unified Modeling Language)序列图来进行描述和分析。 #### 二、Tomcat请求处理流程中的...
通过对`apache-tomcat-9.0.8-src`源码的深入研究,我们可以了解到Tomcat如何处理网络请求,怎样管理Web应用,以及如何实现各种高级特性。这对于开发者来说是一份宝贵的学习资料,可以帮助他们更好地优化应用程序,...
- `main`方法中,“start”关键字引导程序进入`start`方法,进而调用`load`方法。 - `load`方法通过反射机制加载`org.apache.catalina.startup.Catalina`类,并调用其`load`方法。 5. **Catalina类解析**: - **...
然而,这种方法受到Tomcat请求处理流程的限制,作者尝试寻找不改变代码流程的新方法,转而寻找Tomcat中全局存储Request和Response的方式。关键在于找到当前运行代码的上下文环境与Tomcat运行上下文环境之间的关联。 ...
在Tomcat中,Web应用的部署主要由`HostConfig`完成,它解析`WEB-INF/web.xml`来创建`Context`对象。`StandardContext`类是`Context`的具体实现,负责管理Servlet和JSP的生命周期。`WebappClassLoader`则负责加载应用...
《Tomcat源码研读笔记》是对Apache Tomcat服务器内部工作原理的深度探索。Tomcat作为一款广泛应用的开源Java Servlet容器,它的源码是理解Java ...在阅读源码的过程中,应结合实际应用场景,逐步揭开Tomcat的神秘面纱。
3. **请求处理**:` CoyoteAdapter`是Servlet容器与Tomcat网络接口(Coyote)之间的桥梁,它负责将接收到的HTTP请求转化为Servlet的`ServletRequest`和`ServletResponse`对象。 4. **容器结构**:Tomcat有多个级别...
这对于理解如何在Tomcat中管理和控制自定义组件的生命周期至关重要。 4. **连接器实现**: `org.apache.coyote`包下包含了Tomcat的连接器实现,如`CoyoteAdapter`,它负责将网络I/O事件转化为内部请求对象,如`org...
在Tomcat6.0.18中,主要有两个协议处理器:AprLifecycleListener(使用Apache Portable Runtime库)和 CoyoteAdapter(用于Java的NIO和BIO实现)。源码分析可以帮助我们理解数据传输的细节。 3. **Jasper与JSP编译*...
Service、Connector和Container的配置都在此文件中定义。 Service通常包含一个Container和多个Connector,使得Tomcat可以同时处理多种类型的连接。Connector与Container之间的交互是请求处理的核心流程:Connector...
Tomcat中的组件都遵循一个标准的生命周期,包括初始化、启动、暂停、停止和销毁。`Lifecycle`接口和`LifecycleListener`接口定义了这个过程。 6. **部署与加载** Tomcat使用`org.apache.catalina.deploy`和`org....
Tomcat提供了JNDI(Java Naming and Directory Interface)服务,允许在Web应用中查找和绑定资源。源码中,`org.apache.naming`包包含了相关的实现。 7. **安全管理**: Tomcat的源码中,`org.apache.catalina....
- **Servlet处理**: Servlet执行service()方法,根据请求类型调用doGet()或doPost()等方法。 - **响应生成**: Servlet生成的响应内容通过Response对象返回给Connector,再由Connector打包成HTTP响应返回给客户端。...
6. **生命周期管理**:Tomcat中的所有组件都遵循一定的生命周期,包括初始化、启动、停止和销毁等阶段。源码中可以看到这些阶段是如何管理的。 7. **部署与上下文(Context)**:Tomcat通过Context对象来管理和部署...
Coyote是Tomcat中的核心组件之一,主要负责处理HTTP请求和响应。它的设计目标是提供一个高性能、低级别的连接器,使得Tomcat可以高效地处理网络I/O操作。Coyote的设计模式采用了Java NIO(非阻塞I/O)技术,这使得它...
- **描述**:Tomcat中的各种资源(如消息字符串)通常存储在`.properties`文件中。 - **位置**:这些文件位于Tomcat安装目录下的`conf`文件夹或相应组件的配置文件夹中。 - **功能**:提供国际化支持、错误信息提示...
在源码中,我们可以学习到线程池的实现、内存管理策略、网络通信技术,甚至可以了解Tomcat如何实现与其他应用服务器的集成,如JNDI服务、JMX监控等。 总之,Tomcat 6.0的jar包和源代码为我们提供了一个全面了解和...
- **请求处理流程**:了解从接收到一个HTTP请求到发送响应的整个流程,涉及`CoyoteAdapter`, `Request`, `Response`等类。 - **JSP编译**:深入Jasper源码,查看JSP是如何转换为Servlet的,以及编译和执行的过程。...
在处理过程中,`StandardContext Valves`链通常包括`Mapper Valve`(映射请求到具体的Servlet)、`GlobalRequestProcessor Valve`(处理请求和响应)、`Rewrite Valve`(URL重写)等。这些Valve的顺序和配置可以根据...