0%

如何在 10 分钟内学会 Tomcat 8

关于 Tomcat 系列其他文章的传送门

  1. 《 如何在 10 分钟内学会 Tomcat 8 》     您当前所在位置

  2. 《 干货分享 生产环境中如何为 Tomcat 配置反向代理和负载均衡 》

  3. 《 你一定不知道 如何在 Tomcat 集群中实现三种会话绑定 》



apache_tomcat

一、软件的架构模式

软件从设计上,有以下几种架构

  • 分层架构:把要实现的功能在以下四个层级中抽象的表现出来,各层级之间是隔离的,通过调用接口来完成工作;
    • 表现层:主要处理业务逻辑本身;
    • 业务层
    • 持久层
    • 数据库层:通过调用数据库,把持久层的数据保存在对应的数据库中;
  • 事件驱动架构模式:可以理解是一个分布式异步架构模式,模块之间的调度高度解耦;
  • 微内核架构:即插件式架构,程序核心本身设计的非常小,各种其他功能通过扩展模块的方式插入到核心中,比如 Nginx 就是这样的架构;
  • 微服务架构:把整体系统功能的每一项功能,都独立为一个又一个的发布单元,每个单元都是一个独立的服务提供者,各服务之间通过服务治理系统来完成服务组件之间的交互和通信。
    • API REST-based
    • application REST-based
    • 中心化消息
  • 基于空间的架构:云原生的应用程序。

二、Tomcat 是什么

了解 Tomcat 之前先了解一下 Java,下图是 Java 的技术体系:

Java 技术体系

java.webp

从下网上看,可以看出有以下几个部分:

  • JVM:是 Java 虚拟机,一个专门运行 Java 的环境;
  • JRE:是 JVM + 各种 JAVA2 SE API 的 标准类库 接口;
  • JDK:是 JRE + Java 的开发工具,开源社区版叫 OpenJDK

这其中,JDK 包含了 JRE,JRE 又包含了 JVM。
jvm

Java 的类库接口分为:

  • 标准版:JAVA2 SE(Standard Edition) API;
  • 企业版:JAVA2 EE(Enterprise Edition) API。

其中 JRE 中包含的类库就是 JAVA2 SE 标准类库,而企业版则是 JAVA2 EE 企业类库,企业版比标准版多出很多的库接口,如 Appletjsp 等等。

Tomcat

而 Tomcat 就是在 JRE 的基础上,又包含了 Appletjsp 这两个最常用的企业类库,可以看做是 J2EE 的不完整实现。

Tomcat 是 Apache 的 ASF 旗下已经毕业的开源项目,本身其实也是用 Java 程序编写的,是一个专门为了运行 jsp(java server page) 的容器,而 Tomcat 的代码名则叫 catalina

实现了此类功能的软件其实有很多,比如

  • 商业实现
    • WebSphere
    • WebLogic
    • Oc4j
    • Glassfish
    • Geronimo
    • JOnAS
    • JBoss
  • 开源实现
    • Tomcat
    • Jetty
    • Resin

JSP 代码的运行流程

JSP 其实也是一种 Java 代码,所以先了解一下 Java 代码的运行流程。

Java 代码的运行流程

  • .java 代码会被 java C 编译为 .class (servlet 程序),然后 在 JVM 中运行
  • JVM 则负载加载程序的类文件 *.class,及程序的类文件依赖到的其它的类文件而后运行;
  • 运行时整个表现为一个 JVM 进程。

JSP 代码的运行流程

  • JSP 的代码运行第一步是通过组件 jsp parser*.jsp 转换为 *.java
  • 然后就和 Java 程序运行时一样,.java 代码被 java C 编译为 .class (servlet 程序),然后 在 JVM 中运行

jsp_1
jsp_2

而编译好的 .java*.class 文件会缓存在 /tomcat/work 目录下,加速下次使用,所以程序第一次部署后应该预热一下 Tomcat。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-> # tree /usr/local/tomcat/work
/usr/local/tomcat/work
└── Catalina
└── localhost
├── docs
├── examples
├── host-manager
├── manager
└── ROOT
└── org
└── apache
└── jsp
├── index_jsp.class
└── index_jsp.java

三、Tomcat 的安装和启动

Tomcat 本身也是个 Java 程序,所以要运行 Tomcat 就得先安装好 Java 的运行环境。

安装 JDK

JDK 分为社区版和企业版,下面依次介绍安装方式。

OpenJDK 社区版

使用 yum 可直接安装 devel 的安装包,包含了开发组件和 OpenJDK 的核心包。

1
yum install java-1.8.0-openjdk-devel

