• Tomcat学习之Wrapper


     

    Tomcat学习之Wrapper

    分类: WEB服务器

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

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

    1. // Load and initialize all "load on startup" servlets  
    2. if (ok) {  
    3.     loadOnStartup(findChildren());  
    4. }  
    1. public void loadOnStartup(Container children[]) {  
    2.   
    3.        // Collect "load on startup" servlets that need to be initialized  
    4.        TreeMap<Integer, ArrayList<Wrapper>> map =  
    5.            new TreeMap<Integer, ArrayList<Wrapper>>();  
    6.        for (int i = 0; i < children.length; i++) {  
    7.            Wrapper wrapper = (Wrapper) children[i];  
    8.            int loadOnStartup = wrapper.getLoadOnStartup();  
    9.            if (loadOnStartup < 0)  
    10.                continue;  
    11.            Integer key = Integer.valueOf(loadOnStartup);  
    12.            ArrayList<Wrapper> list = map.get(key);  
    13.            if (list == null) {  
    14.                list = new ArrayList<Wrapper>();  
    15.                map.put(key, list);  
    16.            }  
    17.            list.add(wrapper);  
    18.        }  
    19.   
    20.        // Load the collected "load on startup" servlets  
    21.        for (ArrayList<Wrapper> list : map.values()) {  
    22.            for (Wrapper wrapper : list) {  
    23.                try {  
    24.                    wrapper.load();  
    25.                } catch (ServletException e) {  
    26.                    getLogger().error(sm.getString("standardWrapper.loadException",  
    27.                                      getName()), StandardWrapper.getRootCause(e));  
    28.                    // NOTE: load errors (including a servlet that throws  
    29.                    // UnavailableException from tht init() method) are NOT  
    30.                    // fatal to application startup  
    31.                }  
    32.            }  
    33.        }  
    34.   
    35.    }  

    这个方法做了两件事:

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

    2、遍历这个map,依次加载对应list中的各个wrapper。由于采用的是arrayList,所以相同"load on start"值靠前的先加载

    下面来看看StandardWrapper的load方法,直接调用了loadServlet方法来初始化
    1. public synchronized void load() throws ServletException {  
    2.        instance = loadServlet();  
    3.          
    4.        if (!instanceInitialized) {  
    5.            initServlet(instance);  
    6.        }  
    7.   
    8.        if (isJspServlet) {  
    9.            StringBuilder oname =  
    10.                new StringBuilder(MBeanUtils.getDomain(getParent()));  
    11.              
    12.            oname.append(":type=JspMonitor,name=");  
    13.            oname.append(getName());  
    14.              
    15.            oname.append(getWebModuleKeyProperties());  
    16.              
    17.            try {  
    18.                jspMonitorON = new ObjectName(oname.toString());  
    19.                Registry.getRegistry(null, null)  
    20.                    .registerComponent(instance, jspMonitorON, null);  
    21.            } catch( Exception ex ) {  
    22.                log.info("Error registering JSP monitoring with jmx " +  
    23.                         instance);  
    24.            }  
    25.        }  
    26.    }  
    1.  private synchronized void initServlet(Servlet servlet)throws ServletException {  
    2.      if (instanceInitialized && !singleThreadModel) return;  
    3.      // Call the initialization method of this servlet  
    4.      try {  
    5.         instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet);  
    6. if (Globals.IS_SECURITY_ENABLED) {  
    7.     Object[] args = new Object[] { (facade) };  
    8.     SecurityUtil.doAsPrivilege("init", servlet, classType, args);  
    9.     args = null;  
    10. else {  
    11.     servlet.init(facade);  
    12. }  
    13.   
    14. instanceInitialized = true;  
    15. instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet);  
    16.      } catch (UnavailableException f) {  
    17. //handle exception  
    18.      }  
    19.  }  
    实际上是调用了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

  • 相关阅读:
    vue生命周期过程做了什么
    css_css3_实用属性_随时补充更新
    echarts的symbol引用本地图片写法
    无废话设计模式(1)--简单工厂、工厂方法、抽象工厂
    JavaWeb--Maven学习
    SpringCloud Alibaba实战 -引入服务网关Gateway
    从ReentrantLock看AQS (AbstractQueuedSynchronizer) 运行流程 抽象的队列式同步器
    架构的搭建(一)SpringCloud Alibaba
    配置中心之Nacos简介,使用及Go简单集成
    RabbitMQ
  • 原文地址:https://www.cnblogs.com/01picker/p/4556483.html
Copyright © 2020-2023  润新知