精华内容
下载资源
问答
  • 开学之前需要自己完成JavaWeb的环境搭建,搭建过程中,遇到了些许麻烦,索性按照步骤和向老师求助最终完成任务,接下来总结一些我搭建环境的过程中的实施过程和些许心得,帮助那些还没有搭建完成或是有需要的...

    开学之前需要自己完成JavaWeb的环境搭建,在搭建过程中,遇到了些许麻烦,索性按照步骤和向老师求助最终完成任务,接下来总结一些我在搭建环境的过程中的实施过程和些许心得,帮助那些还没有搭建完成或是有需要的同志们排雷,减少出错几率。

    一、前提说明

    面向对象程序设计课程是基于Java的可视化开发环境,这里我们选用Eclipse集成开发环境。在这个过程中,我们需要先下载java JDK和Eclipse来支撑开发的基本环境。

    本文以jdk-8u191-windows-x64和eclipse-jee-oxygen-2-win32-x86_64为例。

    二、环境配置

    (一)Java:JDK安装和环境配置

    (1)JDK下载地址

    https://www.oracle.com/java/technologies/javase-jdk8-downloads.html

    注意:此处我们下载Java8版本即可,目前最高版本是Java13,但是不建议使用最新版本,因为网上一些早期版本集成环境并不支持最新版本,如果在借鉴网络上的代码时也会遇到库函数或是语法问题。

    d945063750cee9a33bbb2e359a2b857d.png

    其中x86针对32位操作系统,x64针对64位操作系统;此处32位并不是不能在64位机子上使用,而是会放到一个叫做program(86)

    的文件夹,其后也要下载对应32位版本的eclipse。

    接下来如图所示:

    e4915e62aa38c70fa756b0c017be7cec.png

    这里要注意选择接受协议。

    bd50fa42924458b630594403befccb75.png

    (2)JDK安装,以java1.8为例

    打开下载好的JDK安装文件,直接默认安装即可,安装过程中可以修改JDK安装地址。

    94826c4a885202d6b68e852bb430ce79.png

    66fd82489f774ce9de030094b7fa99c9.png

    4dc6fd3ceefae7b176d05453259dc922.png

    点击确定,安装。

    86febd1b96e42a21092feb2695f2a5d0.png

    点击下一步,显示安装进度。

    d6bf60f94f11b301b2805a0d43068aa1.png

    1c392f936fd8f5cf9d9fd16dbe5c9b5e.png

    安装完成,点击关闭。

    (二)Eclipse的下载安装

    (1)Eclipse下载地址:

    https://www.eclipse.org/downloads/packages/

    这里主要是用于Java web开发,所有我们选择Java EE

    ed44a17feb3a7a030de8bc85e91db24e.png

    或是在右侧找到早期版本进行下载

    194a8fe986e4fac043f75c9ce389785a.png

    (2)Eclipse下载安装:

    在Eclipse下载页选择右侧正确的系统类型后(右击计算机,选择属性,可以查看电脑的系统类型是32位还是64位),直接下载到电脑,解压到电脑盘中即可。

    b6a66933a29ab83505198d3c60ac6f13.png

    选择使用的版本 eclipse-jee-oxygen-2-win32-x86_64,进入相应的文件夹

    c45363c4d6f7eeb03ea7527371fb7cc2.png

    双击eclipse 图标,显示设置目录,指定工程目录。

    495ccffe6a7dd8a32c49067ffb7aec83.png

    等待片刻,出现如下图示,第一次打开时间会稍长。

    e10fc7ecc770b8a6df27f85def4aea99.png

    成功则出现如下界面,若打开不成功请检查JDK的安装。

    37d721a106e117b6266858c96e59d327.png

    点击WorkBench,进入编辑工作窗口。

    bd5abfcabccd0ef5a6e9852ada079abe.png

    以上这些,只要按照步骤来做,一般情况下是不会出错的。

    **

    (三)基于Tomcat的Web开发需要配置环境变量

    **

    前面的Java+eclipse集成开发环境配置是不需要配置环境变量的,但是要实现Web开发就需要配置环境变量。

    (1)Java环境配置

    基于Tomcat的Web开发需要配置环境变量(也有的版本不需要,网上也有免搭建环境的),由于配置环境有利于深入理解TOmcat的运行原理以及Web开发,所以这里详细描述一下。

    在计算机属性中,选择左上方的“高级系统设置”,并在弹出框中选择“高级”,下方列表中会有“环境变量”选项,点击“环境变量”,弹出环境变量设置的窗口。

    环境变量中我们主要是在系统变量里面配置java环境,首先我们在系统变量中选择“Path”变量,点击编辑(或双击该变量),在编辑窗中新增java“bin”路径和使用的jre 路径,如下所示:

    C:\Program Files\Java\jdk1.8.0_191\bin;

    C:\Program Files\Java\jre1.8.0_191\bin;

    (注意哦:这里的应该是你的真实的路径,具体放在哪里看你盘符的具体情况,这里只是个例子)

    接下来在系统变量中新建一个CLASSPATH变量,点击新建,在新建系统变量弹出框中变更名处输入“CLASSPATH”,在变量值中输入java中lib目录下的tools.jar和dt.jar路径,如下所示:

    .; (此处不能省略)

    C:\Program Files\Java\jdk1.7.0_05\lib\tools.jar;

    C:\Program Files\Java\jdk1.7.0_05\lib\dt.jar;

    (注:地址前或地址最后必须有“.;”,其中“.”表示各目录的根目录)

    验证环境变量配置是否成功:进入cmd键入java ,出现如下界面

    50d3831175c437126810cb54a769a185.png

    然后输入“javac“,回车,会出现如下图所示内容:

    ba6f53659d55f2db5861d212d7573302.png

    上面两个界面均出现说明Java配置成功!!!!

    注意: 一定注意使用英文的输入法,win 10 系统可能在配置classpath时会出问题,将JAVA_HOME换成绝对路径试一下。若是打不开命令行,可将下列语句拷贝入文件,存为cmdhere.reg;然后双击该文件,加载注册表可在桌面点击右键出现cmdhere 弹出菜单。

    REGEDIT4

    [HKEY_CLASSES_ROOT*\shell\cmdhere]

    @=“Cmd&Here”

    [HKEY_CLASSES_ROOT*\shell\cmdhere\command]

    @=“cmd.exe /c start cmd.exe /k pushd “%L\…””

    [HKEY_CLASSES_ROOT\Folder\shell\cmdhere]

    @=“Cmd&Here”

    [HKEY_CLASSES_ROOT\Folder\shell\cmdhere\command]

    @=“cmd.exe /c start cmd.exe /k pushd “%L””

    以上配置是Java开发的基本路径配置;若想进行web开发除了以上配置之外,还需为TOMCAT配置下面的环境变量

    新建变量JAVA_HOME

    其值为:C:\Program Files\Java\jdk1.7.0_05 (后面不要分号;)

    新建变量JRE_HOME

    其值为:C:\Program Files\Java\jre7 (后面不要分号;)

    如果不配置 则会出现以下提示:

    cae81cd288c6ec4b68a9e6d2ac91f43c.png

    (2)Tomcat环境配置(Tomcat9.0.8)

    Tomcat下载地址:https://tomcat.apache.org/download-90.cgi

    建议下载免安装版apache-tomcat- .zip

    ee0405076f0f4e30143ab014ca2203ec.png

    注意版本要和自己的JDK匹配,也要和操作系统匹配

    8def040a2e2644eba3eae5212bdad86f.png

    b71b4b8482c4b696c588c590b4c33107.png

    b1b09387c1e3d38403d74c04c7a804d4.png

    选择合适版本下载即可。

    Tomcat环境变量配置:

    1)在计算机属性中,选择左上方的“高级系统设置”,并在弹出框中选择“高级”,下方列表中会有“环境变量”选项,点击“环境变量”,弹出环境变量设置的窗口。

    2)环境变量主要是配合Eclipse中的windows—>perferences下Tomcat的路径方便使用。

    ①我们在系统变量中选择系统变量path,然后点击编辑(也可以双击path),在弹出框的变量值中输入Tomcat的bin路径:

    J:\Tools\apache-tomcat-9.0.8\bin;

    选中系统变量CLASSPATH,添加Tomcat中servlet-api.jar路径:J:\Tools\apache-tomcat-9.0.8\lib\servlet-api.jar;

    ②创建两个新的系统变量 CATALINA_BASE其值为(Tomcat的安装路径或工作路径)(原来是用的是 TOMCAT-home,在Tomcat 4 以后,采用了新的Servlet容器Catalina,所以环境变量的名字也改为了CATALINA_HOME。)

    J:\Tools\apache-tomcat-9.0.8(后面不要分号;)

    CATALINA_HOME,变量值为(必须是Tomcat的安装路径) J:\Tools\apache-tomcat-9.0.8 (后面不要分号;)

    ③在Tomcat安装目录下bin文件中找到startup.bat双击,启动Tomcat服务器(这个我当初在bin目录下只找到了startup并双击了它,没有找到有后缀的)

    记住,添加完路径之后一定要将其保存,保存,保存!!!

    ④打开浏览器,在地址栏输入: http://localhost:8080(或http://127.0.0.1:8080),

    如果打开页面如下图所示时,则表示Tomcat环境配置完成。

    7a61a6a96cba3e5400e5452b8c605841.png

    如果你没有对你的路径进行保存就出不来(我当初就是没有保存,怎么着都出不来,但是发现路径和安装的什么的都没有错误,最后问老师才知道原来是路径没有保存,这是血的教训!!!!)

    如果出现闪退,请到安装目录查看日志文件。

    47ada735df6c66bb11a54f2141b0060d.png

    三、Eclipse中web开发的基本设置

    (一)Eclipse中Tomcat环境配置

    1)打开Eclipse,选择Window—>perferences,在弹出的框中选择左侧的Server目录下的Runtime Environments,如下图所示:

    a96e12d5e91fcef2693eaba756a2982e.png 2)在弹出框选择右侧的Add,然后在Apache目录下选择安装的Tomcat版本,这里选择Apache Tomcat9.0,如下图所示:

    851683fc749192722613deb809cf4796.png

    点击Next,在弹窗中设置apache-tomcat-9.0.8的安装路径(点击Browse,选择安装文件夹),并在下方选择安装的jdk版本,如下图所示:

    318d0c3850195bd8507ff776ce3fd79c.png

    点击Finish完成Runtime Evironments配置,点击ok,完成Tomcat的基本配置。

    (二)运行HelloWorld!

    (1)创建Web工程

    选择File—>New—>Other,在弹出框中选择Web—>Dynamic Web Project,点击Next,弹出工程创建页面,在Project name中输入HelloWorld,然后点击Finish,完成HelloWorld工程创建。

    35660471feaa3a9b9ac665ab0f9e5ab8.png

    b3dcdd3dc4bf9a236644211efe38f149.png

    (2)新建index.jsp文件

    1)选中HelloWorld工程目录下的WebConnent文件夹,右击选择New—>JSP File,在弹出框的File name右侧输入index.jsp,点击Finish,完成index.jsp的创建。

    1f05dfe40d68653aa504140cabcefcd7.png

    2)双击打开index.jsp,在

    与之间输入

    Hello World ! This is my first JSP page!

    点击左上角保存。

    ae7cc2804a727ba6fa408c4dbac4935e.png

    3)选中HelloWorld工程,右击选择Run AS—>Run on Server,在弹出框中选择Server对应得Tomcat版本,点击Finish,运行HelloWorld工程。如果出现如下图所示内容,则环境配置成功。

    e2adba3175bc886db2c075837d7eb1f5.png

    大致的详细步骤就是这样子的,也不算难,就是有的地方很容易忽略,如果弄错了会非常麻烦。

    e20bfc21bf756450f2b6c2f6324cae37.png

    d1358d4695d8660de2972cc1f6e682b2.png

    super帅锅锅

    发布了5 篇原创文章 · 获赞 0 · 访问量 54

    私信

    关注

    标签:Web,Java,JDK,Tomcat,配置,Eclipse,点击,环境变量

    来源: https://blog.csdn.net/qq_45804925/article/details/104550709

    展开全文
  • intellij idea 使用Tomcat部署javaweb项目后到Tomcat的webapps目录下找不到项目. 1. 首先看下部署项目后webapps的目录 2. 首先说明怎么找到已经部署好的项目,再来解释原因. 2.1 首先点击项目,右键点击Show in...

    intellij idea 使用Tomcat部署javaweb项目后到Tomcat的webapps目录下找不到项目.

    1. 首先看下部署项目后webapps的目录
      这里写图片描述
      这里写图片描述
    2. 首先说明怎么找到已经部署好的项目,再来解释原因.
      2.1 首先点击项目,右键点击Show in Explorer.
      这里写图片描述
      2.2
      这里的项目没有使用maven,所以输出目录是out,如果是maven则是target目录中,还有可能是idea版本的问题,所以名称不同,但是都是属于输出目录.18年的文章…
      这里写图片描述
      2.3这里写图片描述
      2.4这里写图片描述
      此时部署的web项目已经找到.
    3. intellij idea使用Tomcat部署项目后并不会把编译后的项目复制到tomcat的webapps目录下,但是它会把编译好的项目路径告诉Tomcat,让Tomcat来找到这个项目,其它的项目比如Tomcat的主页项目ROOT是打不开的,因为intellij idea 只让Tomcat运行了一个项目.
      接下来看一下war包的目录结构,也就是整个web项目编译后的目录结构
      这里写图片描述
      这里写图片描述

    4.tomcat有4中部署方式,eclipse的部署方式与IntelliJ idea的部署方式不同.

    tomcat部署方式分别是:
    (1)利用Tomcat自动部署
    项目放到webapps目录下,启动tomcat,就回自动部署

    (2)利用控制台进行部署
    控制台不是说cmd,而是tomcat启动后进入root页面,有个manager管理部署项目.
    进入tomcat的manager控制台的deploy区域进行设置就可以部署

    上面这两种都是自己用的,就是平时别人发包过来,然后丢进去,启动tomcat就部署,但是开发工具没有用上面两种.

    platform-zwml-admin这个是我的项目名称

    下面的在IntelliJ idea中使用
    (3)增加自定义的Web部署文件(%Tomcat_Home%\conf\Catalina\localhost\platform-zwml-admin.xml)
    在这里插入图片描述
    下面一种都在eclipse中使用
    (4)修改%Tomcat_Home%\conf\server.xml文件来部署web应用
    在这里插入图片描述
    所以web项目不是必须放在webapps文件夹里面才能部署的,放在其它位置为也可以部署,
    eclipse默认放在工作空间的.metadata文件夹,可以修改到其它地方,一般配置在webapps文件夹.
    而idea是配置到out文件夹,就是输出目录.

    展开全文
  • 三种方法被写死在tomcat的HostConfig.java中:org/apache/catalina/startup/HostConfig.java 使用xml描述部署:在tomcat的server.xml文件中添加<context path=“name” docBase=“应用文件的路径”></...

    tomcat部署应用的三种方式

    三种方法被写死在tomcat的HostConfig.java中:org/apache/catalina/startup/HostConfig.java

    • 使用xml描述部署:在tomcat的server.xml文件中添加<context path=“name” docBase=“应用文件的路径”></context>节点
    • 使用war包部署:将一个war包放到tomcat中
    • 使用文件部署:将要部署的项目的文件夹告诉tomcat,让tomcat自己去找
       /**
         * Deploy applications for any directories or WAR files that are found
         * in our "application root" directory.
         */
        protected void deployApps() {
            // Migrate legacy Java EE apps from legacyAppBase
            migrateLegacyApps();
            File appBase = host.getAppBaseFile();
            File configBase = host.getConfigBaseFile();
            String[] filteredAppPaths = filterAppPaths(appBase.list());
            // Deploy XML descriptors from configBase
            deployDescriptors(configBase, configBase.list());
            // Deploy WARs
            deployWARs(appBase, filteredAppPaths);
            // Deploy expanded folders
            deployDirectories(appBase, filteredAppPaths);
        }
    

    tomcat四大容器

    Context是一个接口,tomcat提供了一个它的实现:StandardContext,里面有许多的Hashmap<string,String>

    Wrapper也是一个接口,Tomcat提供了一个它的实现:StandardWrapper,wrapper里面可能只有一个servlet实例,也有可能有多个,如果只有一个就将其存在 instance里面,如果有多个就放在一个Stack实现的实例池中:instancePool

        /**
         * The (single) possibly uninitialized instance of this servlet.
         */
        protected volatile Servlet instance = null;
    
        /**
         * Maximum number of STM instances.
         */
        protected int maxInstances = 20;
    
    
        /**
         * Number of instances currently loaded for a STM servlet.
         */
        protected int nInstances = 0;
    
    
        /**
         * Stack containing the STM instances.
         */
        protected Stack<Servlet> instancePool = null;
    
    
        /**
    

    Host也是一个接口,tomcat提供了StandardHost实现类,

    Engine也是一个接口,tomcat提供了StandardEngine实现类,

    Pipeline是tomcat提供的一个组件,PipeLine中存储这许多valve(阀门), Pipeline–Valve是一种责任链模式,它和普通责任链模式有两点区别:

    • 每个Pipeline都是有特定的Valve,而且是在管道的最后一个执行,这个Valve叫BaseValve,并且BaseValve是不可删除的;
    • 在上层容器的管道的BaseValve中会调用下层容器的管道。
    • "容器的 过滤器”
    // 在standardWrapper构造器中就将最后一个wrapper写死:使用StandardWrapperValve
    
        /**
         * Create a new StandardWrapper component with the default basic Valve.
         */
        public StandardWrapper() {
    
            super();
            swValve=new StandardWrapperValve();
            pipeline.setBasic(swValve);
            broadcaster = new NotificationBroadcasterSupport();
    
        }
    
    

    Engine 组件

    Engine 是 Servlet 处理器的一个实例,即 Servlet 引擎,定义在 server.xml 中的 Service 标记中。Engine 需要 defaultHost 属性来为其定义一个接收所有发往非明确定义虚拟主机的请求的 host 组件。

    <Engine name="Catalina" defaultHost="localhost">
    

    name:Engine 组件的名称;
    defaultHost:Tomcat 支持基于 FQDN(Fully Qualified Domain Name 全限定域名)的虚拟主机,这些虚拟主机可以通过在 Engine 容器中定义多个不同的 Host 组件来实现;但如果此引擎的连接器收到一个发往非明确定义虚拟主机的请求时则需要将此请求发往一个默认的虚拟主机进行处理,因此,在 Engine 中定义的多个虚拟主机的主机名称中至少要有一个跟 defaultHost 定义的主机名称同名;

    Host 组件

    位于 Engine 容器中用于接收请求并进行相应处理的虚拟主机。通过该容器可以运行 Servlet 或者 JSP 来处理请求。

    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
    

    name:虚拟主机的名称,Tomcat 通过在请求 URL 中的域名与 name 中的值匹配,用于查找能够处理该请求的虚拟主机。如果未找到则交给在 Engine 中 defaultHost 指定的主机处理;
    appBase:此 Host 的 webapps目录,即指定存放 web 应用程序的目录的路径,默认指向 ROOT 目录下的 index.jsp;
    unpackWARs:在启用此 webapps 时是否对 WAR 格式的归档文件先进行展开;默认为 true;
    autoDeploy:在 Tomcat 处于运行状态时放置于 appBase 目录中的应用程序文件是否自动进行 部署,默认为 true;

    Context 组件

    Context 是 Host 的子标签,代表指定一个 Web 应用,它运行在某个指定的虚拟主机(Host) 上;每个 Web 应用都是一个 WAR 文件,或文件的目录;server.xml 配置中没有配置 Context 属性,默认支持运行多个项目。

    <Context path="/test" docBase="D:\bjsxt\itbaizhan.war"/> 
    

    path:context path 既浏览器访问项目的访问路径。
    docBase:相应的 Web 应用程序的存放位置;也可以使用相对路径,起始路径为此 Context 所属 Host 中 appBase 定义的路径;

    doGet方法在哪里调用

    总的来说Valve其实就是过滤器,在dorequest前后都执行filter方法。

    我们要将用户发过来的请求:request,wrapper,servlet一起创建filterChain,他会将doRequest等方法嵌入到filterChain中

     // Create the filter chain for this request 
    ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    
    

    **filterchain主要调用dofilter方法, 在filterChain.dofilter中,它主要执行这个方法:internalDoFilter(req,res); 在这个方法中,它首先会执行过滤操作,在做完过滤操作后,会调用传进来的Httpservlet的service()方法,在service方法中调用servlet的doGet()方法,也就是我们实现的doGet方法!!! **

    所以我们自己重写的doGet,doPost等,都与tomcat无关,他们的调用都是在servlet的service()方法中,tomcat只不过是使用了servlet封装好的service方法!! 当tomcat调用了Http.service(),由servlet规范自己去判断掉doGet还是doPost.

    • filterchain.dofilter():它将请求和响应传进去,request.getRequest(),和response.getResponse()都会返回一个facade,这是一个门面模式,

      filterChain.doFilter(request.getRequest(), response.getResponse());
      
         /**
           * @return the <code>ServletRequest</code> for which this object
           * is the facade.  This method must be implemented by a subclass.
           */
          public HttpServletRequest getRequest() {
              if (facade == null) {
                  facade = new RequestFacade(this);
              }
              if (applicationRequest == null) {
                  applicationRequest = facade;
              }
              return applicationRequest;
          }
      

    internalDoFilter(req, rep)

       private void internalDoFilter(ServletRequest request,
                                      ServletResponse response)
            throws IOException, ServletException {
    
            // Call the next filter if there is one
            if (pos < n) {
                ApplicationFilterConfig filterConfig = filters[pos++];
                try {
                    Filter filter = filterConfig.getFilter();
    
                    if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                            filterConfig.getFilterDef().getAsyncSupported())) {
                        request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                    }
                    if( Globals.IS_SECURITY_ENABLED ) {
                        final ServletRequest req = request;
                        final ServletResponse res = response;
                        Principal principal =
                            ((HttpServletRequest) req).getUserPrincipal();
    
                        Object[] args = new Object[]{req, res, this};
                        SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
                    } else {
                        filter.doFilter(request, response, this);
                    }
                } catch (IOException | ServletException | RuntimeException e) {
                    throw e;
                } catch (Throwable e) {
                    e = ExceptionUtils.unwrapInvocationTargetException(e);
                    ExceptionUtils.handleThrowable(e);
                    throw new ServletException(sm.getString("filterChain.filter"), e);
                }
                return;
            }
    
            // We fell off the end of the chain -- call the servlet instance
            try {
                if (dispatcherWrapsSameObject) {
                    lastServicedRequest.set(request);
                    lastServicedResponse.set(response);
                }
    
                if (request.isAsyncSupported() && !servletSupportsAsync) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                // Use potentially wrapped request from this point
                if ((request instanceof HttpServletRequest) &&
                        (response instanceof HttpServletResponse) &&
                        Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                        ((HttpServletRequest) req).getUserPrincipal();
                    Object[] args = new Object[]{req, res};
                    SecurityUtil.doAsPrivilege("service",
                                               servlet,
                                               classTypeUsedInService,
                                               args,
                                               principal);
                } else {
                    servlet.service(request, response);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
                if (dispatcherWrapsSameObject) {
                    lastServicedRequest.set(null);
                    lastServicedResponse.set(null);
                }
            }
        }
    

    connector组件与Http11NioProtocol类

    tomcat会使用connector组件来处理连接

        <!--The connectors can use a shared executor, you can define one or more named thread pools-->
        <!--
        <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
            maxThreads="150" minSpareThreads="4"/>
        -->
    
    
        <!-- A "Connector" represents an endpoint by which requests are received
             and responses are returned. Documentation at :
             Java HTTP Connector: /docs/config/http.html
             Java AJP  Connector: /docs/config/ajp.html
             APR (HTTP/AJP) Connector: /docs/apr.html
             Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
        -->
        <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
        <!-- A "Connector" using the shared thread pool-->
        <!--
        <Connector executor="tomcatThreadPool"
                   port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
        -->
        <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443
             This connector uses the NIO implementation. The default
             SSLImplementation will depend on the presence of the APR/native
             library and the useOpenSSL attribute of the
             AprLifecycleListener.
             Either JSSE or OpenSSL style configuration may be used regardless of
             the SSLImplementation selected. JSSE style configuration is used below.
        -->
        <!--
        <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
                   maxThreads="150" SSLEnabled="true">
            <SSLHostConfig>
                <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                             type="RSA" />
            </SSLHostConfig>
        </Connector>
        -->
        <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
             This connector uses the APR/native implementation which always uses
             OpenSSL for TLS.
             Either JSSE or OpenSSL style configuration may be used. OpenSSL style
             configuration is used below.
        -->
        <!--
        <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
                   maxThreads="150" SSLEnabled="true" >
            <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
            <SSLHostConfig>
                <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                             certificateFile="conf/localhost-rsa-cert.pem"
                             certificateChainFile="conf/localhost-rsa-chain.pem"
                             type="RSA" />
            </SSLHostConfig>
        </Connector>
        -->
    
        <!-- Define an AJP 1.3 Connector on port 8009 -->
        <!--
        <Connector protocol="AJP/1.3"
                   address="::1"
                   port="8009"
                   redirectPort="8443" />
        -->
    

    当我们在xml中配置了connector后,会创建一个connector对象,如下为connector的构造器:

    public Connector(String protocol) {
            configuredProtocol = protocol;
            ProtocolHandler p = null;
            try {
                p = ProtocolHandler.create(protocol);
            } catch (Exception e) {
                log.error(sm.getString(
                        "coyoteConnector.protocolHandlerInstantiationFailed"), e);
            }
            if (p != null) {
                protocolHandler = p;
                protocolHandlerClassName = protocolHandler.getClass().getName();
            } else {
                protocolHandler = null;
                protocolHandlerClassName = protocol;
            }
            // Default for Connector depends on this system property
            setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));
        }
    
    
    
    public static ProtocolHandler create(String protocol)
                throws ClassNotFoundException, InstantiationException, IllegalAccessException,
                IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
            
    if (protocol == null || "HTTP/1.1".equals(protocol) || org.apache.coyote.http11.Http11NioProtocol.class.getName().equals(protocol)) {
    return new org.apache.coyote.http11.Http11NioProtocol();} 
                  
    else if ("AJP/1.3".equals(protocol)|| org.apache.coyote.ajp.AjpNioProtocol.class.getName().equals(protocol)) {
                return new org.apache.coyote.ajp.AjpNioProtocol();}
                  
    else {
    	// Instantiate protocol handler
    	Class<?> clazz = Class.forName(protocol);
    	return (ProtocolHandler) clazz.getConstructor().newInstance();
            }
        }
    

    在构造器中,会调用ProtocolHandler.creat(),来解析我们xml的配置,判断HTTP/1.1

    还是 AJP/1.3协议,还是自己实现的协议。

    • 如果使用HTTP/1.1协议:它会创建Http11NioProtocol类,作为protocolHandler 来处理连接,这里默认使用NIO。
    • 如果使用 AJP/1.3协议: 它会创建AjpNioProtocol类,作为protocolHandler来处理连接
    • 如果是自定义的协议,首先你要实现一个处理自定协议的类,然后将自定义协议名配置在server.xml 文件中,它首先会获取你xml温江中协议类名,然后用反射加载这个协议对应的处理类,并将这个类返回,作为protocolHandler 来处理连接。

    Nioendpiont

    查看Http11NioProtocol构造器,发现,里面有一个类:Nioendpiont

     public Http11NioProtocol() {
            super(new NioEndpoint());
        }
    
    public AbstractHttp11Protocol(AbstractEndpoint<S,?> endpoint) {
            super(endpoint);
            setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
            ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
            setHandler(cHandler);
            getEndpoint().setHandler(cHandler);
        }
    
        public AbstractProtocol(AbstractEndpoint<S,?> endpoint) {
            this.endpoint = endpoint;
            setConnectionLinger(Constants.DEFAULT_CONNECTION_LINGER);
            setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
        }
    
     /**
         * Start the NIO endpoint, creating acceptor, poller threads.
         */
        @Override
        public void startInternal() throws Exception {
    
            if (!running) {
                running = true;
                paused = false;
    
                if (socketProperties.getProcessorCache() != 0) {
                    processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            socketProperties.getProcessorCache());
                }
                if (socketProperties.getEventCache() != 0) {
                    eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            socketProperties.getEventCache());
                }
                int actualBufferPool =
                        socketProperties.getActualBufferPool(isSSLEnabled() ? getSniParseLimit() * 2 : 0);
                if (actualBufferPool != 0) {
                    nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            actualBufferPool);
                }
    
                // Create worker collection
                if (getExecutor() == null) {
                    createExecutor();
                }
    
                initializeConnectionLatch();
    
                // Start poller thread
                poller = new Poller();
                Thread pollerThread = new Thread(poller, getName() + "-Poller");
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
    
                startAcceptorThread();
            }
        }
    
     protected void startAcceptorThread() {
            acceptor = new Acceptor<>(this);
            String threadName = getName() + "-Acceptor";
            acceptor.setThreadName(threadName);
            Thread t = new Thread(acceptor, threadName);
            t.setPriority(getAcceptorThreadPriority());
            t.setDaemon(getDaemon());
            t.start();
        }
    

    createExecutor(); 会创建一个线程池,startAcceptorThread() 会将Acceptor以守护线程在线程池中启动,

    acceptor

    从上面代码,启动endpoint的时候,会创建一个acceptor的类:

    acceptor它是接收请求的接收器,它继承了Runnable接口,说明它可以是一个单独的线程,既然是runnable,我们肯定要关心run()方法,里面是一个循环,一直循环使endpoint从socket中取数据:endpoint.serverSocketAccept()

       public void run() {
    
            int errorDelay = 0;
    
            try {
                // Loop until we receive a shutdown command
                while (!stopCalled) {
    
                    // Loop if endpoint is paused
                    while (endpoint.isPaused() && !stopCalled) {
                        state = AcceptorState.PAUSED;
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
    
                    if (stopCalled) {
                        break;
                    }
                    state = AcceptorState.RUNNING;
    
                    try {
                        //if we have reached max connections, wait
                        endpoint.countUpOrAwaitConnection();
    
                        // Endpoint might have been paused while waiting for latch
                        // If that is the case, don't accept new connections
                        if (endpoint.isPaused()) {
                            continue;
                        }
    
                        U socket = null;
                        try {
                            // Accept the next incoming connection from the server
                            // socket
                            socket = endpoint.serverSocketAccept();
                        } catch (Exception ioe) {
                            // We didn't get a socket
                            endpoint.countDownConnection();
                            if (endpoint.isRunning()) {
                                // Introduce delay if necessary
                                errorDelay = handleExceptionWithDelay(errorDelay);
                                // re-throw
                                throw ioe;
                            } else {
                                break;
                            }
                        }
                        // Successful accept, reset the error delay
                        errorDelay = 0;
    
                        // Configure the socket
                        if (!stopCalled && !endpoint.isPaused()) {
                            // setSocketOptions() will hand the socket off to
                            // an appropriate processor if successful
                            if (!endpoint.setSocketOptions(socket)) {
                                endpoint.closeSocket(socket);
                            }
                        } else {
                            endpoint.destroySocket(socket);
                        }
                    } catch (Throwable t) {
                        ExceptionUtils.handleThrowable(t);
                        String msg = sm.getString("endpoint.accept.fail");
                        // APR specific.
                        // Could push this down but not sure it is worth the trouble.
                        if (t instanceof Error) {
                            Error e = (Error) t;
                            if (e.getError() == 233) {
                                // Not an error on HP-UX so log as a warning
                                // so it can be filtered out on that platform
                                // See bug 50273
                                log.warn(msg, t);
                            } else {
                                log.error(msg, t);
                            }
                        } else {
                                log.error(msg, t);
                        }
                    }
                }
            } finally {
                stopLatch.countDown();
            }
            state = AcceptorState.ENDED;
        }
    
    

    endpoint.serverSocketAccept() 方法会调用 ServerSocketChannelImpl的accept()方法:

        public SocketChannel accept() throws IOException {
            synchronized(this.lock) {
                if (!this.isOpen()) {
                    throw new ClosedChannelException();
                } else if (!this.isBound()) {
                    throw new NotYetBoundException();
                } else {
                    SocketChannelImpl var2 = null;
                    int var3 = 0;
                    FileDescriptor var4 = new FileDescriptor();
                    InetSocketAddress[] var5 = new InetSocketAddress[1];
    
                    InetSocketAddress var6;
                    try {
                        this.begin();
                        if (!this.isOpen()) {
                            var6 = null;
                            return var6;
                        }
    
                        this.thread = NativeThread.current();
    
                        do {
                            var3 = this.accept(this.fd, var4, var5);
                        } while(var3 == -3 && this.isOpen());
                    } finally {
                        this.thread = 0L;
                        this.end(var3 > 0);
    
                        assert IOStatus.check(var3);
    
                    }
    
                    if (var3 < 1) {
                        return null;
                    } else {
                        IOUtil.configureBlocking(var4, true);
                        var6 = var5[0];
                        var2 = new SocketChannelImpl(this.provider(), var4, var6);
                        SecurityManager var7 = System.getSecurityManager();
                        if (var7 != null) {
                            try {
                                var7.checkAccept(var6.getAddress().getHostAddress(), var6.getPort());
                            } catch (SecurityException var13) {
                                var2.close();
                                throw var13;
                            }
                        }
    
                        return var2;
                    }
                }
            }
        }
    

    最后会调用这个方法:this.accept(this.fd, var4, var5);

        private int accept(FileDescriptor var1, FileDescriptor var2, InetSocketAddress[] var3) throws IOException {
            return this.accept0(var1, var2, var3);
        }
    
        private native int accept0(FileDescriptor var1, FileDescriptor var2, InetSocketAddress[] var3) throws IOException;
    

    最终调用我们熟悉的accept0 方法!!!

    tomcat实现自定义加载类

    tomcat就打破了双亲委派,因为tomact要隔离jar包。tomcat是个web容器,一个web容器可能要部署两个或者多个应用程序,不同的应用程序,因此要保证每一个应用程序的类库都是独立、相互隔离的。所有应用都在一个容器上跑,同一个内存,同一个JVM,但不同的应用要用到的类可能版本不同,使用双亲委派的话就无法保证每一个应用程序的类库都是独立、相互隔离的。

    WebappClassLoader

    tomcat实现了一个webappclassloader类,每一个web应用都new一个webappclassloader的实例,我们知道在JVM中,以全限定类名+加载器名来标示一个类,所以类加载实力不同,就算加载的是同一个类,JVM也认为他们不相等。WebappClassLoader应该负责的目录应该是:WEB-INF下的lib 和 classes。 当然如果想要他加载其他额外的目录也是可以的。

    webappClassLoader的父加载器就是commonClassLoader,它继承于WebappClassLoaderBase,而WebappClassLoaderBase继承URLClassLoader.

    commonClassLoader

    同时tomcat还实现了commonClassLoader类,用来加载tomcat要依赖的jar包,应用程序的类就使用webAppClassLoader来加载,tomcat的核心依赖类使用commonClassLoader来加载,这样就避免了tomcat依赖的类的冲突。

    commonClassLoader的父加载器就是AppClassLoader

    URLClassLoader

    URLClassLoader 是JDK提供的一个类,它用于指定一个类的路径:可以是目录,可以是文件,可以是远程的jar包。这样tomcat的WebappClassLoader就可以按照指定的目录加载类了。

    tomcat 加载类的过程

    当tomcat要加载类web应用的某个类时,使用WebappClassloader加载该类,WebappClassloader会调用它父类WebappClassloaderBase的loadClass()方法,

    1. 首先调用tomcat实现的findLoadedClass0() 方法,查找该类是否被tomcat加载过了,找到了直接返回
    2. 如果没找到,调用JDK的findLoadedClass0()方法,查找该类是否被JDK加载过了,找到了直接返回
    3. 如果没有找到,会判断该类是否以java.*开头的类,如果是,则让BootstrapClassLoader加载
    4. 如果不是,根据delegate(是否委派)属性是true还是false,来加载该类。默认是False,可以修改
    5. 如果为true,说明该次加载使用委派模式,先由它的父加载器commonClassLoader 来加载,如果commonClassLoader不能加载则使用WebappClassloader来加载, 如果两个都不能加载,就抛出异常
    6. 如果为False,说明该次加载不使用委派模式,先由自己加载,如果自己加载不了,在使用父加载器加载。两个都加载不了就抛出异常。

    resolveClass(clazz)

    加载的具体类为:resolveClass(clazz),Tomcat具体加载类的方法也是这个,由JDK提供的。因为Tomcat自定义的类也是继承了JDK的ClassLoader。如果resolveClass() 方法tomcat也自己实现的话那继承ClassLoader就没什么意义了。

    resolveClass(clazz)方法调用的是resolveClass0(clazz) 方法,是一个native方法。

    tomcat 实现的findLoadedClass0()

    tomcat 自己实现了findLoadedClass0(), 它用来寻找该类是否被tomcat 加载过,在这个方法中维护的一个ConcurrentHashMap: Map<String, ResourceEntry>。 String 是类的ID, ResourceEntry是{long lastModified , Class<?> loadedClass}。

    这样的一个ConcurrentHashMap 就起到了缓存的作用。

    JDK 的findLoadedClass0()

    JDK的findLoadedClass0()毫无疑问调用的是本地方法findLoadedClass0().

    tomcat热加载

    热加载与热部署不同,当一个类发生修改,tomcat会自动重新加载这个类,但是添加一个新类不会,因为加载时按需加载的,只有需要才会加载。在serve.xml 文件的context节点 将reloader设置为true就开启了热加载。

    在WebappLoader类中,有backgroundProcess():

        /**
         * Execute a periodic task, such as reloading, etc. This method will be
         * invoked inside the classloading context of this container. Unexpected
         * throwables will be caught and logged.
         */
        @Override
        public void backgroundProcess() {
            Context context = getContext();
            if (context != null) {
                if (context.getReloadable() && modified()) {//判断这个context是否设置了reload=true,并且该类是否发生了改变
                    ClassLoader originalTccl = Thread.currentThread().getContextClassLoader();
                    try {
                        Thread.currentThread().setContextClassLoader(WebappLoader.class.getClassLoader());
                        context.reload();
                    } finally {
                        Thread.currentThread().setContextClassLoader(originalTccl);
                    }
                }
            }
        }
    

    modified() 判断文件是否改变,它不会一个一个的去比较文件的内容,而是比较上一次修改的时间。

    展开全文
  • tomcat server options 在哪里

    千次阅读 2016-02-23 16:14:20
    tomcat server options 在哪里? 答:在ECLIPSE中双击配置好的TOMCAT服务器,即出现tomcat server配置页。

    tomcat server options 在哪里?


    答:在ECLIPSE中双击配置好的TOMCAT服务器,即出现tomcat server配置页。


    展开全文
  • tomcat8在哪里配置websocket的参数,在哪个文件中呢,我要配置org.apache.tomcat.websocket.executorMaxSize这个参数,来修改websocket的最大连接数.另外有没有人测试过tomcat能够支持的websocket最大连接数是多少,谢谢
  • 一、Tomcat数据库连接池配置1、Tomcat5.5的安装程序默认是没有管理(Admin)模块的,所以要先在Tomcat网站上下载最新的admin模块包(apache-tomcat-5.5.26-admin.zip)2、下载后将解压出来的文件copy到tomcat安装目录下...
  • 手动起tomcat ,可以输出log日志文件。 idea启动tomcat 却找不到日志文件,也没有追加到之前的log日志里。 是输出到别的位置了还是根本不会输出啊? 小白求助。。。
  • tomcat目录下的logs文件夹下。有个catalina.20xx-xx-xx.log 转载于:https://www.cnblogs.com/shizhijie/p/7567634.html
  • 路径:server/framework/runtime/tomcat/bin 当server 没启动成,重启也还没成。就要检查这个位置,重启 ./shutdown.sh ./startup.sh
  • MyEclipse启动tomcat在哪里?MyEclipse8.5 [quote] tomcat增加内存在catalina.bat下 在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx...
  • intellij idea 使用Tomcat部署javaweb项目后到Tomcat的webapps目录下找不到项目. 首先看下部署项目后webapps的目录 首先说明怎么找到已经部署好的项目,再来解释原因. 2.1 首先点击项目,右键点击S...
  • 但是有一点说错了,第4.3 IntelliJ idea中使用 增加自定义的Web部署文件(%Tomcat_Home%\conf\Catalina\localhost\platform-zwml-admin.xml) 这个路径不是%Tomcat_Home% 应该是 C:\Users\Administrator\AppData...
  • tomcat接收一个请求后,这个请求就会在容器间流动,最后肯定tomcat要返回结果给用户,请问返回结果是在哪段程序里进行的呢?...我现在是想在源码段记录tomcat处理每个请求的时间,不知道该在哪里截取endTime。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,123
精华内容 449
关键字:

tomcat在哪里