OpenJDK 可多版本并存,当 1.6.0, 1.7.0, 1.8.0 多版本并存时,可使用 alternatives 命令设定默认使用的版本。alternatives 就是利用软连接实现的。

/usr/bin/java 其实是个软连接,完整路径为:

1
/usr/bin/java -> /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.222.b10-0.el7_6.x86_64/jre/bin/java

最后那个才是真正的 Java 程序目录。

Oracle JDK 企业版

先下载 rpm 安装包。
Oracle JDK 需要从官网下载,如商业使用需要注意版权,个人学习使用无限制。

安装
使用 rpm 安装,默认会安装到 /usr/java 目录下。

1
rpm -ivh jdk-8u221-linux-x64.rpm

添加 JAVA_HOME 环境变量。

1
2
3
4
~]# vim /etc/profile.d/java.sh
JAVA_HOME=/usr/java/latest
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH

重载 shell 生效。

1
exec bash

能查看当前的 Java 版本,说明安装成功。

1
2
3
4
~]# java -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)

安装 Tomcat

接下来就可以安装 Tomcat 了。

Tomcat 也有两种安装方法,可以直接使用 yum 从 Base 仓库安装,也可以从官网下载编译好的 tar 包解压安装。

1. 通过 yum 安装

可以直接使用 yum 安装,Base仓库是 7.x 的版本。

1
yum install -y tomcat tomcat-webapps tomcat-docs-webapp tomcat-admin-webapps
  • rpm 包安装的程序环境:
    • 配置文件目录:/etc/tomcat
    • 主配置文件:server.xml
  • 网页文件的存放位置:/var/lib/tomcat/webapps/
    • examples
    • manager
    • host-manager
    • docs
  • Unit File:tomcat.service
  • 环境配置文件:/etc/sysconfig/tomcat

通过 systemd 就能直接启动 Tomcat 了。

1
systemctl start tomcat

2. 通过 tar 包安装

如果想用新版,需要从官网下载,当前版本是 8.5.43

下载地址 http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.43/bin/apache-tomcat-8.5.43.tar.gz

下载的是编译好的 Java 二进制程序,接下来展开压缩包到指定位置即可完成安装。

展开 Tomcat 即可完成安装。

1
2
tar -xvf apache-tomcat-8.5.43.tar.gz -C /usr/local
ln -sv /usr/local/apache-tomcat-8.5.43 /usr/local/tomcat

Tomcat 的目录结构

  • /bin/:脚本,及启动时用到的类;
  • /conf/:配置文件目录;
  • /lib/:库文件,Java 类库,jar;
  • /logs/:日志文件目录;
  • /temp/:临时文件目录;
  • /webapps/:网页文件的默认目录;
  • /work/:工作目录;

配置 Tomcat 程序的权限

注意:建议使用普通用户运行 Tomcat,而不是 root,所以先创建普通账户并修改权限。

