iis服务器助手广告
返回顶部
首页 > 资讯 > 精选 >怎么在tomcat中调用Servlet实现初始化
  • 867
分享到

怎么在tomcat中调用Servlet实现初始化

2023-06-14 22:06:35 867人浏览 泡泡鱼
摘要

怎么在Tomcat中调用Servlet实现初始化?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、代码启动tomcat平常我们不论是windows还是linux,我们都是通过脚

怎么在Tomcat中调用Servlet实现初始化?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

一、代码启动tomcat

平常我们不论是windows还是linux,我们都是通过脚本来启动tomcat,这对于我们分析源码不是很友好,所以我们 需要通过代码启动,启动代码如下:

Tomcat tomcat = new Tomcat();        tomcat.setPort(8080);        //new 出各层容器,并且维护各层容器的关系        tomcat.addWEBapp("/","/");        tomcat.start();        //阻塞监听端口        tomcat.getServer().await();

启动代码还是非常非常简单,从代码中我们就可以看出,我们本篇博客主要分析的就是 addWebapp()方法和start()方法,通过这两个方法我们就可以找到servlet容器是在什么时候被初始化的。

二、tomcat框架

在我们进行分析上面两个方法之前,我们先总结一下tomcat的基础框架,其实从我们非常熟悉的 server.xml配置文件中就可以知道,tomcat就是一系列父子容器组成:

Server ---> Service --> Connector Engine addChild---> context(servlet容器) ,这就是我们从配置文件中分析出来的几个容器,tomcat启动时候就是逐层启动容器。

三、创建容器(addWebapp())

3.1 方法 调用流程图

怎么在tomcat中调用Servlet实现初始化

上面的流程图就是,从源码中逐步分析出来的几个重要的方法,这对于我们分析源码非常有帮助。

3.2 源码分析

1)通过反射获得confiGContext监听器

方法路径:package org.apache.catalina.startup.Tomcat.addWebapp(Host host, String contextPath, String docBase);

     public Context  addWebapp(Host host, String contextPath, String docBase) {        //通过反射获得一个监听器  ContextConfig,        //通过反射得到的一定是LifecycleListener的一个实现类,进入getConfigClass得到实现类(org.apache.catalina.startup.ContextConfig)        LifecycleListener listener = null;        try {            Class<?> clazz = Class.forName(getHost().getConfigClass());            listener = (LifecycleListener) clazz.getConstructor().newInstance();        } catch (ReflectiveOperationException e) {            // Wrap in IAE since we can't easily change the method signature to            // to throw the specific checked exceptions            throw new IllegalArgumentException(e);        }         return addWebapp(host, contextPath, docBase, listener);    }

2) 获得一个context容器(StandardContext)

在下面代码中,createContext()方法通过反射加载StandardContext容器,并且将设置监听ContextConfig, ctx.addLifecycleListener(config);

public Context addWebapp(Host host, String contextPath, String docBase,            LifecycleListener config) {         silence(host, contextPath);         //获得一个context容器(StandardContext)        Context ctx = createContext(host, contextPath);        ctx.setPath(contextPath);        ctx.setDocBase(docBase);         if (aDDDefaultWebXmlToWebapp) {            ctx.addLifecycleListener(getDefaultWebXmlListener());        }         ctx.setConfigFile(getWebappConfigFile(docBase, contextPath));        //把监听器添加到context中去        ctx.addLifecycleListener(config);         if (addDefaultWebXmlToWebapp && (config instanceof ContextConfig)) {            // prevent it from looking ( if it finds one - it'll have dup error )            ((ContextConfig) config).setDefaultWebXml(nodefaultWebXmlPath());        }         if (host == null) {            //getHost会逐层创建容器,并维护容器父子关系            getHost().addChild(ctx);        } else {            host.addChild(ctx);        }         return ctx;    }

3)维护各层容器

