您的位置:首页 > 运维架构 > Tomcat

Tomcat学习之Wrapper

2016-07-25 08:53 459 查看
http://blog.csdn.net/aesop_wubo/article/details/7926823

Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。它的父容器一般是Context,Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会抛illegalargumentexception。Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和
Servlet 的各种信息打交道。

在StandardContext启动时,读取web.xml配置文件,配置Context之后,紧接着启动Context的一些附属组件,除此以外还加载了那些标记为"load on start"的那些wrapper

[java] view
plain copy

 print?

// Load and initialize all "load on startup" servlets  

if (ok) {  

    loadOnStartup(findChildren());  

}  

[java] view
plain copy

 print?

public void loadOnStartup(Container children[]) {  

  

       // Collect "load on startup" servlets that need to be initialized  

       TreeMap<Integer, ArrayList<Wrapper>> map =  

           new TreeMap<Integer, ArrayList<Wrapper>>();  

       for (int i = 0; i < children.length; i++) {  

           Wrapper wrapper = (Wrapper) children[i];  

           int loadOnStartup = wrapper.getLoadOnStartup();  

           if (loadOnStartup < 0)  

               continue;  

           Integer key = Integer.valueOf(loadOnStartup);  

           ArrayList<Wrapper> list = map.get(key);  

           if (list == null) {  

               list = new ArrayList<Wrapper>();  

               map.put(key, list);  

           }  

           list.add(wrapper);  

       }  

  

       // Load the collected "load on startup" servlets  

       for (ArrayList<Wrapper> list : map.values()) {  

           for (Wrapper wrapper : list) {  

               try {  

                   wrapper.load();  

               } catch (ServletException e) {  

                   getLogger().error(sm.getString("standardWrapper.loadException",  

                                     getName()), StandardWrapper.getRootCause(e));  

                   // NOTE: load errors (including a servlet that throws  

                   // UnavailableException from tht init() method) are NOT  

                   // fatal to application startup  

               }  

           }  

       }  

  

   }  

这个方法做了两件事:

1、遍历这些wrapper,将其放入一个map中。key为启动顺序,value是同一启动顺序的servlet list,为了保护数字小的先启动,这里用了treemap这种数据结构来存储;

2、遍历这个map,依次加载对应list中的各个wrapper。由于采用的是arrayList,所以相同"load on start"值靠前的先加载
下面来看看StandardWrapper的load方法,直接调用了loadServlet方法来初始化

[java] view
plain copy

 print?

public synchronized void load() throws ServletException {  

       instance = loadServlet();  

         

       if (!instanceInitialized) {  

           initServlet(instance);  

       }  

  

       if (isJspServlet) {  

           StringBuilder oname =  

               new StringBuilder(MBeanUtils.getDomain(getParent()));  

             

           oname.append(":type=JspMonitor,name=");  

           oname.append(getName());  

             

           oname.append(getWebModuleKeyProperties());  

             

           try {  

               jspMonitorON = new ObjectName(oname.toString());  

               Registry.getRegistry(null, null)  

                   .registerComponent(instance, jspMonitorON, null);  

           } catch( Exception ex ) {  

               log.info("Error registering JSP monitoring with jmx " +  

                        instance);  

           }  

       }  

   }  

[java] view
plain copy

 print?

 private synchronized void initServlet(Servlet servlet)throws ServletException {  

     if (instanceInitialized && !singleThreadModel) return;  

     // Call the initialization method of this servlet  

     try {  

        instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet);  

if (Globals.IS_SECURITY_ENABLED) {  

    Object[] args = new Object[] { (facade) };  

    SecurityUtil.doAsPrivilege("init", servlet, classType, args);  

    args = null;  

} else {  

    servlet.init(facade);  

}  

  

instanceInitialized = true;  

instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet);  

     } catch (UnavailableException f) {  

//handle exception  

     }  

 }  

实际上是调用了servlet的init方法,这已经是servlet的代码了,这里不再分析。

前面提到的servlet的加载只是被标识为“load on start”的那些servlet,那么其他servlet是在什么时候被加载的呢?选中StandardWrapper的initServlet方法,在eclipse中查看其调用层次如下:



会发现有个allocate方法间接调用了它,这里给出请求进入wrapper之后的方法调用时序图:



可以看出在请求进入wrapper之后,通过allocate方法从实例池栈中弹出一个servlet实例来处理这个请求,servlet实例被封装成filterChain对象,紧接着通过一系列的过滤器过滤到达servlet.service()方法,这是singleThreadModel模式的做法。在非singleThreadModel模式的情况下首次加载并初始始化servlet赋给instance字段,下次直接从这个字段中获取servlet实例,因此在非singleThreadModel模式下每次返回的是同一个servlet实例。有关singleThreadModel的具体介绍参考:http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/SingleThreadModel.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java tomcat