1
2
useradd tomcat
chown -R :tomcat /usr/local/tomcat/*

但是对 logs, temp, work 这些目录应该有写权限,而且对 conf/* 应该有读的权限,否则会因为加载不了配置信息而无法启动。

1
2
chown -R tomcat: /usr/local/tomcat/{logs/,temp/,work/}
chmod g+x /usr/local/tomcat/conf && chmod g+r /usr/local/tomcat/conf/*

运行 Tomcat

先切换到 tomcat 用户,然后使用 startup.sh 脚本来启动 Tomcat。

1
2
[root@node1 ~]# su - tomcat
[tomcat@node1 ~]$ /usr/local/tomcat/bin/startup.sh

或者配置环境变量。

1
2
3
4
[root@node1 ~]# vim /etc/profile.d/tomcat.sh
CATALINA_BASE=/usr/local/tomcat/
PATH=$CATALINA_BASE/bin:$PATH
export CATALINA_BASE PATH

环境变量生效后,就可以通过命令 startup.sh 直接启动 Tomcat 了。

1
[root@node1 ~]# startup.sh

catalina.sh 工具

使用 /usr/local/tomcat/bin/catalina.sh 工具可以完成很多控制动作:

1
2
3
4
5
6
7
8
9
~]# catalina.sh --help
run # 在当前终端直接启动
start # 等于调用 startup.sh,剥离当前终端在后台运行
stop # 等于调用 shutdown.sh
stop -n # N 秒后才停止
stop -force # 强制停止
stop -n -force # N 秒后强制停止
configtest # 配置文件语法测试
version # 查看详细信息

四、Tomcat 的程序结构

配置文件介绍

Tomcat 的配置文件放置在 tomcat/conf/ 下,yum 安装的话会在 /etc/tomcat/conf/下。

  • server.xml:主配置文件;
  • web.xml:提供默认的与部署相关的配置;每个 webapp 都可以有自己的 web.xml,存放位置为 WEB-INF/ 目录中,如果没有,则此文件会提供默认部署配置;
  • context.xml:提供默认的配置文件;每个 webapp 都可以有专用的配置文件,它通常由专用的配置文件 context.xml 来定义,其存放位置为 WEB-INF/ 目录中;如果没有,此文件会提供默认配置;
  • tomcat-users.xml:关于 basic 用户认证的账号和密码文件;
  • catalina.policy:当使用 -security 选项启动 Tomcat 时,用于为 Tomcat 设置安全策略;
  • catalina.properties:主要配置 Tomcat 的安全设置、类加载设置、不需要扫描的类设置、字符缓存设置,以及一些与 JVM 调优相关参数;
  • /tomcat.conf:一些变量的配置;
  • logging.properties:日志系统相关的配置。

JSP WebAPP 的组织结构

  • tomcat/weball/:webapps 的根目录,放置各种与站点相关的目录;
    • index.jsp, index.html:主页文件;
    • WEB-INF/:当前 webapp 的私有资源路径;通常用于存储当前 webapp 的 web.xmlcontext.xml 配置文件;
    • META-INF/:类似于 WEB-INF/
    • classes/:类文件,当前 webapp 所提供的类;
    • lib/:类文件,当前 webapp 所提供的被打包为 jar 格式的类;
    • ROOT:存放网站首页的目录。

webapp 归档格式

webapp 在发布时通常是被打包为一个归档文件,有如下几种格式:

  • *.war:webapp;
  • *.jar:EJB 的类打包文件;
  • *.rar:资源适配器类打包文件;
  • *.ear:企业级 webapp。

五、JSP 部署 webapp 的相关操作

部署操作有以下几种

  • 部署(deploy)流程:
    1. 将 webapp 的源文件放置于目标目录(网页程序文件存放目录),配置 Tomcat 服务器能够基于 web.xmlcontext.xml 文件中定义的路径来访问此 webapp;
    2. 将其特有的类和依赖的类通过 class loader 装载至 JVM 虚拟机;
  • 部署有两种方式:
    1. 自动部署:由 Tomcat 自动完成;
    2. 手动部署:
      (1) 冷部署:把 webapp 复制到指定的位置,而后启动 Tomcat;
      (2) 热部署:在不停止 Tomcat 的前提下进行部署;部署工具包括:managerant 脚本tcd(tomcat client deployer) 等;
  • 反部署(undeploy):
    • 停止 webapp,并从 Tomcat 实例上卸载 webapp;
  • start:启动处于停止状态的 webapp;
  • stop:停止 webapp,不再向用户提供服务;其类依然在 jvm 上;
  • redeploy:重新部署;

冷部署示例

手动创建一个测试类应用,并冷部署。

1、创建名为 myapp 的工作目录。

1
mkdir -pv /usr/local/tomcat/webapps/myapp/{classes,lib,WEB-INF}

2、创建 jsp 主页文件。

vim /usr/local/tomcat/webapps/myapp/index.jsp

1
2
3
4
5
6
7
8
9
10
11
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<% out.println("hello world");
%>
</body>
</html>

3、就可以访问了

1
2
3
4
5
6
7
8
9
10
11
~]# curl http://192.168.50.12:8080/myapp/

<html>
<head>
<title>Test Page</title>
</head>
<body>
hello world

</body>
</html>

4、在 tomcat/work/.../myapp/ 目录下可以看到自动转换并生成的 *.java*.class 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-> # tree /usr/local/tomcat/work
/usr/local/tomcat/work
└── Catalina
└── localhost
├── docs
├── examples
├── host-manager
├── manager
├── ROOT
│   └── org
│   └── apache
│   └── jsp
│   ├── index_jsp.class
│   └── index_jsp.java
└── myapp
└── org
└── apache
└── jsp
├── index_jsp.class
└── index_jsp.java

六、部署 Tomcat 的两个管理应用

  1. Manager:管理 webapps 应用程序;
  2. Host Manager:管理虚拟主机。

登录管理界面需要先创建账户,并为每个账户分配不同的角色,每个角色的权限也各不相同

  • Manager App 的角色
    • manager-gui:允许访问 HTML GUI 和状态页;
    • manager-script:允许访问文本界面和状态页;
    • manager-jmx:允许访问 JMX 代理和状态页;
    • manager-status:只允许访问状态页;
  • Host Manager 的角色
    • admin-gui:Host Manager 的管理角色。

配置示例

编辑 tomcat-users.xml 添加账户并分配角色:

1
vim /usr/local/tomcat/conf/tomcat-users.xml

<tomcat-users> 上下文中,添加对账户的权限配置。

1
2
3
4
5
6
7
8
9
10
<tomcat-users
...
...
<role rolename="admin-gui"/> // 启用 Host Manager 的管理角色
<role rolename="manager-gui"/> // 启用 Manager App 的管理角色
<role rolename="manager-script"/> // 启用 Manager App 的管理角色
<user username="tomcat" password="123456" roles="manager-gui,manager-script,admin-gui"/>
...
...
</tomcat-users>

重启 Tomcat 后,就可以访问管理界面,对 Tomcat 进行启动、停止、反部署等管理操作。

管理页面的入口在首页的这里:

manager

查看是否对 IP 做了限制:

如果访问时提示 403 Access Denied 被拒绝,可能因为 tomcat 默认对 IP 做了限制。

解决办法

tomcat/webapps/managertomcat/webapps/host-manager/ 下都有一个 /META-INF/context.xml 文件,注释两个文件中掉其中对 IP 的限制信息即可。

1
2
3
4
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->

七、server.xml 中常用组件的配置

server.xmlTomcat 的核心配置文件,内部通过组件来定义,每一个组件都由一个 Java 的“类”实现,这些组件大体可分为以下几个类型:

  • 顶级组件:Server
  • 服务类组件:Service
  • 连接器组件:http, https, ajp(apache jserv protocol)
  • 容器类:Engine, Host, Context
  • 被嵌套类:valve, logger, realm, loader, manager, …;
  • 集群类组件:listener, cluster, …;

组件的框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Server>                   // 定义一个实例,内部有一个或多个 Service
<Service> // 用于将一个或多个 connector 关联至 Engine 上
<connector/> // 连接器负载监听和接收来自于客户端的请求
<connector/>
...
<Engine> // 运行 java 应用程序代码并负责处理请求
<Host> // 虚拟主机
<Context/> // 定义 url 与本地文件系统的对应关系,以及访问权限, 类似 Apache 中的 location
<Context/>
...
</Host>
<Host>
</Host>
...
</Engine>
</Service>
</Server>

注意server.xml 不应该让其他用户有权限访问。

下面了解各组件的功能和使用方法。

Server 组件

默认配置:<Server port="8005" shutdown="SHUTDOWN">

Server 代表了 tomcat instance,表现为一个 Java 进程,监听在 本机地址8005 端口,属于管理端口,只接收 SHUTDOWN 关键字;

  • 各 Server 监听的端口不能相同,因此,在同一物理主机启动多个实例时,需要修改其监听端口为不同的端口;

注意

  • 因为可使用 SHUTDOWN 关键字直接关闭 Tomcat 的 Java 进程
  • 这个操作非常危险,应关闭此端口或更换为复杂的关键字。
1
2
3
4
5
6
-> # telnet 127.0.0.1 8005
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SHUTDOWN # 使用此命令直接关闭了 Java 进程
Connection closed by foreign host.
1
2
-> # openssl rand -base64 10  # 生成随机数
5VG/92mOgrKdLw==

替换关键词

1
<Server port="8005" shutdown="5VG/92mOgrKdLw">

Service 组件

用于实现将一个或多个 connector 组件关联至一个 engine 组件。

Connector 组件

定义属于整个 Tomcat 的监听地址和端口,负责接收请求。

  • 常见的连接器有三类
    • http
    • https
    • ajp

进入 Tomcat 的请求可分为两类

  1. standalone: 直接接收来自于客户端浏览器的请求;

  2. 由其它的 web server 反代,请求是来自前端的反代服务器;

    • nginx -> http connector -> tomcat
    • httpd(proxy_http_module) -> http connector -> tomcat
    • httpd(proxy_ajp_module) -> ajp connector -> tomcat
    • httpd(mod_jk) -> ajp connector -> tomcat

连接器可以使用的一些属性

  • port="8080":定义端口。注意:Tomcat 最好使用普通用户启动,所以无法使用 1024 以下的端口;
  • protocol="HTTP/1.1":定义默认使用的协议版本;
  • connectionTimeout="20000":连接超时时长,单位毫秒;
  • address:监听的 IP 地址,默认为本机所有可用地址;
  • maxThreads:最大并发连接数,默认为 200
  • enableLookups:是否启用DNS查询功能;
  • URIEncoding="UTF-8":如果 uri 内有中文,一定要指定编码格式为 UTF8;
  • acceptCount:等待队列的最大长度;
  • secure:启用 SSL;
  • sslProtocol:定义 SSL 证书、版本、私有文件。

示例:定义一个连接器

1
2
3
4
5
<Connector port="10080" protocol="HTTP/1.1"
connectionTimeout="2000"
enableLookups="false"
maxThreads="300"
URIEncoding="UTF-8" />

Engine 组件

每个 Engine 代表一个 Servlet 实例,即 servlet 引擎,是可以运行代码的位置,其内部可以一个或多个 host 组件来定义虚拟主机,有多个虚拟主机时通常需要通过 defaultHost 属性来定义默认的虚拟主机;

常用属性:

  • name="Catalina":基本上均为 Catalina
  • defaultHost="localhost":定义默认的虚拟主机,使用 Host 中定义的名字;
  • jvmRoute=TAG:基于 cookie 的会话绑定时,赋予当前 Engine 一个唯一的标识符。

Host 组件

Host 其实就是定义基于主机名的虚拟主机,位于 Engine 内部用于接收请求并进行相应处理。

注意:Tomcat 仅支持基于主机名的虚拟主机。

Host 基础配置

1
2
3
<Host name="localhost"  appBase="webapps"
unpackWARs="true" autoDeploy="true">
</Host>

常用属性说明

  • name:定义虚拟主机名;
  • appBase:定义网页文件根目录,指存放非归档的 web 应用程序或归档的 WAR 文件目录路径;
    • 注意:使用相对路径时是基于 $CATALINA_BASE 变量所定义的路径;
  • unpackWARs:如果 appBase 内有一个 WAR 文件,是否自动展开;
  • autoDeploy:在 Tomcat 处于运行状态时,有新的某 webapp 放置于 appBase 所定义的目录中时,是否自动将其部署至 Tomcat。
    • 生产环境不建议开启。

示例:定义一个新的 Host

1、添加一个 Host

1
2
<Host name="node1.monster.com" appBase="/data/myapp" unpackWARs="true" autoDeploy="true">
</Host>

2、在 ROOT 中提供一个网站首页测试页

1
2
mkdir -pv /data/myapp/ROOT/{lib,classes,WEB-INF}
vim /data/myapp/ROOT/index.jsp`
1
2
3
4
5
6
7
8
9
10
11
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<% out.println("hello world");
%>
</body>
</html>

3、重启 tomcat 后访问 http://node1.monster.com:8080,可以看到新页面就说明成功了。

1
2
3
4
5
6
7
8
9
10
~]# curl node2.monster.com:8080
<html>
<head>
<title>Test Page</title>
</head>
<body>
hello world

</body>
</html>

Context 组件

可以自定义 url 和网页文件目录的对应关系,类似于 Apache 中的 alias 别名。

Context 基础配置

1
<Context path="/uri" docBase="/PATH/TO/SOMEDIR" reloadable=""/>
  • Context path="/PATH":定义 uri 路径;
  • docBase="/PATH/TO/SOMEDIR":网页文件路径;
  • reloadable="":是否支持自动重载。

Context 示例

访问 node1.monster.com/jump/* 时,本来应该是访问 /data/myapp/jump/ 下的文件,

配置 Context 后,实际是访问,/data/jumphome/ 下的文件。

1
2
3
4
<Host name="node1.monster.com" appBase="/data/myapp" unpackWARs="true" autoDeploy="true">
<Context path="/jump/" docBase="/data/jumphome/" reloadable="">
</Context>
</Host>

Valve 组件

使用 Valve 在 Host 中定义一种功能阀门。

定义访问日志的 Valve

使用 org.apache.catalina.valves.AccessLogValve

1
2
3
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
  • directory="logs":日志存放目录,相对路径为 $CATALINA_BASE 的目录下;
  • prefix="localhost_access_log":日志文件的前缀,中间是日期;
  • suffix=".txt":日志文件的后缀;
  • pattern="%h %l %u %t &quot;%r&quot; %s %b":定义日志格式。

Tomcat 官方关于日志中变量的对应关系
https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/AbstractAccessLogValve.html

定义访问控制的 Valve

使用 org.apache.catalina.valves.RemoteAddrValve

1
<Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="192\.168\.50\.20"/>

Value 综合示例

1
2
3
4
5
6
7
8
9
10
<Host name="node1.monster.com" appBase="/data/myapp" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="node1_access" suffix=".log"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
<Context path="/jump/" docBase="/data/jumphome/" reloadable="">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="node1_access_" suffix=".log"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Context>
</Host>

tom