How Tomcat works之第十一章 Allocate The Servlet
来源:互联网 发布:康师傅 解散 知乎 编辑:程序博客网 时间:2024/06/02 17:42
如同这章开头提到的那样,StandardWrapperValue的invoke方法调用wrapper的allocate方法获取一个请求servlet的实例。StandardWrapper类必须有这个方法的实现。Allocate方法的签名如下:
Publicjavax.servlet.Serlvet allocate() throwsServletException
注意allocate方法返回请求servlet的实例
为了支持STM servlets 使得allocate方法有点小复杂。实际上,allocate方法分成两部分,一部分满足非STM servlets需求,其他的满足STM Servlets需要。第一部分有如下框架:
If(!singleThreadModel){
//return a non-STM servlet instance
}
singleThreadModel是一个Boolean值,指明由StandardWrapper代表的Servlet是否是一个STM Servlet。虽然singleThreadModel初始值是false,但是loadServlet方法测试它加载的Servlet并设置这个Boolean ,如果这个Servlet是一个STM Servlet。
如果simpleThreadModel是true,allocate方法的第二部分就被执行。大致骨架如下:
synchronized(instancepool) {
//returns an instance of the servlet from the pool
}
现在我们看看第一部分和第二部分
对于非STMServlet,StandardWrapper定义了一个命名为instance 类型为javax.servlet.servlet的变量。
Private Servletinstance = null;
Allocate方法检查实例是否为null。如果为null,allocate方法调用loadServlet方法加载Servlet。之后使countAllocated变量加一并返回Servlet。
代码如下:
if(!singleThreadModel) { // Load and initialize our instance if necessary
if (instance == null) {
synchronized (this) { if (instance ==null) {
try { instance = loadServlet(); }
catch (ServletException e) {throw e; }
catch (Throwable e) {
throw newServletException
(sm.getString("standardWrapper.allocate"),e); } } } }
if(!singleThreadModel) {
if (debug >= 2)
log(" Returninq non-STMinstance");
countAllocated++;
return (instance);
}
}
如果Servlet是一个STM Servlet,allocate方法尝试从池中获取一个实例。InstancePool变量是java.util.Stack类型,与STM Servlet实例的栈关联。
代码如下:
Private Stack instancePool = null;
这个变量在loadServlet方法内部实例化,这将在下一章节讨论。
Allocate方法将分配STM Servlet的一个实例,只要实例的数量没有达到指定的最大值。maxInstances最大值默认为20.
Private int maxInstance = 20;
为获取STM 实例的当前数量,StandardWrapper类使用nInstances变量。
这里是allocate方法的第二部分。
synchronized(instancePool) { while (countAllocated >= nInstances) { // Allocate a newinstance 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();
}
上路代码使用了一个while循环,直到nInstances少于或者等于countAllocated的值。在while循环内部,allcoate方法检查nInstances的值,如果低于maxInstances,allocate方法将调用loadServlet方法并将新的实例添加到pool中并使nInstances加一。如果nInstances的值与maxInstance相等或者更大,它就通过调用instancePool的stack的wait方法等待,等待一个实例返回到stack中。
Loading theServlet
StandardWrapper类实现了wrapper接口的load方法。load方法调用loadServlet方法(加载这个Servlet)并调用它的init方法,传递一个javax.servlet.ServletConfig实例。这里是loadServlet方法如何工作的。
loadServlet方法以检查当前StandardWrapper代表的是否是一个STM Servlet开始。如果不是并且变量实例不为null(意味着Servlet之前已经加载过了),就简单的返回实例。
// Nothing to doif we already have an instance or an instance pool if (!singleThreadModel&& (instance != null)) return instance;
如果实例为null或者是一个STM实例,就运行方法的剩余部分。
首先,获取System.out和System.err的输出,这样在使用了ServletContext的log方法后可以记录任何信息。
PrintStream out =System.out; SystemLogHandler.startCapture();
之后定义类型为Servlet的变量。这代表一个需要加载的实例,由loadServlet方法返回。
Servlet servlet = null;
loadServlet方法负责加载一个servlet类。这个类的名字应该已经被指定给servletClass 的类变量。这个方法指定这个变量的值给String类型的actualClass变量。
String actualClass = servletClass
然而,由于Catalina也是一个jsp容器,loadServlet方法必须也找出请求的Servlet是否是一个jsp页面。如果是的,loadServlet方法试着获取JSP页面真正的类。
if ((actualClass == null) && (jspFile != null)) {
Wrapper jspWrapper = (Wrapper)
((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
if (jspWrapper != null)
actualClass = jspWrapper.getServletClass();
}
如果JSP页面的Servlet的名字没能发现,Servletclass变量的值将被使用。然而,如果servletClass还没有被StandardWrapper类的setServletClass方法调用,将抛出一个异常并且方法的剩余部分也不会执行。
// Complain if no servlet class has been specified
if (actualClass == null) {
unavailable(null);
throw new ServletException
(sm.getString("StandardWrapper.notClass", getName()));
}
在这个阶段,Servlet 类名还没有被指定,这样loadServlet方法获取加载器。如果没有加载器发现,就抛出一个异常并停止方法。
// Acquire an instance of the class loader to be used
Loader loader = getLoader();
if (loader == null) {
unavailable(null);
throw new ServletException
(sm.getString("StandardWrapper.missingLoader", getName()));
}
如果没有发现加载器,loadServlet方法调用它的getClassLoader方法去获取一个ClassLoader
ClassLoader classLoader = loader.getClassLoader().
Catalina提供了特殊的Servlets ,这些都在org.apache.catalian包中。如果Servlet是一个特殊的Servlet,即如果isContainerProvidedServlet方法返回true,classLoader变量由另一个ClassLoader实例指定,这样访问Catalina的内部成为可能。
// Acquire an instance of the class loader to be used
// Special case class loader for a container provided servlet
if (isContainerProvidedServlet(actualClass)) {
ClassLoader = this.getClass().getClassLoader();
log(sm.getString
("standardWrapper.containerServlet", getName()));
}
有了类加载器和要加载的servlet 名字,loadServlet方法现在能加载这个servlet了。
// Load the specified servlet class from the appropriate class
// loader
Class classClass = null;
try {
if (ClassLoader != null) {
System.out.println("Using classLoader.loadClass");
classClass = classLoader.loadClass(actualClass);
}
else {
System.out.println("Using forName");
classClass = Class.forName(actualClass);
}
}
catch (ClassNotFoundException e) {
unavailable(null);
throw new ServletException
(sm.getstring("standardWrapper.missingClass", actualClass), e);
}
if (classClass == null) {
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.missingClass", actualClass));
}
稍后,它能实例化这个servlet:
// Instantiate and initialize an instance of the servlet class
// itself
try {
servlet = (Servlet) classClass.newInstance();
}
catch (ClassCastException e) {
unavailable(null);
// Restore the context ClassLoader
throw new ServletException
(sm.getString("standardWrapper.notServlet", actualClass), e);
}
catch (Throwable e) {
unavailable(null);
// Restore the context ClassLoader
throw new ServletException
(sm.getstring("standardWrapper.instantiate", actualClass), e);
}
然而,在loadServlet方法实例化servlet之前,检查加载这个servlet是否被isServletAllowed方法允许。
if (!isServletAllowed(servlet)) {
throw new SecurityException
(sm.getString("standardWrapper.privilegedServlet",
actualClass));
}
如果安全校验通过,它检查servlet是否是一个ContainerServlet。其实现了ContainerServlet接口并能访问Catalina内部功能。如果Servlet是一个ContainerServlet,loadServlet方法调用ContainerServlet的SetWrapper方法,传递这个StandardWrapper实例。
// Special handling for ContainerServlet instances
if ((servlet instanceof ContainerServlet) &&
isContainerProvidedServlet(actualClass)) {
((ContainerServlet) servlet).setWrapper(this);
}
下一步,loadServlet方法触发了BEFORE_INIT_EVENT并调用sender的init方法。
try {
instanceSupport.fireInstanceEvent(
InstanceEvent.BEFORE_INIT_EVENT, servlet);
servlet.init(facade);
注意,init方法传递了门面变量,其与ServletConfig对象关联。
如果loadOnStartup变量被指定为一个整形值并且Servlet是一个JSP页面,就调用这个Servlet的service方法。
// Invoke jspInit on JSP pages
if ((loadOnStartup > 0) && (jspFile != null)) {
// Invoking jspInit
HttpRequestBase req = new HttpRequestBase();
HttpResponseBase res = new HttpResponseBase();
req.setServletPath(jspFile};
req.setQueryString("jsp_precompile=true");
servlet.service(req, res);
}
下一步,loadServlet方法触发了AFTER_INIT_EVENT事件。
instanceSupport.firelnstanceEvent (InstanceEvent.AFTER_INIT_EVENT,
servlet);
如果被StandardWrapper对象表示的Servlet是一个STM Servlet,这个Servlet实例被添加到实例池中。因此,如果这个instancePool变量仍就为空,就被赋值一个Stack对象。
// Register our newly initialized instance
singleThreadModel = servlet instanceof SingleThreadModel;
if (singleThreadModel) {
if (instancePool == null)
instancePool = new Stack();
}
fireContainerEvent("load", this);
}
在finally块中,loadServlet方法停止输出System.out和System.err并记录在加载过程中任何发往到ServletContext的log方法。
finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
if (getServletContext() != null) {
getServletContext().log(log);
}
else {
out.println(log);
}
}
}
并且,最后返回loadServlet方法返回Servlet的实例。
return servlet ;
- How Tomcat works之第十一章 Allocate The Servlet
- How Tomcat works之第十一章之The ServletConfig 对象
- How Tomcat works之第十一章之Parent and Child
- How Tomcat works 之第十一章之StandardWrapperValue
- How tomcat works 之第十一章之 FilterDef
- How Tomcat works之第十一章之ApplicationFilterChain
- How Tomcat works之第十一章之ApplicationFilterChain
- How Tomcat works 之The Application 应用
- How Tomcat Works之(可接受servlet请求)
- how tomcat works 五 servlet容器 上
- how tomcat works 5 servlet容器 下
- How Tomcat Works之第十二章之invoke方法
- How Tomcat works 之第十二章之重新载入支持
- How Tomcat works 之第十三章之 StandardHostMapper
- How Tomcat works之第六章:Lifecycle生命周期
- How Tomcat works之第九章 会话管理
- How Tomcat works 之第九章 BootStrap类
- How Tomcat works 之第十章 Security 安全
- wordpress博客加载缓慢解决:去除Open Sans和Lato 字体
- veridata实验举例(4)验证veridata查找出updata、delete操作导致的不同步现象
- C语言中的命名规则
- 转~ubuntu的一些常用软件
- [网络分析] 3 不用回调的方式捕获数据包
- How Tomcat works之第十一章 Allocate The Servlet
- php连接mysql的操作
- UI笔记_程序启动流程
- protobuf 使用
- zkconfigutil
- poj 2726:采药
- 大数相加
- Sap NetWeaver CE7.1中Webdnpro 超过最大会话数问题
- python字符串模板中的KeyError