`
zddava
  • 浏览: 243654 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Tomcat请求处理(六) -- Servlet实例创建

阅读更多
首先,来看一下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页面在后边还有编译等操作,后边还要继续详述。
分享到:
评论

相关推荐

    tomcat9+tomcat-cluster-redis-session-manager_4.0.zip

    在IT行业中,尤其是在Web服务器领域,Tomcat是一个广泛使用的开源应用服务器,特别是对于Java Servlet和JavaServer Pages(JSP)的应用。"tomcat9+tomcat-cluster-redis-session-manager_4.0.zip"这个文件组合涉及到...

    day04-Tomcat&Servlet入门-讲义.zip

    【标签】"Tomcat&Servlet入门"表明了本教程的主要内容,即为初学者提供Tomcat服务器的安装、配置和管理指南,以及Servlet的基本概念、生命周期、请求处理和响应生成等核心知识。 【压缩包子文件的文件名称列表】:...

    tomcat-redis-session-manager包集合下载(tomcat8)

    Tomcat作为流行的开源Java Servlet容器,负责处理HTTP请求并管理用户会话。默认情况下,Tomcat将session数据存储在服务器内存中,但这种方法在高并发和分布式环境下可能不够高效,因为session数据无法在集群中的多个...

    day04-Tomcat&Servlet入门-资料.zip

    5. **Servlet容器**:理解Servlet容器(如Tomcat)是如何管理Servlet的,包括实例化、线程安全问题和请求分发。 6. **部署应用**:学习如何将Java Web应用打包成war文件,然后部署到Tomcat服务器上。 7. **MVC模式...

    tomcat-connectors-1.2.40-windows-x86_64-httpd-2.4.x

    通过连接器,HTTPD能够将请求分发到不同的Tomcat实例,当某个实例出现问题时,其他实例可以继续提供服务,确保服务的连续性。 Tomcat连接器的工作原理是通过AJP(Apache JServ Protocol)或MOD_JK协议实现通信。AJP...

    tomcat-redis-session-manager tomcat+nginx+redis集群所需jar

    在多服务器环境中,Tomcat通常被用作应用服务器,负责处理业务逻辑和用户请求。 2. **Nginx**: Nginx是一款高性能的HTTP和反向代理服务器,以其高并发、低内存消耗和稳定性著称。在Tomcat集群前部署Nginx,可以实现...

    apache-tomcat-9.0-windows-x64.zip 内置64位的三个版本尽情使用 吧少年

    10. **集群与负载均衡**: 对于高可用性和负载均衡的需求,Tomcat支持集群配置,通过复制请求和session数据来确保在一个实例故障时,其他实例可以接管服务。 以上是关于“apache-tomcat-9.0-windows-x64.zip”压缩包...

    apache-tomcat-9.0.54-embed.zip

    它包含了处理HTTP请求、管理Servlet实例、执行生命周期管理和处理会话管理等功能。开发者可以利用这个模块在自己的应用中直接启动和管理Tomcat服务器。 2. **ECJ**: "ecj-4.20.jar"是Eclipse Compiler for Java的...

    tomcat-redis-session-manager.zip

    - `tomcat-juli-7.0.61.jar`,`tomcat-util-7.0.61.jar`,`tomcat-annotations-api-7.0.61.jar` 和 `tomcat-api-7.0.61.jar`:这些都是Tomcat 7.0.61版本的关联库,提供了日志、实用工具、注解处理和核心API等功能...

    apache-tomcat-7.0.82-windows-x86

    13. **多实例配置**:在同一个机器上运行多个Tomcat实例,每个实例都有自己的配置、日志和工作目录,可以实现负载均衡或隔离不同应用。 14. **集成其他服务器**:Tomcat可以与其他应用服务器如Apache HTTP Server...

    apache-tomcat-7.0.79.zip

    9. **集群与负载均衡**:Tomcat支持集群配置,可以创建多个Tomcat实例,通过负载均衡技术分发请求,提高系统可用性和可扩展性。 10. **Web应用程序的热更新**:在开发过程中,Tomcat支持热部署,即在不重启服务器的...

    tomcat-redis-session-manager-tomcat-7.zip

    Apache Tomcat作为广泛使用的Java Servlet容器,提供了丰富的功能来支持会话管理。然而,在分布式环境中,传统的基于内存的会话管理方式可能会面临数据不一致性和高可用性问题。为了解决这些问题,我们可以采用Redis...

    tomcat-servlet-ajax最基础例子

    【标题】"Tomcat-Servlet-Ajax基础实例详解" 在这个基础实例中,我们将探讨如何在Tomcat服务器上使用Servlet和Ajax技术实现一个简单的交互功能。Tomcat是一个流行的开源Java Servlet容器,它允许开发者运行和部署...

    web容器---servlet

    1. 加载和初始化:当Web容器接收到第一个针对Servlet的请求时,会加载Servlet类并创建一个Servlet实例。然后调用`init()`方法进行初始化,可以在这个方法中进行配置初始化或者资源加载。 2. 服务:初始化后,每当有...

    Tomcat请求处理UML序列图

    ### Tomcat请求处理UML序列图解析 #### 一、概述 Apache Tomcat是一个开源的Servlet容器,主要用于执行Java Servlet和展示JSP页面。在Tomcat中,HTTP请求的处理流程是一个复杂的过程,涉及到多个组件之间的交互。...

    servlet是如何同时处理多个请求的

    通过这种方式,Tomcat可以同时处理多个请求,而无需为每个请求创建新的Servlet实例。 3. **Servlet的`service`方法**: - `service`方法是Servlet的核心,它会根据请求的方法(GET、POST等)调用对应的`doGet`、`...

    apache-tomcat-7.0.42-windows-x64免安装包

    - **Catalina**:这是Tomcat的核心组件,负责处理Servlet和JSP的请求。 - **Jasper**:JSP编译器,将JSP页面转换为Java类,然后由Catalina执行。 - **Connector**(又称HTTP Connector):负责与Web客户端通信,...

    tomcat-connectors-1.2.40-windows-x86_64-httpd-2.4.x.zip mod_jk 64位

    Apache Tomcat是一款广泛应用的开源Java Servlet容器,它负责处理Java Web应用程序。然而,Tomcat本身并不包含Web服务器功能,因此通常需要与其他Web服务器如Apache HTTP Server集成,以实现更强大的功能和更好的...

    apache-tomcat-6.0.32-windows-x64

    Servlet容器接收HTTP请求,创建Servlet实例,调用Servlet的方法来处理请求,并将响应返回给客户端。 2. **JSP支持**:除了Servlet,Tomcat还支持JSP技术,使得开发者可以使用HTML、CSS和Java代码混合编写动态网页。...

    apache-tomcat-7.0.64-src

    Tomcat通过解析HTTP请求,调用相应的Servlet实例,执行业务逻辑,并将结果返回给客户端。在Tomcat中,Servlets和JSPs通常一起使用,JSP用于生成动态HTML内容,而Servlet则负责处理业务逻辑。 Tomcat 7.0.64是该软件...

Global site tag (gtag.js) - Google Analytics