精华内容
下载资源
问答
  • Tomcat

    2021-06-10 16:41:45
    一、Tomcat服务器简介 Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。 一般来说,Tomcat虽然和...

    一、Tomcat服务器简介

    Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。
    一般来说,Tomcat虽然和Apache或者Nginx这些Web服务器一样,具有处理HTML页面的功能,然而由于其处理静态HTML的能力远不及Apache或者Nginx,所以Tomcat通常是作为一个Servlet和JSP容器,单独运行在后端。

    1、Java Servlet

    运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用Servlet,可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。与CGI(公共网关接口)功能相类似。

    2、JSP全称Java Server Pages

    一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头以%>结束。 JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分。 JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。

    3、Tomcat三大核心组件

    Tomcat 由一系列的组件构成,其中核心的组件有三个

    名称功能
    Web 容器完成 Web 服务器的功能
    Servlet 容器名字为 catalina,用于处理 Servlet 代码
    JSP 容器用于将 JSP 动态网页翻译成 Servlet 代码

    二、Tomcat服务部署安装

    在部署 Tomcat 之前必须安装好 jdk,因为 jdk 是 Tomcat 运行的必要环境。

    1.关闭防火墙,将安装 Tomcat 所需软件包传到/opt目录下

    在这里插入图片描述
    在这里插入图片描述

    2.安装JDK

    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3.设置JDK环境变量

    在这里插入图片描述

    小知识
    CLASSPATH编译、运行Java程序时,JRE会去该变量指定的路径中搜索所需的类(.class)文件。
    dt.jar是关于运行环境的类库,主要是 swing 的包。
    tools.jar主要是一些jdk工具的类库,包括javac,java,javap,javadoc等。
    JDKjava development kit (java开发工具)
    JREjava runtime environment (java运行时环境)
    JVMjava virtuak machine (java虚拟机),使java程序可以在多种平台上运行class文件。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    4.安装启动Tomcat

    在这里插入图片描述
    在这里插入图片描述

    -----启动tomcat-----

    /usr/local/tomcat/bin/startup.sh 
    netstat -natp | grep 8080
    

    在这里插入图片描述

    浏览器访问Tomcat的默认主页 http://192.168.184.10:8080
    在这里插入图片描述

    5.优化tomcat启动速度

    第一次启动查看日志会发现 Tomcat 启动很慢,默认情况下可能会需要几十秒,可以修改jdk参数进行改。

    在这里插入图片描述

    -----117行修改-----

    securerandom.source=file:/dev/urandom
    
     
    • 1

    在这里插入图片描述

    在这里插入图片描述


    在这里插入图片描述

    主要目录说明
    bin存放启动和关闭 Tomcat 的脚本文件,比较常用的是 catalina.sh、startup.sh、shutdown.sh 三个文件
    conf存放 Tomcat 服务器的各种配置文件,比较常用的是 server.xml、context.xml、tomcat-users.xml、web.xml 四个文件。
    lib存放 Tomcat 服务器的 jar 包,一般不作任何改动,除非连接第三方服务,比如 redis,那就需要添加相对应的 jar 包
    logs存放 Tomcat 日志
    temp存放 Tomcat 运行时产生的文件
    webapps存放项目资源的目录
    workTomcat 工作目录,一般清除 Tomcat 缓存的时候会使用到

    三、Tomcat 虚拟主机配置

    很多时候公司会有多个项目需要运行,那么肯定不可能是一台服务器上运行多个Tomcat服务,这样会消耗太多的系统资源。此时,就需要使用到 Tomcat 虚拟主机。例如现在新增两个域名 www.lic.com 和 www.accp.com,希望通过这两个域名访问到不同的项目内容。

    1.创建 lic 和 accp 项目目录和文件

    在这里插入图片描述

    2.修改 Tomcat 主配置文件

    在这里插入图片描述

    在这里插入图片描述

    Host name主机名
    appBaseTomcat程序工作目录,相对路径为webapps,绝对路径为/usr/local/tomcat/webapps
    unpackWARs是否解压war包
    autoDeploy指示Tomcat运行时,如有新的WEB应用是否允许自动部署
    xmlValidation是否验证xml文件执行有效性检验的标志
    xmlNamespaceAware是否启用xml命名空间,设置该值与xmlValidation为true,表示对web.xml文件执行有效性检验
    appBaseWEB应用的目录
    path设置访问的URI为WEB应用的根目录
    reloadable是否在程序有改动时重新载入

    在这里插入图片描述

    3.客户端浏览器访问验证

    在这里插入图片描述

    浏览器访问 http://www.lic.com:8080 页面显示This is lic page\!
    浏览器访问 http://www.accp.com:8080 页面显示This is accp page\!

    在这里插入图片描述

    四、Tomcat 优化

    Tomcat默认安装下的缺省配置并不适合生产环境,它可能会频繁出现假死现象需要重启,只有通过不断压测优化才能让它最高效率稳定的运行。优化主要包括三方面,分别为操作系统优化(内核参数优化),Tomcat配置文件参数优化,Java虚拟机(JVM)调优。

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    Tomcat常用优化选项

    选项名称参数设定
    maxThreadsTomcat 使用线程来处理接收的每个请求,这个值表示 Tomcat 可创建的最大的线程数,默认值是 200。
    minSpareThreads最小空闲线程数,Tomcat 启动时的初始化的线程数,表示即使没有人使用也开这么多空线程等待,默认值是 10。
    maxSpareThreads最大备用线程数,一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值是-1(无限制)。一般不需要指定。
    URIEncoding指定 Tomcat 容器的 URL 编码格式,语言编码格式这块倒不如其它 Web服务器软件配置方便,需要分别指定。
    connnectionTimeout网络连接超时,单位:毫秒,设置为 0 表示永不超时,这样设置有隐患的。通常默认 20000 毫秒就可以。
    enableLookups是否反查域名,以返回远程主机的主机名,取值为:true 或 false,如果设置为 false,则直接返回 IP 地址,为了提高处理能力,应设置为 false。
    disableUploadTimeout上传时是否使用超时机制。应设置为 true。
    connectionUploadTimeout上传超时时间,毕竟文件上传可能需要消耗更多的时间,这个根据你自己的业务需要自己调,以使Servlet有较长的时间来完成它的执行,需要与上一个参数一起配合使用才会生效。
    acceptCount指定当所有可以使用的处理请求的线程数都被使用时,可传入连接请求的最大队列长度,超过这个数的请求将不予处理,默认为 100 个。
    compression是否对响应的数据进行GZIP压缩,off:表示禁止压缩;on:表示允许压缩(文本将被压缩)、force:表示所有情况下都进行压缩,默认值为 off,压缩数据后可以有效的减少页面的大小,一般可以减小 1/3 左右,节省带宽。
    compressionMinSize表示压缩响应的最小值,只有当响应报文大小大于这个值的时候才会对报文进行压缩,如果开启了压缩功能,默认值就是 2048。
    compressableMimeType压缩类型,指定对哪些类型的文件进行数据压缩。
    noCompressionUserAgents=“gozilla, traviata”对于以下的浏览器,不启用压缩

    以上是一些常用的配置参数,还有好多其它的参数设置,还可以继续深入的优化,HTTP Connector 与 AJP Connector 的参数属性值,可以参考官方文档的详细说明进行学习。

    展开全文
  • 总结tomcat的核心组件以及根目录结构1. 目录结构1.1 bin(程序文件)1.2 conf目录(配置文件)1.3 logs(日志文件) 1. 目录结构 目录 说明 bin 服务启动、停止等相关程序和文件 conf 配置文件 lib 库目录 ...

    1. 目录结构

    目录说明
    bin服务启动、停止等相关程序和文件
    conf配置文件
    lib库目录
    logs日志目录
    temp临时目录
    webapps应用程序,应用部署目录
    workjsp编译后的结果文件,建议提前预热访问

    在这里插入图片描述

    1.1 bin(程序文件)

    文件名说明
    catalina.sh启动,停止调用的脚本
    shutdown.sh停止服务
    startup.sh启动服务
    version.sh查看版本号

    1.2 conf目录(配置文件)

    文件名说明
    server.xml主配置文件
    web.xml每个webapp只有“部署”后才能被访问,它的部署方式通常由web.xml进行定义,其存放位置为WEB-INF/目录中;此文件为所有的webapps提供默认部署相关的配置,每个web应用也可以使用专用配置文件,来覆盖全局文件
    context.xml用于定义所有web应用均需加载的Context配置,此文件为所有的webapps提供默认配置,每个web应用也可以使用自已专用的配置,它通常由专用的配置文件context.xml来定义,其存放位置为WEB-INF/目录中,覆盖全局的文件
    tomcat-users.xml用户认证的账号和密码文件
    catalina.policy当使用security选项启动tomcat时,用于为tomcat设置安全策略
    catalina.propertiesTomcat 环境变量的配置,用于设定类加载器路径,以及一些与JVM调优相关参数
    logging.propertiesTomcat 日志系统相关的配置,可以修改日志级别和日志路径等

    1.3 logs(日志文件)

    文件名说明
    catalina.日期.log按日期切割的catalina.out,和
    catalina.outtomcat访问日志信息它记录的访问的时间,IP ,访问的资料等相关信息。
    manager.日期.logmanager项目日志
    host-manager.日期.loghost-manager项目日志
    localhost.日期.log运行中的日志,它主要记录运行的一些信息,尤其是一些异常错误日志信息.
    localhost_access_log.日期.txttomcat访问日志

    2. Tomcat 核心组件

    Tomcat核心组件有6个,分别为Tomcat有Server、Service、Connector、Engine、Host和Context等,下面为大家一一介绍:

    2.1 Server

    Server元素在最顶层,代表整个Tomcat容器,因此它必须是server.xml中唯一一个最外层的元素。一个Server元素中可以有一个或多个Service元素。
    Server的主要任务,就是提供一个接口让客户端能够访问到这个Service集合,同时维护它所包含的所有的Service的声明周期,包括如何初始化、如何结束服务、如何找到客户端要访问的Service。

    2.2 Service

    Service的作用,是在Connector和Engine外面包了一层,把它们组装在一起,对外提供服务。一个Service可以包含多个Connector,但是只能包含一个Engine;其中Connector的作用是从客户端接收请求,Engine的作用是处理接收进来的请求。Tomcat可以提供多个Service,不同的Service监听不同的端口。

    2.3 Connector

    Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据;然后分配线程让Engine来处理这个请求,并把产生的Request和Response对象传给Engine。通过配置Connector,可以控制请求Service的协议及端口号。

    2.4 Engine

    Engine组件在Service组件中有且只有一个;Engine是Service组件中的请求处理组件。Engine组件从一个或多个Connector中接收请求并处理,并将完成的响应返回给Connector,最终传递给客户端。
    实际上,Engine、Host和Context都是容器,但它们不是平行的关系,而是父子关系:Engine包含Host,Host包含Context。

    2.5 Host

    Host是Engine的子容器。Engine组件中可以内嵌1个或多个Host组件,每个Host组件代表Engine中的一个虚拟主机。Host组件至少有一个,且其中一个的name必须与Engine组件的defaultHost属性相匹配。
    Host虚拟主机的作用,是运行多个Web应用(一个Context代表一个Web应用),并负责安装、展开、启动和结束每个Web应用。

    2.6 Context

    Context元素代表在特定虚拟主机上运行的一个Web应用。每个Web应用基于WAR文件,或WAR文件解压后对应的目录(这里称为应用目录)。Context是Host的子容器,每个Host中可以定义任意多的Context元素。

    展开全文
  • Java Web三大组件

    2020-12-19 11:05:56
    上篇文章我们介绍了Servlet和Jsp以及一些Java Web开发的基础概念,本篇文章我们来介绍另一Java Web开发中的重要概念——Java Web三大组件,即Servlet、Filter和Listener。 1. Servlet 由于我们上篇文章已经介绍过...

    上篇文章我们介绍了Servlet和Jsp以及一些Java Web开发的基础概念,本篇文章我们来介绍另一Java Web开发中的重要概念——Java Web三大组件,即Servlet、Filter和Listener。

    1. Servlet

    由于我们上篇文章已经介绍过Servlet了,这里就不再详细介绍了,透过现象看本质——什么是servlet

    2. Filter

    Filter(过滤器)用于拦截用户请求,在服务器作出响应前,可以在拦截后修改request和response。可以实现一次编码,多处应用。完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

    2.1 作用

    • 拦截修改请求:在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
    • 拦截修改响应:在HttpServletResponse到达客户端之前,拦截HttpServletResponse。根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

    2.2 原理

    Filter也是一个接口,实现了该接口并进行相应配置,就可以使Filter生效,进而实现:对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后再对服务器响应进行后处理。Filter的底层原理是基于函数回调的,这里用到了责任链模式。

    • init(FilterConfig filterConfig)
      • 初始化方法,只会在web应用程序启动时调用一次
      • 和Servlet一样,Filter的创建和销毁由WEB服务器负责
      • web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象
      • Filter对象创建之后会驻留在内存,一直服务
    • doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      • 完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器
    • destroy();
      • 销毁方法,只会在当web应用移除或服务器停止时才调用一次来卸载Filter对象
      • 通常在这个方法中,可以释放过滤器使用的资源

    所以我们自定义实现Filter的核心逻辑就在doFilter方法中,一般我们自定义实现Filter都会按照以下的模式:

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    	//对用户请求执行预处理的代码逻辑
    	precode... 
    	//交给FilterChain的下一个对象处理
    	//如果还有filter则调用下一个filter
    	//如果没有,则调用目标资源。
    	chain.doFilter(req, resp);
    	//对服务器响应执行后处理
    	postcode...
    }

    2.2.2 FilterConfig

    与Servlet一样,Filter也很可能需要访问 Servlet 容器。Servlet 规范将代表 ServletContext对象和Filter的配置参数信息都封装到一个称为FilterConfig的对象中。

    • getInitParameter():获取初始化参数
    • getInitParameterNames():获取所有初始化参数的名称
    • getFilterName():获取过滤器的配置名称
    • getServletContext():获取ServletContext

    2.2.3 FilterChain

    在一个web应用当中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链,其中每个过滤器(Filter)都可以决定是否执行下一步。

    doFilter():该方法被FilterChain对象调用,表示对Filter过滤器过滤范围下的资源进行放行,让链中下一个对象进行处理

    FilterChain在tomcat中的实现类是ApplicationFilterChain。

    • n:filter个数
    • pos:下一个要执行的filter的位置
    • Servlet:当pos >= n,即过滤完成时,调用Servlet的service方法,把请求交给Servlet
    • filters:Filter的相关配置信息

    FilterChain持有所有Filter的配置信息,它们保存在一个数组中,然后通过移动pos,来获取后续的Filter并执行的,符合之前的链式处理流程。

    FilterChain pos的维护使用过pos++实现的,我们可能会担心是否会有线程安全问题。但其实FilterChain是不存在线程安全问题的。

    ApplicationFilterChain对象是由ApplicationFilterFactory工厂的createFilterChain方法生成的。而这个方法在ApplicationDispatcher的invoke方法内被调用。这个invoke方法是Connector把新请求传递给Container的方式。这样来看每个请求都会创建一个FilterChain对象,所以不用担心会有线程安全问题

    对于FilerChain,我们需要注意:

    • 只要FilterChain中任意一个Filter没有调用FilterChain.doFilter方法,则目标Servlet的service方法都不会被执行
    • FilterChain中的各个Filter的拦截顺序与它们在web.xml文件中的映射顺序一致
    • 最后一个Filter调用doFilter方法将激活目标Servlet的service方法,该逻辑在FilterChain.doFilter方法中实现

    2.3 编写一个Filter

    通常我们编写一个Filter,主要包含以下两个步骤:

    1. 定义一个Filter类,该类实现了Filter接口
    2. 将自定义的Filter类配置到web.xml中

    2.3.1 实现Filter类

    public class TestFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // 初始化方法,在web应用程序启动时调用一次
        }
    
        @Override
        public void destroy() {
            // 销毁方法,当web应用移除或服务器停止时才调用一次来卸载Filter对象
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            // 1. preCode,对Request做前置处理,也可以在这里实现一些Filter过滤器前置逻辑,比如读取Filter配置的init-param信息,存储到成员变量中,实现过滤逻辑
            // ……
    
            // 2. 当前过滤器放行,继续执行下一个过滤器的过滤逻辑
            filterChain.doFilter(servletRequest, servletResponse);
    
            // 3. postCode,对服务器响应执行后处理
            // ……
        }
    }

    2.3.2 Filter配置

    在web.xml中配置过滤器,需要谨记一条原则:在web.xml中,监听器 > 过滤器 > servlet。也就是说web.xml需要先配置监听器,然后配置过滤器,最后是Servlet,否则会出错。

    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <!DOCTYPE web-app
            PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
            "http://java.sun.com/dtd/web-app_2_3.dtd">
    
    <web-app>
    
        <filter>
            <filter-name>testFilter</filter-name>
            <filter-class>com.zhuoli.service.servlet.TestFilter</filter-class>
            <init-param>
                <param-name>cacheTimeout</param-name>
                <param-value>600</param-value>
            </init-param>
        </filter>
        <>
            <filter-name>testFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <servlet>
            <servlet-name>testServlet</servlet-name>
            <servlet-class>com.zhuoli.service.servlet.TestServlet</servlet-class>
            <init-param>
                <param-name>myParam</param-name>
                <param-value>paramValue</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>testServlet</servlet-name>
            <url-pattern>*.html</url-pattern>
        </servlet-mapping>
    </web-app>

    <filter>元素用于配置一个过滤器

    • <filter-name>:用于为过滤器指定一个名字,不能为空
    • <filter-class>:用于指定过滤器的完整的限定类名,不能为空
    • <init-param>:用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数

    <filter-mapping>元素用于设置一个Filter所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet名称(<servlet-name>)和资源访问的请求路径(<url-pattern>)

    • <filter-name>:用于设置filter的注册名称,该值必须是在<filter>元素中声明过的过滤器的名字
    • <url-pattern>:用于设置filter所拦截的请求路径(过滤器关联的URL样式)
      • 作用与所有web资源:<url—pattern>/*</url-pattern>。则客户端请求访问任意资源文件时都要经过过滤器的过滤
      • 作用于某一文件夹下所有文件:<url—pattern>/dir/*</url-pattern>
      • 作用于某一种类型的文件:<url—pattern>*.扩展名</url-pattern>。比如<url—pattern>*.jsp</url-pattern>过滤所有对jsp文件的访问请求
      • 作用于某一文件夹下某一类型文件:<url—pattern>/dir/*.扩展名</url-pattern>
    • <servlet-name>:用于设置filter所拦截的Servlet名称
    • <dispatcher>:用于资源访问时,设置过滤器是否被Servlet容器调用,可以是REQUEST、INCLUDE、FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截
      • REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用
      • INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用
      • FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用
      • ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用

    2.3.3 Filter执行顺序

    Filter的执行顺序是按照FilterChain来执行的,FilterChain中Filter的顺序不同配置方式下的组织情况不同,具体如下:

    • 使用web.xml配置:根据对应的Mapping的顺序组织,谁定义在上边谁就在前
    • 基于注解配置(Spring注解):按照类名的字符串比较规则比较,值小的先执行

    2.3.4 实际运用

    • 处理全站中文乱码问题
    • 过滤非法请求
    • 实现自动登录
    • 过滤敏感词汇
    • 选择性让浏览器缓存
    • 结合日志记录用户操作

    3. Listener

    监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。监听器其实就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行。而这里讲的Listener其实就是是Servlet的监听器,它可以监听客户端请求(Request)、服务端Session、服务端ServletContext生命周期内的变化。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量等。

    被监听对象A中,关联着监听器B对象。事件源A类对外提供一个方法,用于设置监听器对象B到A类的某一实例变量中。在需要被监听的事件源的方法中,方法体的某一处先构造创建一个Event对象,将监听器对象B与相关的动作封装进Event对象中,然后调用监听器B对象的xxAdded(event)、xxCreated(event)方法,将事件对象传入方法实参中,实现事件源修改触发监听器监听的动作。通俗一点讲就是:

    • 事件源:即谁产生的事件
    • 事件对象:即产生了什么事件
    • 监听器:监听事件源的动作

    按照划分Java Web监听器可分为三类:

    • ServletContext监听器:监听ServletContext对象的初始化和销毁
    • Request监听器:监听Request对象的初始化和销毁以及属性改变
    • Session监听器:监听Session对象的创建和销毁以及属性改变

    3.1 ServletContext监听器

    3.1.1 ServletContextListener

    ServletContextListener用于对ServletContext进行监听(创建、销毁)。

    • contextInitialized:监听ServletContext初始化动作
    • contextDestroyed:监听ServletContext销毁动作
    • getServletContext:获取ServletContext

    这里我们写个demo,实现使用监听器对数据库连接池DataSource进行初始化。

    public class ListenerTest implements ServletContextListener{       
       // 应用监听器的销毁方法     
       public void contextDestroyed(ServletContextEvent servletContextEvent) {     
            ServletContext servletContext = servletContextEvent.getServletContext();  
            // 在整个web应用销毁之前调用,将所有应用空间所设置的内容清空  
            servletContext.removeAttribute("dataSource");  
            System.out.println("销毁工作完成...");    
       }     
        // 应用监听器的初始化方法     
        public void contextInitialized(ServletContextEvent servletContextEvent) {        
            // 通过这个事件可以在整个web应用下面启动的时候做一些初始化的内容添加工作     
            ServletContext servletContext = servletContextEvent.getServletContext();    
            // 设置一些基本的内容;比如一些参数或者是一些固定的对象     
            // 创建DataSource对象,连接池技术 dbcp     
            BasicDataSource basicDataSource = new BasicDataSource();   
            basicDataSource.setDriverClassName("com.jdbc.Driver");   
            basicDataSource.setUrl("jdbc:mysqlocalhost:3306/");   
            basicDataSource.setUsername("root");     
            basicDataSource.setPassword("root");     
            basicDataSource.setMaxActive(10);//最大连接数     
            basicDataSource.setMaxIdle(5);//最大管理数     
            servletContext.setAttribute("dataSource", basicDataSource);     
            System.out.println("应用监听器初始化工作完成...");     
            System.out.println("已经创建DataSource...");    
        }     
    }
    //web.xml中配置监听器   
    <listener>     
        <listener-class>com.zhuoli.service.listener.ListenerTest</listener-class>     
    </listener> 

    3.1.2 ServletContextAttributeListener

    ServletContextAttributeListener用于对ServletContext属性变更的监听(增删改属性)

    • attributeAdded:监听ServletContext attributes添加kv动作
    • attributeRemoved:监听ServletContext attributes删除kv动作
    • attributeRepalced:ServletContext attributes替换kv动作
    • getName:获取属性名称
    • getValue:属性的值

    这里我们看一下ApplicationContext类中对ServletContext方法setAttribute的实现:

    public void setAttribute(String name, Object value) {
        // 1. 检查attribute name不能为null
        if (name == null) {
            throw new NullPointerException
                (sm.getString("applicationContext.setAttribute.namenull"));
        }
    
        // 2. 如果attribute value为null则删除该attribute
        if (value == null) {
            removeAttribute(name);
            return;
        }
    
        // Add or replace the specified attribute
        // 3. 如果attribute为readOnlyAttribute,直接返回
        if (readOnlyAttributes.containsKey(name))
            return;
    
        // 4.添加或替换attribute
        Object oldValue = attributes.put(name, value);
        // 5. 根据返回值,判断是添加操作还是替换操作
        boolean replaced = oldValue != null;
    
        // 获取所有的监听器,通知监听器,实现监听动作
        Object listeners[] = context.getApplicationEventListeners();
        if ((listeners == null) || (listeners.length == 0))
            return;
        ServletContextAttributeEvent event = null;
        if (replaced)
            event =
                new ServletContextAttributeEvent(context.getServletContext(),
                                                 name, oldValue);
        else
            event =
                new ServletContextAttributeEvent(context.getServletContext(),
                                                 name, value);
    
        for (int i = 0; i < listeners.length; i++) {
            if (!(listeners[i] instanceof ServletContextAttributeListener))
                continue;
            ServletContextAttributeListener listener =
                (ServletContextAttributeListener) listeners[i];
            try {
                if (replaced) {
                    context.fireContainerEvent
                        ("beforeContextAttributeReplaced", listener);
                    listener.attributeReplaced(event);
                    context.fireContainerEvent("afterContextAttributeReplaced",
                                               listener);
                } else {
                    context.fireContainerEvent("beforeContextAttributeAdded",
                                               listener);
                    listener.attributeAdded(event);
                    context.fireContainerEvent("afterContextAttributeAdded",
                                               listener);
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                if (replaced)
                    context.fireContainerEvent("afterContextAttributeReplaced",
                                               listener);
                else
                    context.fireContainerEvent("afterContextAttributeAdded",
                                               listener);
                // FIXME - should we do anything besides log these?
                log(sm.getString("applicationContext.attributeEvent"), t);
            }
        }
    }

    逻辑是非常简单的,事件源ApplicationContext的attribute修改动作,出发监听器的监听。

    这里我们写一个demo,对ServletContext attribute属性的变更做监听。

    public class MyServletContextAttributeListener implements
            ServletContextAttributeListener {
        @Override
        public void attributeAdded(ServletContextAttributeEvent scab) {
            String str =MessageFormat.format(
                    "ServletContext域对象中添加了属性:{0},属性值是:{1}"
                    ,scab.getName()
                    ,scab.getValue());
            System.out.println(str);
        }
    
        @Override
        public void attributeRemoved(ServletContextAttributeEvent scab) {
            String str =MessageFormat.format(
                    "ServletContext域对象中删除属性:{0},属性值是:{1}"
                    ,scab.getName()
                    ,scab.getValue());
            System.out.println(str);
        }
    
        @Override
        public void attributeReplaced(ServletContextAttributeEvent scab) {
            String str =MessageFormat.format(
                    "ServletContext域对象中替换了属性:{0}的值"
                    ,scab.getName());
            System.out.println(str);
        }
    //web.xml配置监听器
    <listener>
       <listener-class>com.zhuoli.service.listener.MyServletContextAttributeListener</listener-class>
    </listener>

    3.2 Request监听器

    3.2.1 ServletRequestListener

    ServletRequestListener用于对Request请求进行监听(创建、销毁)。

    • requestInitialized:监听ServletRequest初始化动作
    • requestDestroyed:监听ServletRequest销毁动作
    • getServletRequest:从Evenet对象中获取ServletRequest对象
    • getServletContext:从Event对象中获取ServletContext

    这里我们写一个demo,使用servletRequestListener来实现web浏览量的变化。

    public class ListenerTest3 implements ServletRequestListener {
        @Override
        public void requestDestroyed(ServletRequestEvent arg0) {
            System.out.println("requestDestroyed" + "," + new Date());
            System.out.println("当前访问次数:" + arg0.getServletContext().getAttribute("count"));
        }
    
        @Override
        public void requestInitialized(ServletRequestEvent arg0) {
            System.out.println("requestInitialized" + "," + new Date());
            Object count = arg0.getServletContext().getAttribute("count");
            Integer cInteger = 0;
            if (count != null) {
                cInteger = Integer.valueOf(count.toString());
            }
            System.out.println("历史访问次数::" + count);
            cInteger++;
            arg0.getServletContext().setAttribute("count", cInteger);
        }
    }

    但是需要注意的是,这里的是非线程安全的。

    3.2.2 ServletRequestAttributeListener

    ServletRequestAttributeListener用于对ServletRequest属性添加、删除、修改做监听。

    • attributeAdded:监听ServletRequest attribute添加动作
    • attributeRemoved:监听ServletRequest attribute删除动作
    • attributeReplaced:监听ServletRequest attribute替换动作
    • getName:获取ServletRequest attribute名称
    • getValue:获取ServletRequest attribute值
    public class ServletRquestListeners implements ServletRequestListener,ServletRequestAttributeListener  
    {  
        //这个是在请求后调用  
        public void requestDestroyed(ServletRequestEvent s)  
        {  
            System.out.println("销毁了ServletReqeust");  
        }  
      
        //它是在请求前调用  
        public void requestInitialized(ServletRequestEvent s)  
        {  
            ServletRequest servletRequest = s.getServletRequest();  
            HttpServletRequest request = (HttpServletRequest) servletRequest;  
            String pathInfo = request.getServletPath();  
            System.out.println("请求地址:"+pathInfo);  
        }  
      
        public void attributeAdded(ServletRequestAttributeEvent srae)  
        {  
            HttpServletRequest request = (HttpServletRequest) srae.getServletRequest();  
            System.out.println("增加request--->"+request.getAttribute("requestName"));  
        }  
      
        public void attributeRemoved(ServletRequestAttributeEvent srae)  
        {  
            HttpServletRequest request = (HttpServletRequest) srae.getServletRequest();  
            System.out.println("删除request--->"+request.getAttribute("requestName"));  
        }  
      
        public void attributeReplaced(ServletRequestAttributeEvent srae)  
        {  
            HttpServletRequest request = (HttpServletRequest) srae.getServletRequest();  
            System.out.println("替换request--->"+request.getAttribute("requestName"));  
        }  
    } 
    //web.xml配置
    <!-- 自定义ServletRquestListener的监听 --> 
    <listener> 
        <listener-class>com.zhuoli.service.listener.ServletRquestListeners</listener-class> 
    </listener> 

    3.3 Session监听器

    3.3.1 HttpSessionListener

    HttpSessionListener用于对Session的整体状态(创建,销毁)进行监听。

    • sessionCreated:监听session的创建动作
    • sessionDestroyed:监听session的销毁动作
    • getSession:获取session

    下面通过一个demo,实现对sessino创建销毁的监听。

    public class MyListener implements HttpSessionListener {  
     
        ServletContext sc;
        ArrayList list = new ArrayList();  
        // 新建一个session时触发此操作  
        public void sessionCreated(HttpSessionEvent se) {  
            sc = se.getSession().getServletContext();  
            System.out.println("新建一个session");  
        }  
      
        // 销毁一个session时触发此操作  
        public void sessionDestroyed(HttpSessionEvent se) {  
            System.out.println("销毁一个session");  
            if (!list.isEmpty()) {  
                list.remove((String) se.getSession().getAttribute("userName"));  
                sc.setAttribute("list", list);  
            }  
        } 
    }  

    web.xml配置

    <?xml version="1.0" encoding="UTF-8"?>    
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"    
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee     
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">    
        <listener>    
            <listener-class>    
                com.zhuoli.service.listener.MyListener
            </listener-class>    
        </listener>    
        <!--默认的会话超时时间间隔,以分钟为单位  -->    
        <session-config>    
            <session-timeout>1</session-timeout>    
        </session-config>
    </web-app>
    //index.jsp
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
    <%  
        String path = request.getContextPath();  
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";  
    %>  
    <html>  
        <body>  
            <%  
                session = request.getSession(false);  
                if (session != null)  
                    session.invalidate();  
            %>  
            <form action="isOnline.jsp" method="post">  
                用户名:  
                <input type="text" name="uName" />  
                <input type="submit" value="上线">  
        </body>  
    </html> 
    //isOnline.jsp
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
    <%  
    String path = request.getContextPath();  
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
    %>  
    <html>  
      <body>  
        <%  
    session=request.getSession();  
    session.setAttribute("userName",request.getParameter("uName"));  
    response.sendRedirect("showOnline.jsp");  
    %>  
      </body>  
    </html>
    //showOnline.jsp
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
    <%  
    String path = request.getContextPath();  
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
    %> 
    <html>  
        <body>  
            <%  
    ArrayList showList=(ArrayList)(getServletContext().getAttribute("list"));  
    out.print("在线人数 "+showList.size()+"<br>");  
    for(int i=0;i<showList.size();i++){  
    out.print(showList.get(i)+"在线"+"<br>");  
    }  
    %>  
            <br>  
            <a href="index.jsp">退出</a>  
        </body>  
    </html>

    HttpSessionListener中sessionCreated是新建一个会话时候触发,也可以说是客户端第一次和服务器交互时候触发。 sessionDestroyed是会话销毁的时候触发,一般来说只有某个按钮触发进行销毁或者配置定时销毁。

    3.3.2 HttpSessionAttributeListener

    HttpSessionAttributeListener用于对session的属性(添加,删除,替换)进行监听。

    • attributeAdded:监听session attribute添加动作
    • attributeRemoved:监听session attribute删除动作
    • attributeReplaced:监听session attribute替换动作
    • getSession:获取session
    • getName:获取session attribute名称
    • getValue:获取session attribute值

    下面通过一个demo,实现对session attribute的监听。

    public class MyAttributeListener implements HttpSessionAttributeListener {  
        @Override  
        public void attributeAdded(HttpSessionBindingEvent event) {  
            String attributeName = event.getName();  
            Object attributeValue = event.getValue();  
            System.out.println("HttpSessionAttributeListener Attribute added : " + attributeName + " : "  
                    + attributeValue);  
        }  
      
        @Override  
        public void attributeRemoved(HttpSessionBindingEvent event) {  
            String attributeName = event.getName();  
            Object attributeValue = event.getValue();  
            System.out.println("HttpSessionAttributeListener Attribute removed : " + attributeName + " : "  
                    + attributeValue);  
        }  
      
        @Override  
        public void attributeReplaced(HttpSessionBindingEvent event) {  
            String attributeName = event.getName();  
            Object attributeValue = event.getValue();  
            System.out.println("Attribute replaced : " + attributeName + " : "  
                    + attributeValue);  
        }  
    }  
    //web.xml配置监听器
    <listener>  
        <listener-class>com.zhuoli.service.listener.MyAttributeListener</listener-class>  
    </listener>  
    //test.jsp
    <html>
    <body>  
        <%  
            session = request.getSession();  
            session.setAttribute("url", "51gjie.com"); //HttpSessionAttributeListener attributeAdded() is executed  
            session.setAttribute("url", "www.51gjie.com"); //attributeReplaced() is executed  
            session.removeAttribute("url"); //HttpSessionAttributeListener attributeRemoved() is executed  
        %>  
    </body>  
    </html>  

    4. 理解Java Web三大组件

    当我们进入Java Web开发后会发现,我们好像已经不再关心我们的程序是如何、从何处被调用的。我们写一个类,甚至从来没new过,它也可以运行起来。不想我们在开发JavaSE时,一切都是那么清晰,定义一个类,然后在main方法中实例化该类,最后进行方法调用。

    所以当我们一开始接触Java Web开发时肯定是非常疑惑的,特别是接触了Java Web中一些列的组件Servlet/Filter/Listener后。没有main方法,也不需要new。只需要在web.xml进行配置后,就可以生效了。

    那么我们可以想象,既然我们没有自己定义Servlet/Filter/Listener等组件访问的入口,那是不是有人替我们写了入口,并通过web.xml的配置进行了调用。答案是肯定的,Java Web应用跟普通应用一样,也是有访问入口的,而这个入口其实就是Tomcat(Servlet容器)替我们生成的。Tomcat根据我们的配置文件,生成我们定义的组件实例,并进行方法调用(这个过程可以称为“注入”、“回调”)。

    假如我们想象Tomcat中存在这么一个main方法入口:

    是不是我们定义的组件在这可以在这里生效了,其实实际上Tomcat也是通过上图的方式,实现我们自定义组件调用的,只不过考虑的东西更多,更加复杂,但是原理是一致的。

    参考链接:

    1. Java中Servlet Filter配置(web.xml详解)

    2. Web三大组件-Filter

    3. Java过滤器Filter的使用详解

    4. java web 三大组件

    5. Java中Servlet Listener监听器详解(原理)

    6. JavaSchool——Servlet入门教程

    展开全文
  • 一:Tomcat核心组件及应用架构详解

    千次阅读 多人点赞 2021-05-19 21:05:18
    目录 Web 容器是什么?...Tomcat 部署脚本编写 Web 容器是什么? 让我们先来简单回顾一下 Web 技术的发展历史,可以帮助你理解 Web 容器的由来。 早期的 Web 应用主要用于浏览新闻等静态页面,HTTP 服务

    目录

    Web 容器是什么?

    HTTP 的本质

    HTTP 请求响应实例

    Cookie 和 Session

    Servlet规范

    Servlet 容器

    Web 应用

    扩展机制

    一、Tomcat各组件认知

    2.Tomcat 各组件及关系

    二、Tomcat server.xml 配置详解

    三、Tomcat 部署脚本编写


    Web 容器是什么?

    让我们先来简单回顾一下 Web 技术的发展历史,可以帮助你理解 Web 容器的由来。

    早期的 Web 应用主要用于浏览新闻等静态页面,HTTP 服务器(比如 Apache、Nginx)向浏览器返回静态 HTML,浏览器负责解析 HTML,将结果呈现给用户。

    随着互联网的发展,我们已经不满足于仅仅浏览静态页面,还希望通过一些交互操作,来获取动态结果,因此也就需要一些扩展机制能够让 HTTP 服务器调用服务端程序。

    于是 Sun 公司推出了 Servlet 技术。你可以把 Servlet 简单理解为运行在服务端的 Java 小程序,但是 Servlet 没有 main 方法,不能独立运行,因此必须把它部署到 Servlet 容器中,由容器来实例化并调用 Servlet。

    而 Tomcat 就是一个 Servlet 容器。为了方便使用,它们也具有 HTTP 服务器的功能,因此 Tomcat 就是一个“HTTP 服务器 + Servlet 容器”,我们也叫它们 Web 容器。

     

    HTTP 的本质

    HTTP 协议是浏览器与服务器之间的数据传送协议。作为应用层协议,HTTP 是基于 TCP/IP 协议来传递数据的(HTML 文件、图片、查询结果等),HTTP 协议不涉及数据包(Packet)传输,主要规定了客户端和服务器之间的通信格式。

    假如浏览器需要从远程 HTTP 服务器获取一个 HTML 文本,在这个过程中,浏览器实际上要做两件事情。

    • 与服务器建立 Socket 连接。
    • 生成请求数据并通过 Socket 发送出去。

    0

    HTTP 请求响应实例

    用户在登陆页面输入用户名和密码,点击登陆后,浏览器发出了这样的 HTTP 请求:

    0

    HTTP 请求数据由三部分组成,分别是请求行、请求报头、请求正文。当这个 HTTP 请求数据到达 Tomcat 后,Tomcat 会把 HTTP 请求数据字节流解析成一个 Request 对象,这个 Request 对象封装了 HTTP 所有的请求信息。接着 Tomcat 把这个 Request 对象交给 Web 应用去处理,处理完后得到一个 Response 对象,Tomcat 会把这个 Response 对象转成 HTTP 格式的响应数据并发送给浏览器。

    0

    HTTP 的响应也是由三部分组成,分别是状态行、响应报头、报文主体。同样,我还以极客时间登陆请求的响应为例。

    Cookie 和 Session

    我们知道,HTTP 协议有个特点是无状态,请求与请求之间是没有关系的。这样会出现一个很尴尬的问题:Web 应用不知道你是谁。因此 HTTP 协议需要一种技术让请求与请求之间建立起联系,并且服务器需要知道这个请求来自哪个用户,于是 Cookie 技术出现了。

    Cookie 是 HTTP 报文的一个请求头,Web 应用可以将用户的标识信息或者其他一些信息(用户名等)存储在 Cookie 中。用户经过验证之后,每次 HTTP 请求报文中都包含 Cookie,这样服务器读取这个 Cookie 请求头就知道用户是谁了。Cookie 本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息。

    由于 Cookie 以明文的方式存储在本地,而 Cookie 中往往带有用户信息,这样就造成了非常大的安全隐患。而 Session 的出现解决了这个问题,Session 可以理解为服务器端开辟的存储空间,里面保存了用户的状态,用户信息以 Session 的形式存储在服务端。当用户请求到来时,服务端可以把用户的请求和用户的 Session 对应起来。那么 Session 是怎么和请求对应起来的呢?答案是通过 Cookie,浏览器在 Cookie 中填充了一个 Session ID 之类的字段用来标识请求。

    具体工作过程是这样的:服务器在创建 Session 的同时,会为该 Session 生成唯一的 Session ID,当浏览器再次发送请求的时候,会将这个 Session ID 带上,服务器接受到请求之后就会依据 Session ID 找到相应的 Session,找到 Session 后,就可以在 Session 中获取或者添加内容了。而这些内容只会保存在服务器中,发到客户端的只有 Session ID,这样相对安全,也节省了网络流量,因为不需要在 Cookie 中存储大量用户信息。

    那么 Session 在何时何地创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同的创建 Session 的方法。在 Java 中,是 Web 应用程序在调用 HttpServletRequest 的 getSession 方法时,由 Web 容器(比如 Tomcat)创建的。

    Tomcat 的 Session 管理器提供了多种持久化方案来存储 Session,通常会采用高性能的存储方式,比如 Redis,并且通过集群部署的方式,防止单点故障,从而提升高可用。同时,Session 有过期时间,因此 Tomcat 会开启后台线程定期的轮询,如果 Session 过期了就将 Session 失效。

    Servlet规范

    HTTP 服务器怎么知道要调用哪个 Java 类的哪个方法呢。最直接的做法是在 HTTP 服务器代码里写一大堆 if else 逻辑判断:如果是 A 请求就调 X 类的 M1 方法,如果是 B 请求就调 Y 类的 M2 方法。但这样做明显有问题,因为 HTTP 服务器的代码跟业务逻辑耦合在一起了,如果新加一个业务方法还要改 HTTP 服务器的代码。

    那该怎么解决这个问题呢?我们知道,面向接口编程是解决耦合问题的法宝,于是有一伙人就定义了一个接口,各种业务类都必须实现这个接口,这个接口就叫 Servlet 接口,有时我们也把实现了 Servlet 接口的业务类叫作 Servlet。

    但是这里还有一个问题,对于特定的请求,HTTP 服务器如何知道由哪个 Servlet 来处理呢?Servlet 又是由谁来实例化呢?显然 HTTP 服务器不适合做这个工作,否则又和业务类耦合了。

    于是,还是那伙人又发明了 Servlet 容器,Servlet 容器用来加载和管理业务类。HTTP 服务器不直接跟业务类打交道,而是把请求交给 Servlet 容器去处理,Servlet 容器会将请求转发到具体的 Servlet,如果这个 Servlet 还没创建,就加载并实例化这个 Servlet,然后调用这个 Servlet 的接口方法。因此 Servlet 接口其实是 Servlet 容器跟具体业务类之间的接口。下面我们通过一张图来加深理解。

    0

    Servlet 接口和 Servlet 容器这一整套规范叫作 Servlet 规范。Tomcat 和 Jetty 都按照 Servlet 规范的要求实现了 Servlet 容器,同时它们也具有 HTTP 服务器的功能。作为 Java 程序员,如果我们要实现新的业务功能,只需要实现一个 Servlet,并把它注册到 Tomcat(Servlet 容器)中,剩下的事情就由 Tomcat 帮我们处理了。

    Servlet 接口定义了下面五个方法:

    public interface Servlet {
        void init(ServletConfig config) throws ServletException;
        
        ServletConfig getServletConfig();
        
        void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
        
        String getServletInfo();
        
        void destroy();
    }

    其中最重要是的 service 方法,具体业务类在这个方法里实现处理逻辑。这个方法有两个参数:ServletRequest 和 ServletResponse。ServletRequest 用来封装请求信息,ServletResponse 用来封装响应信息,因此本质上这两个类是对通信协议的封装。

    HTTP 协议中的请求和响应就是对应了 HttpServletRequest 和 HttpServletResponse 这两个类。你可以通过 HttpServletRequest 来获取所有请求相关的信息,包括请求路径、Cookie、HTTP 头、请求参数等。此外, 我们还可以通过 HttpServletRequest 来创建和获取 Session。而 HttpServletResponse 是用来封装 HTTP 响应的。

    你可以看到接口中还有两个跟生命周期有关的方法 init 和 destroy,这是一个比较贴心的设计,Servlet 容器在加载 Servlet 类的时候会调用 init 方法,在卸载的时候会调用 destroy 方法。我们可能会在 init 方法里初始化一些资源,并在 destroy 方法里释放这些资源,比如 Spring MVC 中的 DispatcherServlet,就是在 init 方法里创建了自己的 Spring 容器。

    你还会注意到 ServletConfig 这个类,ServletConfig 的作用就是封装 Servlet 的初始化参数。你可以在web.xml给 Servlet 配置参数,并在程序里通过 getServletConfig 方法拿到这些参数。

    我们知道,有接口一般就有抽象类,抽象类用来实现接口和封装通用的逻辑,因此 Servlet 规范提供了 GenericServlet 抽象类,我们可以通过扩展它来实现 Servlet。虽然 Servlet 规范并不在乎通信协议是什么,但是大多数的 Servlet 都是在 HTTP 环境中处理的,因此 Servet 规范还提供了 HttpServlet 来继承 GenericServlet,并且加入了 HTTP 特性。这样我们通过继承 HttpServlet 类来实现自己的 Servlet,只需要重写两个方法:doGet 和 doPost。

    Servlet 容器

    当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来,然后调用 Servlet 容器的 service 方法,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet,如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的 init 方法来完成初始化,接着调用 Servlet 的 service 方法来处理请求,把 ServletResponse 对象返回给 HTTP 服务器,HTTP 服务器会把响应发送给客户端

    0

    Web 应用

    Servlet 容器会实例化和调用 Servlet,那 Servlet 是怎么注册到 Servlet 容器中的呢?一般来说,我们是以 Web 应用程序的方式来部署 Servlet 的,而根据 Servlet 规范,Web 应用程序有一定的目录结构,在这个目录下分别放置了 Servlet 的类文件、配置文件以及静态资源,Servlet 容器通过读取配置文件,就能找到并加载 Servlet。Web 应用的目录结构大概是下面这样的:

    | -  MyWebApp
          | -  WEB-INF/web.xml        -- 配置文件,用来配置Servlet等
          | -  WEB-INF/lib/           -- 存放Web应用所需各种JAR包
          | -  WEB-INF/classes/       -- 存放你的应用类,比如Servlet类
          | -  META-INF/              -- 目录存放工程的一些信息

    Servlet 规范里定义了 ServletContext 这个接口来对应一个 Web 应用。Web 应用部署好后,Servlet 容器在启动时会加载 Web 应用,并为每个 Web 应用创建唯一的 ServletContext 对象。你可以把 ServletContext 看成是一个全局对象,一个 Web 应用可能有多个 Servlet,这些 Servlet 可以通过全局的 ServletContext 来共享数据,这些数据包括 Web 应用的初始化参数、Web 应用目录下的文件资源等。由于 ServletContext 持有所有 Servlet 实例,你还可以通过它来实现 Servlet 请求的转发。

    扩展机制

    引入了 Servlet 规范后,你不需要关心 Socket 网络通信、不需要关心 HTTP 协议,也不需要关心你的业务类是如何被实例化和调用的,因为这些都被 Servlet 规范标准化了,你只要关心怎么实现的你的业务逻辑。这对于程序员来说是件好事,但也有不方便的一面。所谓规范就是说大家都要遵守,就会千篇一律,但是如果这个规范不能满足你的业务的个性化需求,就有问题了,因此设计一个规范或者一个中间件,要充分考虑到可扩展性。Servlet 规范提供了两种扩展机制:Filter 和 Listener

    Filter 是过滤器,这个接口允许你对请求和响应做一些统一的定制化处理,比如你可以根据请求的频率来限制访问,或者根据国家地区的不同来修改响应内容。过滤器的工作原理是这样的:Web 应用部署完成后,Servlet 容器需要实例化 Filter 并把 Filter 链接成一个 FilterChain。当请求进来时,获取第一个 Filter 并调用 doFilter 方法,doFilter 方法负责调用这个 FilterChain 中的下一个 Filter。

    Listener 是监听器,这是另一种扩展机制。当 Web 应用在 Servlet 容器中运行时,Servlet 容器内部会不断的发生各种事件,如 Web 应用的启动和停止、用户请求到达等。 Servlet 容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet 容器会负责调用监听器的方法。当然,你可以定义自己的监听器去监听你感兴趣的事件,将监听器配置在web.xml中。比如 Spring 就实现了自己的监听器,来监听 ServletContext 的启动事件,目的是当 Servlet 容器启动时,创建并初始化全局的 Spring 容器。

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

    0

    /bin:存放 Windows 或 Linux 平台上启动和关闭 Tomcat 的脚本文件。
    /conf:存放 Tomcat 的各种全局配置文件,其中最重要的是server.xml。
    /lib:存放 Tomcat 以及所有 Web 应用都可以访问的 JAR 文件。
    /logs:存放 Tomcat 执行时产生的日志文件。
    /work:存放 JSP 编译后产生的 Class 文件。
    /webapps:Tomcat 的 Web 应用目录,默认情况下把 Web 应用放在这个目录下。

    打开 Tomcat 的日志目录,也就是 Tomcat 安装目录下的 logs 目录。Tomcat 的日志信息分为两类 :一是运行日志,它主要记录运行过程中的一些信息,尤其是一些异常错误日志信息 ;二是访问日志,它记录访问的时间、IP 地址、访问的路径等相关信息。

    • catalina.***.log 主要是记录 Tomcat 启动过程的信息,在这个文件可以看到启动的 JVM 参数以及操作系统等日志信息。
    • catalina.out是 Tomcat 的标准输出(stdout)和标准错误(stderr),这是在 Tomcat 的启动脚本里指定的,如果没有修改的话 stdout 和 stderr 会重定向到这里。所以在这个文件里可以看到我们在MyServlet.java程序里打印出来的信息
    • localhost.**.log主要记录 Web 应用在初始化过程中遇到的未处理的异常,会被 Tomcat 捕获而输出这个日志文件。
    • localhost_access_log.**.txt存放访问 Tomcat 的请求日志,包括 IP 地址以及请求的路径、时间、请求协议以及状态码等信息。
    • manager.***.log/host-manager.***.log存放 Tomcat 自带的 Manager 项目的日志信息。

    概要:

    1. Tomcat各核心组件认知
    2. server.xml 配置详解

    一、Tomcat各组件认知

    知识点:

    1. Tomcat架构说明
    2. Tomcat组件及关系详情介绍
    3. Tomcat启动参数说明
    4. Tomcat架构说明

    Tomcat是一个基于JAVA的WEB容器,其实现了JAVA EE中的 Servlet 与 jsp 规范,与Nginx apache 服务器不同在于一般用于动态请求处理。在架构设计上采用面向组件的方式设计。即整体功能是通过组件的方式拼装完成。另外每个组件都可以被替换以保证灵活性。

    0

    2.Tomcat 各组件及关系

    • Server 和 Service
    • Connector 连接器
      • HTTP 1.1
      • SSL https
      • AJP( Apache JServ Protocol) apache 私有协议,用于apache 反向代理Tomcat
    • Container 
      • Engine 引擎 catalina
      • Host 虚拟机 基于域名 分发请求
      • Context 隔离各个WEB应用 每个Context的 ClassLoader都是独立
    • Component 
      • Manager (管理器)
      • logger (日志管理)
      • loader (载入器)
      • pipeline (管道)
      • valve (管道中的阀)

    0

    二、Tomcat server.xml 配置详解


    server

    root元素:server 的顶级配置 主要属性: port:执行关闭命令的端口号 shutdown:关闭命令

    •  演示shutdown的用法  #基于telent 执行SHUTDOWN 命令即可关闭(必须大写) telnet 127.0.0.1 8005 SHUTDOWN 

    service

    服务:将多个connector 与一个Engine组合成一个服务,可以配置多个服务。

    Connector

    连接器:用于接收 指定协议下的连接 并指定给唯一的Engine 进行处理。 主要属性:

    • protocol 监听的协议,默认是http/1.1
    • port 指定服务器端要创建的端口号
    • minSpareThreads服务器启动时创建的处理请求的线程数
    • maxThreads 最大可以创建的处理请求的线程数
    • enableLookups 如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址
    • redirectPort 指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号
    • acceptCount 指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
    • connectionTimeout 指定超时的时间数(以毫秒为单位)
    • SSLEnabled 是否开启 sll 验证,在Https 访问时需要开启。生成证书: keytool -genkey -v -alias testKey -keyalg RSA -validity 3650 -keystore D:\test.keystore
    • [ ] 演示配置多个Connector
    <Connector port="8860" protocol="org.apache.coyote.http11.Http11NioProtocol"
                    connectionTimeout="20000"
                    redirectPort="8862"
                    URIEncoding="UTF-8"
                    useBodyEncodingForURI="true"
                    compression="on" compressionMinSize="2048"
    compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css,application/x-json,application/json,application/x-javascript"
                    maxThreads="1024" minSpareThreads="200"
                    acceptCount="800"
                    maxConnections="10000"
                    enableLookups="false"
            />

    Engine

    引擎:用于处理连接的执行器,默认的引擎是catalina。一个service 中只能配置一个Engine。 主要属性:name 引擎名称 defaultHost 默认host

    Host

    虚拟机:基于域名匹配至指定虚拟机。类似于nginx 当中的server,默认的虚拟机是localhost. 主要属性:

    •  演示配置多个Host
    <Host name="www.wukong.com"  appBase="/usr/www/wukong"  unpackWARs="true" autoDeploy="true"> 
    	<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="www.wukong.com.access_log" 
    			suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
    </Host>

    Context

    应用上下文:一个host 下可以配置多个Context ,每个Context 都有其独立的classPath。相互隔离,以免造成ClassPath 冲突。 主要属性:

    •  演示配置多个Context
     <Context path="/testweb" docBase="testweb.war"  reloadbale="true"/>

    Valve 阀门:可以理解成

    的过滤器,具体配置要基于具体的Valve 接口的子类。以下即为一个访问日志的Valve

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                   prefix="www.wukong.com.access_log" suffix=".txt"
                   pattern="%h %l %u %t &quot;%r&quot; %s %b" />

    三、Tomcat 部署脚本编写

    Tomcat启动参数说明

    我们平时启动Tomcat过程是怎么样的?

    1. 复制WAR包至Tomcat webapp 目录。
    2. 执行starut.bat 脚本启动。
    3. 启动过程中war 包会被自动解压装载。

    但是我们在Eclipse 或idea 中启动WEB项目的时候 也是把War包复杂至webapps 目录解压吗?显然不是,其真正做法是在Tomcat程序文件之外创建了一个部署目录,在一般生产环境中也是这么做的 即:Tomcat 程序目录和部署目录分开 。 我们只需要在启动时指定CATALINA_HOME 与 CATALINA_BASE 参数即可实现。

    启动参数 | 描述说明 | |:----|:----| | JAVA_OPTS | jvm 启动参数 , 设置内存 编码等 -Xms100m -Xmx200m -Dfile.encoding=UTF-8 | | JAVA_HOME | 指定jdk 目录,如果未设置从java 环境变量当中去找。 | | CATALINA_HOME | Tomcat 程序根目录 | | CATALINA_BASE | 应用部署目录,默认为$CATALINA_HOME | | CATALINA_OUT | 应用日志输出目录:默认$CATALINA_BASE/log | | CATALINA_TMPDIR | 应用临时目录:默认:$CATALINA_BASE/temp |

    可以编写一个脚本 来实现自定义配置:

    ln -s /home/wukong/apache-tomcat-8.5.56 apache-tomcat

    更新 启动 脚本

    #!/bin/bash 
    export JAVA_OPTS="-Xms100m -Xmx200m"
    export CATALINA_HOME=/home/wukong/apache-tomcat
    export CATALINA_BASE="`pwd`"
    
    case $1 in
            start)
            $CATALINA_HOME/bin/catalina.sh start
                    echo start success!!
            ;;
            stop)
                    $CATALINA_HOME/bin/catalina.sh stop
                    echo stop success!!
            ;;
            restart)
            $CATALINA_HOME/bin/catalina.sh stop
                    echo stop success!!
                    sleep 3
            $CATALINA_HOME/bin/catalina.sh start
            echo start success!!
            ;;
            version)
            $CATALINA_HOME/bin/catalina.sh version
            ;;
            configtest)
            $CATALINA_HOME/bin/catalina.sh configtest
            ;;
            esac
    exit 0

    docker 启动tomcat

    docker run -id --name=test_tomcat -e JAVA_OPTS='-Xmx128m' -p 8888:8080 -v /usr/local/tuling-project/tomcat-test/webapps:/usr/local/tomcat/webapps -v /usr/local/tuling-project/tomcat-test/logs:/usr/local/tomcat/logs -v /usr/local/tuling-project/tomcat-test/conf:/usr/local/tomcat/conf --privileged=true tomcat:8

    源码构建

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

    配置

    1.解压源码 apache-tomcat-8.5.57-src

    2.apache-tomcat-8.5.57-src目录下添加pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>Tomcat8.0</artifactId>
        <name>Tomcat8.0</name>
        <version>8.0</version>
    
        <build>
            <finalName>Tomcat8.0</finalName>
            <sourceDirectory>java</sourceDirectory>
            <testSourceDirectory>test</testSourceDirectory>
            <resources>
                <resource>
                    <directory>java</directory>
                </resource>
            </resources>
            <testResources>
                <testResource>
                    <directory>test</directory>
                </testResource>
            </testResources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3</version>
                    <configuration>
                        <encoding>UTF-8</encoding>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.easymock</groupId>
                <artifactId>easymock</artifactId>
                <version>3.4</version>
            </dependency>
            <dependency>
                <groupId>ant</groupId>
                <artifactId>ant</artifactId>
                <version>1.7.0</version>
            </dependency>
            <dependency>
                <groupId>wsdl4j</groupId>
                <artifactId>wsdl4j</artifactId>
                <version>1.6.2</version>
            </dependency>
            <dependency>
                <groupId>javax.xml</groupId>
                <artifactId>jaxrpc</artifactId>
                <version>1.1</version>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jdt.core.compiler</groupId>
                <artifactId>ecj</artifactId>
                <version>4.5.1</version>
            </dependency>
    
        </dependencies>
    </project>

    3.在apache-tomcat-8.5.57-src 同级目录新建 catalina-home并保证目录下面文件如下

    0

    注意: 上面文件夹apache-tomcat-8.5.57-src里面有的,就剪切过来,没有的就新建一个, bin conf webapps 应该是从apache-tomcat-8.5.57-src剪切过来的

    4.idea引入项目

    File->Open 选择解压的C:\Users\wukong\Downloads\apache-tomcat-8.5.57-src\apache-tomcat-8.5.57-src

    配置启动

    1. MainClass: org.apache.catalina.startup.Bootstrap
    2. VmOptions: -Dcatalina.home=C:\Users\wukong\Downloads\apache-tomcat-8.5.57-src\apache-tomcat-8.5.57-src\catalina-home

    0

    启动报错

    TestCookieFilter 报错找不到这个类CookieFilter

    解决方法:

    1. 删除:TestCookieFilter

    启动后,访问localhost:8080 报错 org.apache.jasper.JasperException: java.lang.NullPointerException

    解决方案:

    org.apache.catalina.startup.Bootstrap 添加代码块

    {
            JasperInitializer initializer =new JasperInitializer();
             }

     

    展开全文
  • 参考文章 ...LifeCycle和LifecycleState 生命周期 Lifecycle 接口里应该定义这么几个方法:init、start、stop 和 destroy,...在父组件的 init 方法里需要创建子组件并调用子组件的 init 方法。同样,在父组件的 start
  • 1.组件定义 Tomcat中只有一个Server,一个Server可以用多个Service,一个Service可以有多个Connector和一个Container。 Server掌握着整个Tomcat的生死大权。 Service是对外提供服务的。一个Server可以有多个Service...
  • Tomcat 连接器组件 Coyote Coyote 简介 Coyote 是Tomcat 中连接器的组件名称 , 是对外的接⼝。客户端通过Coyote与服务器建⽴连接、发送请求并接受响应 。 (1)Coyote 封装了底层的⽹络通信(Socket 请求及响应处理...
  • 启动tomcat报错。“无法启动组件

    千次阅读 2021-03-16 11:42:53
    老师,麻烦帮忙看下可以吗,启动tomcat报错。java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: 无法启动组件[StandardEngine[Catalina].StandardHost[localhost].StandardContext...
  • Tomcat关键组件介绍

    2021-04-18 20:14:46
    Tomcat的Connector组件,通常被称为Coyote。 它包含了EndPoint,Processor,Adatper。 EndPoint:它是coyote通信端点,即通信监听的接口,是具体Socket接收和发送处理器,是对传输层的抽象,因此EndPoint用来实现TCP/IP...
  • 概述 Mapper基类介绍 请求处理机制
  • 二、Tomcat的核心组件三Tomcat的应用架构 一、Tomcat是什么?主要是用来做什么的? Tomcat 是一个 Servlet 容器,它实现了对Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制...
  • 今天我在复习servlet的时候,遇到了无法启动组件、IDEA无法正常启动的问题。如下: 解决方案 由于本人不是什么大神,无法详细解释原因,只能把我解决问题的方法分享给大家。       &...
  • Servlet组件是JavaEE进行web开发的最基本组件,可以处理请求写出响应,tomcat启动以后监听8080端口,解析web.xml文件,获取每个servlet以及对应的请求url,当tomcat接受到请求的时候,就可以根据请求的url信息,找到...
  • 出现此异常的原因应该是项目中有错误 继续查看详细错误信息,有这样一条: 名为 [servlet.MusicInfoServlet]和 [servlet.UpdateMusicServlet] 的servlet不能映射为一个url模式(url-pattern) [/UpdateMusicServlet] ...
  • tomcat核心组件

    2021-03-06 18:03:32
    总结如图,tomcat核心配置文件是server.xml。
  • Tomcat的层次结构中已经知道Server组件Tomcat最顶层组件,它可以当作Tomcat的运行实例的抽象。除此之外,它还包含若干个Service组件、Listener组件以及GlobalNamingResources组件。如下图所示, Tomcat的整个...
  • Tomcat 组件简介 tomcat的各个组件 Http请求的执行图示: tomcat启动源码时序图 tomcat接受请求源码时序图 Tomcat各个组件 Tomcat启动流程 启动时序图中,已经大致疏通了整体tomcat的启动流程,有些...
  • 详细介绍了Tomcat服务器的server.xml配置文件结构,包括BIO与NIO模式,以及请求处理流程。
  • Tomcat中Catalina容器中会有一个Server,而在一个Server下会管理多个Service(服务),而一个Service又会绑定多个Connector(连接器)组件和一个Container(容器)组件,在Container组件中,具备如下的层级结构,...
  • Java web的三大组件

    2021-02-27 20:03:07
    一、web.xml的配置就是主要包括Java web的三大组件:servlet、filter、listener1. servlet1)servlet标准接口包括: init()/service(request,response)/destroy();不要想得太复杂,servlet就是如下一点点的方法。不管...
  • 所以这里总结一下:几乎所有的中文网页都介绍,要修改Tomcat的默认最大并发连接数,应该进行如下设置(实际上这些步骤是错误的):--------------------------------------------在tomcat配置文件serve...
  • 我无法在eclipse上启动我的apache tomcat服务器。一旦我启动它,它就会关闭。我试图删除并重新配置它,也从.m2plugin中删除它并添加了适当的依赖关系但它强行关闭。我正在粘贴堆栈跟踪,希望有人能找到解决方案。它...
  • 我们升级内嵌的组件的版本号时,无需像方式一那样去排除内嵌的组件,然后再重新加入依赖,这样做其实是个笨方法,可以直接定义组件的版本号,这样就可以达到升级组件版本的目的了,不仅Tomcat是这样,其他组件也是...
  • 1.应用服务器设计 2.各个组件说明 3.tomcat请求处理
  • 将Web应用部署到Tomcat根目录的种方法:将应用部署到Tomcat根目录的种方法将应用部署到Tomcat根目录的目的是可以通过“http://[ip]:[port]”直接访问应用,而不是使用“http://[ip]:[port]/[appName]”上下文...
  • Connector组件Tomcat核心组件之一,其主要负责监听服务器指定端口的请求,解析请求报文为Request对象与Response对象。后将Request与Response传递至Container组件进行后续处理。 一、Connector组件
  • tomcat中开启ajp后,启动tomcat遇到错误无法启动组件[Connector[AJP/1.3-8009]]。 错误原因 缺少配置项secretRequired。 tomcat9提供的默认的AJP配置如下: <Connector protocol="AJP/1.3" address="::1
  • JavaWeb监听器三大组件:ServletListenerFilter监听器:它是一个接口,内容由我们来实现;它需要注册,例如注册在按钮上!监听器中的方法,会在特殊事件发生时被调用!JavaWeb中的监听器一、生命周期监听与属性监听...
  • 通常,在刚开始参与一个项目的时候,需要将子模块部署到tomcat运行,这时候由于项目本身或tomcat设置问题会导致一系列的报错,比较常见的就有项目初始化失败的报错,一般提示为:Failed to start component ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 135,305
精华内容 54,122
关键字:

tomcat的三大组件