getHost()方法中得到各层容器,并且维护父亲容器关系,其中包括,server容器、Engine容器。并且将StandardContext容器通过getHost().addChild(ctx); 调用containerBase中的addChild()方法维护在 children 这个map中。

  public Host getHost() {        //将每一层的容器都new 出来        Engine engine = getEngine();        if (engine.findChildren().length > 0) {            return (Host) engine.findChildren()[0];        }         Host host = new StandardHost();        host.setName(hostname);        //维护tomcat中的父子容器        getEngine().addChild(host);        return host;    }

getEngine().addChild(host); 方法选择调用父类containerBase中的addChild方法

怎么在tomcat中调用Servlet实现初始化

  @Override    public void addChild(Container child) {        if (Globals.IS_SECURITY_ENABLED) {            PrivilegedAction<Void> dp =                new PrivilegedAddChild(child);            AccessController.doPrivileged(dp);        } else {            //这里的child 参数是 context 容器            addChildInternal(child);        }    }

addChildInternal()方法的 核心代码

 private void addChildInternal(Container child) {         if( log.isDebugEnabled() )            log.debug("Add child " + child + " " + this);        synchronized(children) {            if (children.get(child.getName()) != null)                throw new IllegalArgumentException("addChild:  Child name '" +                                                   child.getName() +                                                   "' is not unique");            child.setParent(this);  // May throw IAE            children.put(child.getName(), child);    }

四、启动容器(tomcat.start())

4.1、方法调用流程图

怎么在tomcat中调用Servlet实现初始化

4.2、源码分析

说明:StandardServer 、StandardService、StandardEngine等容器都是继承LifecycleBase

所以这里是模板模式的经典应用

1)逐层启动容器

此时的server对应的是我们前面创建的StandardServer

  public void start() throws LifecycleException {        //防止server容器没有创建        getServer();        //获得connector容器,并且将得到的connector容器设置到service容器中        getConnector();        //这里的start的实现是在 LifecycleBase类中实现        //LifecycleBase方法是一个模板方法,在tomcat启动流程中非常关键        server.start();    }

2) 进入start方法

怎么在tomcat中调用Servlet实现初始化

进入LifecycelBase中的start方法,其中核心方法是startInternal。

怎么在tomcat中调用Servlet实现初始化

从上面我们知道现在我们调用的是StandardServer容器的startInternal()方法,所以我们这里选择的是StandardServer

怎么在tomcat中调用Servlet实现初始化

方法路径:org.apache.catalina.core.StandardServer.startInternal()

protected void startInternal() throws LifecycleException {         fireLifecycleEvent(CONFIGURE_START_EVENT, null);        setState(LifecycleState.STARTING);         globalNamingResources.start();         // Start our defined Services        synchronized (servicesLock) {            //启动 service容器,一个tomcat中可以配置多个service容器,每个service容器都对应这我们的一个服务应用            for (Service service : services) {                //对应 StandardService.startInternal()                service.start();            }        }    }

从上面代码中我们可以看出,启动server容器的时候需要启动子容器 service容器,从这里开始就是容器 逐层向向内引爆,所以接下来就是开始依次调用各层容器的star方法。在这里就不在赘述。

2)ContainerBase中的startInternal()方法 核心代码,从这开始启动StandardContext容器

 // Start our child containers, if any        //在addWwbapp的流程中 addChild方法中加入的,所以这里需要找出来        //这里找出来的就是 context 容器        Container children[] = findChildren();        List<Future<Void>> results = new ArrayList<>();        for (Container child : children) {            //通过线程池 异步的方式启动线程池 开始启动 context容器,进入new StartChild            results.add(startStopExecutor.submit(new StartChild(child)));        }

new StartChild(child)) 方法开始启动StandardContext容器

private static class StartChild implements Callable<Void> {         private Container child;         public StartChild(Container child) {            this.child = child;        }         @Override        public Void call() throws LifecycleException {            //开始启动context,实际调用 StandardContext.startInternal()            child.start();            return null;        }    }

StandardContext.startInternal() 方法中的核心代码:

怎么在tomcat中调用Servlet实现初始化

   protected void fireLifecycleEvent(String type, Object data) {        LifecycleEvent event = new LifecycleEvent(this, type, data);        //lifecycleListeners 在addwebapp方法的第一步中,设置的监听的 contextConfig对象        for (LifecycleListener listener : lifecycleListeners) {            //这里调用的是 contextConfig的lifecycleEvent()方法            listener.lifecycleEvent(event);        }    }

进入到 contextConfig中的lifecycleEvent()方法

怎么在tomcat中调用Servlet实现初始化

public void lifecycleEvent(LifecycleEvent event) {         // Identify the context we are associated with        try {            context = (Context) event.getLifecycle();        } catch (ClassCastException e) {            log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);            return;        }         // Process the event that has occurred        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {            //完成web.xml的内容解析            configureStart();        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {            beforeStart();        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {            // Restore docBase for management tools            if (originalDocBase != null) {                context.setDocBase(originalDocBase);            }        } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {            configureStop();        } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {            init();        } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {            destroy();        }     }

在上面方法中,完成对web.xml的加载和解析,同时加载xml中配置的servlet并且封装成wrapper对象。

3)、启动servlet容器,StandardContext.startInternal() 中的 loadOnStartup(findChildren())方法

public boolean loadOnStartup(Container children[]) {         // Collect "load on startup" servlets that need to be initialized        TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();        for (Container child : children) {            //这里的 Wrapper就是 我们前面封装的 servlet            Wrapper wrapper = (Wrapper) child;            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<>();                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 {                    //通过 load 方法  最终会调用 servlet的init方法                    wrapper.load();                } catch (ServletException e) {                    getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",                          getName(), wrapper.getName()), StandardWrapper.getRootCause(e));                    // NOTE: load errors (including a servlet that throws                    // UnavailableException from the init() method) are NOT                    // fatal to application startup                    // unless failCtxIfServletStartFails="true" is specified                    if(getComputedFailCtxIfServletStartFails()) {                        return false;                    }                }            }        }        return true;     }

看完上述内容,你们掌握怎么在tomcat中调用Servlet实现初始化的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网精选频道,感谢各位的阅读!

--结束END--

本文标题: 怎么在tomcat中调用Servlet实现初始化

本文链接: https://www.lsjlt.com/news/275609.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么在tomcat中调用Servlet实现初始化
    怎么在tomcat中调用Servlet实现初始化?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、代码启动tomcat平常我们不论是Windows还是linux,我们都是通过脚...
    99+
    2023-06-14
  • 详解从源码分析tomcat如何调用Servlet的初始化
    目录引言一、代码启动tomcat二、tomcat框架三、创建容器(addWebapp())3.1 方法 调用流程图3.2 源码分析四、启动容器(tomcat.start())4.1、...
    99+
    2024-04-02
  • Java中怎么实现初始化
    Java中怎么实现初始化,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、静态块优先程序首先会执行静态块的内容,这也就有了不写main方法就跑hello wor...
    99+
    2023-06-17
  • Vue3初始化怎么调用函数
    这篇文章主要介绍“Vue3初始化怎么调用函数”,在日常操作中,相信很多人在Vue3初始化怎么调用函数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3初始化怎么调用函数”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-07-02
  • C#中怎么实现对象初始化
    本篇文章给大家分享的是有关C#中怎么实现对象初始化,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C#对象初始化器 (Object Initializers) :.NET2.0框...
    99+
    2023-06-17
  • 怎么在java中初始化数组
    这篇文章给大家介绍怎么在java中初始化数组,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. 网页开发;5. 企...
    99+
    2023-06-14
  • 怎么在CentOS中初始化服务器
    今天就跟大家聊聊有关怎么在CentOS中初始化服务器,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、挂载硬盘磁盘分区fdisk -l #查看设备,一般可以看到设备名为/dev/xv...
    99+
    2023-06-07
  • go map初始化赋值怎么实现
    在Go语言中,可以使用字面量的方式对map进行初始化赋值。以下是几种常见的map初始化赋值方法: 使用make函数创建一个空的m...
    99+
    2023-10-23
    go
  • C++11类内初始化怎么实现
    本篇内容主要讲解“C++11类内初始化怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++11类内初始化怎么实现”吧!重复的初始化代码考察下面的代码:enum LineStyle{&nb...
    99+
    2023-06-19
  • jQuery中如何实现Chosen通用初始化
    小编给大家分享一下jQuery中如何实现Chosen通用初始化,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!no_results...
    99+
    2024-04-02
  • 怎么在python中对defaultdict进行初始化
    怎么在python中对defaultdict进行初始化?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动性...
    99+
    2023-06-14
  • 怎么在python中初始化进程池Pool
    本篇文章为大家展示了怎么在python中初始化进程池Pool,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、lo...
    99+
    2023-06-14
  • 怎么在Java中动态初始化数组
    怎么在Java中动态初始化数组?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户...
    99+
    2023-06-14
  • 怎么在Java中初始化二维数组
    今天就跟大家聊聊有关怎么在Java中初始化二维数组,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;...
    99+
    2023-06-14
  • java初始化数组为空怎么实现
    在Java中,可以使用null来表示一个空数组。以下是一种初始化数组为空的方法: 声明一个数组变量,但不分配内存空间。 使用nul...
    99+
    2023-10-27
    java
  • Java数组怎么实现动态初始化
    这篇文章主要讲解了“Java数组怎么实现动态初始化”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java数组怎么实现动态初始化”吧!概念1、数组动态初始化只给定数组长度,系统默认初始化值。2...
    99+
    2023-06-30
  • ASP.NET Core中间件初始化的实现
    目录前言  自定义的方式 Use方式 基于约定的方式 实现IMiddleware的方式 源码探究 Use扩展方法 UseMiddleware 总结 前言  ...
    99+
    2024-04-02
  • C#中怎么初始化变量
    这篇文章将为大家详细讲解有关C#中怎么初始化变量,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C#变量初始化的操作中有两个方法可确保变量在使用前进行了初始化:◆变量是类或结构中的字段,如果没...
    99+
    2023-06-17
  • 怎么在Python中利用for循环初始化数组
    这篇文章给大家介绍怎么在Python中利用for循环初始化数组,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动性和面向对象的脚本语言,其最初的设计...
    99+
    2023-06-14
  • VB.NET中怎么初始化数组
    本篇文章给大家分享的是有关VB.NET中怎么初始化数组,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。VB.NET数组初始化在任何编程语言中都很重要。VB.NET与其它语言相似,...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作