`
刘琛颖
  • 浏览: 50289 次
  • 性别: Icon_minigender_1
  • 来自: 成都
最近访客 更多访客>>
社区版块
存档分类
最新评论

请求在Tomcat中传到了CoyoteAdapter的#service()方法中后,就要准备进入Pi

阅读更多
首先,来看一下Servlet的载入过程。

具体是在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页面在后边还有编译等操作,后边还要继续详述。
分享到:
评论

相关推荐

    Tomcat请求处理UML序列图

    在Tomcat中,HTTP请求的处理流程是一个复杂的过程,涉及到多个组件之间的交互。为了更好地理解这个过程,我们可以利用UML(Unified Modeling Language)序列图来进行描述和分析。 #### 二、Tomcat请求处理流程中的...

    apache-tomcat-9.0.8-src源码资源

    通过对`apache-tomcat-9.0.8-src`源码的深入研究,我们可以了解到Tomcat如何处理网络请求,怎样管理Web应用,以及如何实现各种高级特性。这对于开发者来说是一份宝贵的学习资料,可以帮助他们更好地优化应用程序,...

    我的tomcat7源码手撕过程

    - `main`方法中,“start”关键字引导程序进入`start`方法,进而调用`load`方法。 - `load`方法通过反射机制加载`org.apache.catalina.startup.Catalina`类,并调用其`load`方法。 5. **Catalina类解析**: - **...

    基于全局储存的新思路 _ Tomcat的一种通用回显方法研究1

    然而,这种方法受到Tomcat请求处理流程的限制,作者尝试寻找不改变代码流程的新方法,转而寻找Tomcat中全局存储Request和Response的方式。关键在于找到当前运行代码的上下文环境与Tomcat运行上下文环境之间的关联。 ...

    Tomcat8.0底层源码

    在Tomcat中,Web应用的部署主要由`HostConfig`完成,它解析`WEB-INF/web.xml`来创建`Context`对象。`StandardContext`类是`Context`的具体实现,负责管理Servlet和JSP的生命周期。`WebappClassLoader`则负责加载应用...

    tomcat源码研读笔记中的tomcat源码

    《Tomcat源码研读笔记》是对Apache Tomcat服务器内部工作原理的深度探索。Tomcat作为一款广泛应用的开源Java Servlet容器,它的源码是理解Java ...在阅读源码的过程中,应结合实际应用场景,逐步揭开Tomcat的神秘面纱。

    简单的Tomcat源码实现

    3. **请求处理**:` CoyoteAdapter`是Servlet容器与Tomcat网络接口(Coyote)之间的桥梁,它负责将接收到的HTTP请求转化为Servlet的`ServletRequest`和`ServletResponse`对象。 4. **容器结构**:Tomcat有多个级别...

    tomcat5.5源代码

    这对于理解如何在Tomcat中管理和控制自定义组件的生命周期至关重要。 4. **连接器实现**: `org.apache.coyote`包下包含了Tomcat的连接器实现,如`CoyoteAdapter`,它负责将网络I/O事件转化为内部请求对象,如`org...

    Tomcat6_0_18 源代码 src

    在Tomcat6.0.18中,主要有两个协议处理器:AprLifecycleListener(使用Apache Portable Runtime库)和 CoyoteAdapter(用于Java的NIO和BIO实现)。源码分析可以帮助我们理解数据传输的细节。 3. **Jasper与JSP编译*...

    Tomcat系统架构.docx

    Service、Connector和Container的配置都在此文件中定义。 Service通常包含一个Container和多个Connector,使得Tomcat可以同时处理多种类型的连接。Connector与Container之间的交互是请求处理的核心流程:Connector...

    Tomcat8源代码

    Tomcat中的组件都遵循一个标准的生命周期,包括初始化、启动、暂停、停止和销毁。`Lifecycle`接口和`LifecycleListener`接口定义了这个过程。 6. **部署与加载** Tomcat使用`org.apache.catalina.deploy`和`org....

    apache-tomcat-9.0.1源码

    Tomcat提供了JNDI(Java Naming and Directory Interface)服务,允许在Web应用中查找和绑定资源。源码中,`org.apache.naming`包包含了相关的实现。 7. **安全管理**: Tomcat的源码中,`org.apache.catalina....

    tomcat工作原理-框架

    - **Servlet处理**: Servlet执行service()方法,根据请求类型调用doGet()或doPost()等方法。 - **响应生成**: Servlet生成的响应内容通过Response对象返回给Connector,再由Connector打包成HTTP响应返回给客户端。...

    tomcat6.0源码

    6. **生命周期管理**:Tomcat中的所有组件都遵循一定的生命周期,包括初始化、启动、停止和销毁等阶段。源码中可以看到这些阶段是如何管理的。 7. **部署与上下文(Context)**:Tomcat通过Context对象来管理和部署...

    tomcat-coyote-7.0.34-sources.jar.zip

    Coyote是Tomcat中的核心组件之一,主要负责处理HTTP请求和响应。它的设计目标是提供一个高性能、低级别的连接器,使得Tomcat可以高效地处理网络I/O操作。Coyote的设计模式采用了Java NIO(非阻塞I/O)技术,这使得它...

    tomcat源码分析

    - **描述**:Tomcat中的各种资源(如消息字符串)通常存储在`.properties`文件中。 - **位置**:这些文件位于Tomcat安装目录下的`conf`文件夹或相应组件的配置文件夹中。 - **功能**:提供国际化支持、错误信息提示...

    tomcat6.0 jar包及源代码

    在源码中,我们可以学习到线程池的实现、内存管理策略、网络通信技术,甚至可以了解Tomcat如何实现与其他应用服务器的集成,如JNDI服务、JMX监控等。 总之,Tomcat 6.0的jar包和源代码为我们提供了一个全面了解和...

    apache-tomcat-6.0.24-src源码

    - **请求处理流程**:了解从接收到一个HTTP请求到发送响应的整个流程,涉及`CoyoteAdapter`, `Request`, `Response`等类。 - **JSP编译**:深入Jasper源码,查看JSP是如何转换为Servlet的,以及编译和执行的过程。...

    Tomcat7 核心包 catalina包源码

    在处理过程中,`StandardContext Valves`链通常包括`Mapper Valve`(映射请求到具体的Servlet)、`GlobalRequestProcessor Valve`(处理请求和响应)、`Rewrite Valve`(URL重写)等。这些Valve的顺序和配置可以根据...

Global site tag (gtag.js) - Google Analytics