前言
Java 是一种广泛使用的计算机编程语言,拥有跨平台、面向对象、泛型编程的特性,广泛应用于企业级 Web 应用开发和移动应用开发。
在了解 Java 之前,首先应该明白 JDK 与 JRE
JRE:Java Runtime Enviroment,是Java的运行环境。面向Java程序的使用者,而不是开发者。如果你仅下载并安装了JRE,那么你的系统只能运行Java程序。JRE是运行Java程序所必须环境的集合,包含JVM标准实现及 Java核心类库。它包括Java虚拟机、Java平台核心类和支持文件。它不包含开发工具(编译器、调试器等)。
JDK:Java Development Kit,是Java开发工具包,它提供了Java的开发环境和运行环境。如果你下载并安装了JDK,那么你不仅可以开发Java程序,也同时拥有了运行Java程序的平台。JDK是整个Java的核心,包括了Java运行环境(JRE),一堆Java工具tools.jar和Java标准类库 (rt.jar)。
Java 又分为三部分:J2SE, J2EE 和 J2ME
J2SE:Java 2 standard edition,也被称为核心 Java,这是 Java 的最基本和标准的版本。它是 Java 的最纯粹的形式,是所有其他版本的基础
J2EE:Java 的企业版具有更多的 Java 使用,如 Web 服务,网络,服务器端脚本和其他各种基于Web的应用程序的开发。 J2EE 使用了许多 J2SE 组件,并且拥有许多自己的新特性,如 JSP,Servlets,JavaBeans,Java Message Service,为语言增添了全新的功能。
J2ME:这个版本的Java主要集中在嵌入式系统,手机和小型设备上运行的应用程序。应用不广泛。
而要想了解 Tomcat ,必须要了解 JSP 与 Servlet
早期的 Java 代码是不能够写在 html 语言中的。后来开发出了 JSP 。JSP 相当于 Java 的一个特殊的类库,这个类库能够将 Java 语句直接嵌套进 html 格式的语言中,通过 JSP 将这种格式的语言翻译成 Java 代码,交给后端的 Servlet 进行运行。
JSP:J2EE 中一个特殊的类库,能够内嵌至 html 页面,通过 ServletS类与后端数据库交互的,基于 Java 作为脚本语言拥有特定语法格式的技术。
Servlet:J2EE 中一个特殊的类库,能够将客户端发送过来的 Java 代码进行解析并生成动态 Web 内容。而 Servlet 类要想运行必须要有专门的运行环境,这个运行环境要将 Servlet 类运行的各项应用都装载进来,而且还能够与前端通过 CGI 协议进行交互。
要想能够运行客户端发送过来的请求,那么此时在服务器中就必须要有 JSP 类库、Servlet 类库以及 JDK。JDK 由 Sun 公司提供,而要想实现 JSP 类库与 Servlet 类库程序员就必须要将这些类库编写出来。而这个工程量是很浩大的,所以市面上有一些机构或者开源组织就提供了包含了这些类库的开源实现。
实现有两种:商业实现、开源实现
商业实现:WebSphere、WebLogic、Oc4j、Glassfish 等
开源实现: Tomcat、Jetty、Resin(这款软件在性能上要好于前两款,但是是半开源的实现。)
Tomcat 的组成
Tomcat 三大核心组件:Catalina、Coyote、Jasper
Catalina:Servlet Contalina (Servlet 容器),Servlet的代码实现,项目名称叫做 Cataina。
Coyote:HTTP connector(HTTP 的连接器),与前端 HTTP 服务器进行交互的连接器。
Jasper:JSP engine(JSP引擎),能够将 JSP 代码解释成 Servlet 代码(也就是 Java 代码)
Tomcat 的内部构成如下图所示:
Server:即一个 Tomcat 实例
Service:用于将 connect 关联至 engine 组件,一个 service 只能包含一个 engine,一个 engine 可以关联多个 connect
Engine:Tomcat 的核心组件,用于运行 JSP 或者 Servlet 代码
Connector:接受并解析用户请求,将请求映射为 Engine 中运行的代码,并将结果构建成响应代码。这个连接器通常是 HTTP 的连接器
Host:类似 httpd 的虚拟主机
Context:类似于 httpd 中的 alias,通过一个路径映射至一个内容,并将这个内容部署成一个独立的应用程序
Server 一个 Tomcat 实例,也相当于一个 Tomcat 进程。但是这个进程的显示方式是一个 Java 进程。这个进程无法单独接受 Http 协议的连接,所以这里就使用了 Connector 组件, 能够将客户端的请求连接进来转交给能够处理该请求的核心组件 Engine Servlet Container(也就是 Servlet 容器)。而 Connector 组件无法与 Servlet 容器单独连接,所以提供了 Service 组件,将 Connector 组件与 Servlet 组件结合起来。所以在这里 Server、Service、Engine Servlet Container 就组合成了一个 Web 站点。如果这方面不清楚的话,在下面讲到 Tomcat 的配置文件的时候你就会清楚,Connector 组件是嵌套在 Service 组件中的。
Tomcat 的安装
1、JDK 的安装
上面说道,所有的 Java 代码的开发以及运行都要有 JDK ,因为 JDK 中有 Java 代码运行所必须的组件以及 JVM (Java 虚拟机)。所以在安装 Tomcat 之前要首先安装 JDK 。
JDK 有两个分支,一个是 Oracle JDK ,一个是 Open JDK 。CentOS 7 中提供的是 Open JDK ,直接使用 yum 安装即可。如果要想使用 Oracle JDK 则要自行下载。这里以 Oracle JDK 为例。
Oracle JDK 下载地址:Oracle JDK 下载地址
(1) 下载 JDK ,直接安装
# yum install -y jdk-8u151-linux-x64.rpm
(2) 导出 Java 环境变量
JDK 系统默认安装路径在 /usr/java 目录下
# ls /usr/java
default jdk1.8.0_152 latest
default:是 JDK 的链接文件
jdk1.8.0_152:是 JDK 真实路径
latest:是 JDK 的另外一个链接文件
两个链接文件有什么用呢?
可能系统上因为某些应用需要安装不止一个 JDK ,那么这个时候我们就可以根据应用的需要使用不同的 JDK 。这里在导出环境变量的时候使用任意一个链接文件都行。
# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/java/latest
export PATH=$JAVA_HOME/bin:$PATH
重读配置文件
# . /etc/profiled.d/tomcat.sh
使用命令验证是否成功
# echo $PATH
/usr/java/latest/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# java 使用该命令能够显示出 java 的帮助信息代表安装 JDK 成功
为什么要导出 JAVA_HOME 这么一个环境变量呢?
因为很多应用程序在执行过程中要查找 JAVA_HOME 这么一个变量。通过这个变量找到 JDK 的安装路径。
2、安装 Tomcat
Tomcat 是 Apache 软件基金会的一个顶级开源项目,官网地址:tomcat。现在 Tomcat 9 已经出来,不过建议还是使用 Tomcat 7 或者 Tomcat 8。毕竟 Tomcat 9 太新。
(1) 下载安装
这里以 Tomcat 7 为例。下载地址:Tomcat 7 下载地址
解压
# tar xf apache-tomcat-7.0.82.tar.gz -C /usr/local
创建链接,以便于将来好进行升级管理
# ln -sv apache-tomcat-7.0.82 tomcat
配置环境变量
# vim /etc/profile.d/tomcat.sh
export CATALINA_HOME=/usr/local/tomcat
export PATH=$CATALINA_HOME/bin:$PATH
重读配置文件
# . /etc/profile.d/tomcat.sh
验证是否成功
# catalina.sh 如果能够显示帮助信息则表示安装成功
这里要导出 CATALINA_HOME 环境变量的原因与导出 JAVA_HOME 的原因一样。
(2) 启动
在 /usr/local/tomcat/bin 目录中有一个 bash 脚本文件 catalina.sh 作为 Tomcat 的启动脚本文件。如果要启动 Tomcat 该命令进行启动。
# catalina.sh start
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/latest
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
查看监听端口
# ss -tnl
请确保 8009|8005|8080 端口启动
使用浏览器进行访问,注意端口一定要是 8080:
Tomcat 的结构
Tomcat 目录结构:
bin:脚本以及启动时用到的类
lib:类库
conf:配置文件
logs:日志文件
webapps:应用程序默认部署目录
work:工作目录
temp:临时文件目录
Tomcat 的配置文件:
server.xml:Tomcat 的主配置文件,包含Service, Connector, Engine, Realm, Valve, Hosts 等组件的相关配置信息
context.xml:每个 webapp 都可以有专用的配置文件,这些配置文件通常位于 webapp 应用程序目录下的 WEB-INF 目录中,用于定义回话管理器、JDBC 等; conf/context.xml 是为个 webapp 提供默认配置
web.xml:每个 webapp “部署”之后才能被访问,此文件则用于为所有的 webapp 提供默认部署相关的配置
tomcat-users.xml:Realm 认证时用到的相关角色、用户和密码等信息;Tomcat 自带的 manager 默认情况下会用到此文件;在 Tomcat 中添加/删除用户,为用户指定角色等将通过编辑此文件实现
catalina.policy:当使用 -security 选项启动 tomcat 实例时会读取此配置文件来实现其安全运行策略
catalina.properties:Java 属性的定义文件,用于设定类加载器路径等,以及一些 JVM 性能相关的调优参数
logging.properties:Tomcat 6 通过自己内部实现的 JAVA 日志记录器来记录操作相关的日志,此文件即为日志记录器相关的配置信息,可以用来定义日志记录的组件级别以及日志文件的存在位置等
Tomcat 的 server.xml 配置文件遵循 XML 格式的语法,组成框架:
<server>
<service>
<connector />
...
<engine>
<host>
<context />
...
</host>
...
</engine>
</service>
</server>
组件说明:
Server:Tomcat 的一个实例,通常一个 JVM 只能包含一个 Tomcat 实例;因此,一台物理服务器上可以在启动多个 JVM 的情况下在每一个 JVM 中启动一个 Tomcat 实例,每个实例分属于一个独立的管理端口。这是一个顶级组件。
Service:一个服务组件通常包含一个引擎和与此引擎相关联的一个或多个连接器。给服务命名可以方便管理员在日志文件中识别不同服务产生的日志。一个server可以包含多个service组件,但通常情下只为一个service指派一个server。这是一个服务类组件
Connectors:负责连接客户端(可以是浏览器或Web服务器)请求至Servlet容器内的Web应用程序,通常指的是接收客户发来请求的位置及服务器端分配的端口。默认端口通常是HTTP协议的8080,管理员也可以根据自己的需要改变此端口。一个引擎可以配置多个连接器,但这些连接器必须使用不同的端口。默认的连接器是基于HTTP/1.1的Coyote。同时,Tomcat也支持AJP、JServ和JK2连接器。这是一个容器类组件。
Engine:引擎通常是指处理请求的Servlet引擎组件,即Catalina Servlet引擎,它检查每一个请求的HTTP首部信息以辨别此请求应该发往哪个host或context,并将请求处理后的结果返回的相应的客户端。严格意义上来说,容器不必非得通过引擎来实现,它也可以是只是一个容器。如果Tomcat被配置成为独立服务器,默认引擎就是已经定义好的引擎。而如果Tomcat被配置为Apache Web服务器的提供Servlet功能的后端,默认引擎将被忽略,因为Web服务器自身就能确定将用户请求发往何处。一个引擎可以包含多个host组件。
Host:主机组件类似于Apache中的虚拟主机,但在Tomcat中只支持基于FQDN的“虚拟主机”。一个引擎至少要包含一个主机组件。
Context:Context组件是最内层次的组件,它表示Web应用程序本身。配置一个Context最主要的是指定Web应用程序的根目录,以便Servlet容器能够将用户请求发往正确的位置。Context组件也可包含自定义的错误页,以实现在用户访问发生错误时提供友好的提示信息。
Valve:用来拦截请求并在将其转至目标之前进行某种处理操作,类似于Servlet规范中定义的过滤器。Valve可以定义在任何容器类的组件中。Valve常被用来记录客户端请求、客户端IP地址和服务器等信息,这种处理技术通常被称作请求转储(request dumping)。请求转储valve记录请求客户端请求数据包中的HTTP首部信息和cookie信息文件中,响应转储valve则记录响应数据包首部信息和cookie信息至文件中。
Logger:用于记录组件内部的状态信息,可被用于除Context之外的任何容器中。日志记录的功能可被继承,因此,一个引擎级别的Logger将会记录引擎内部所有组件相关的信息,除非某内部组件定义了自己的Logger组件。
Realm:用于用户的认证和授权;在配置一个应用程序时,管理员可以为每个资源或资源组定义角色及权限,而这些访问控制功能的生效需要通过Realm来实现。Realm的认证可以基于文本文件、数据库表、LDAP服务等来实现。Realm的效用会遍及整个引擎或顶级容器,因此,一个容器内的所有应用程序将共享用户资源。同时,Realm可以被其所在组件的子组件继承,也可以被子组件中定义的Realm所覆盖。
Tomcat 目录中 webapps 组织结构:
有特定的组织形式、层次型的目录结构:主要包含了servlet代码文件、JSP页面文件、类文件、部署描述符文件等
我们在浏览器中输入服务器端 IP 地址访问的时候实际上是以 webapps 作为访问的根目录,而 ROOT 目录又是 webapps 目录下的默认访问目录。这是在配置文件 server.xml 中定义了的:
125 <Host name="localhost" appBase="webapps"
当访问 localhost 的时候实际上的访问路径应该是 Tomcat 所在路径下的 webapps 目录
126 unpackWARs="true" autoDeploy="true">
当我们需要自定义更改访问目录的时候可以对配置文件进行修改,除了要修改配置文件之外,还需要在程序所在目录下放置以下目录及文件:
WEB-INF/: 当前 webapp 的私有资源目录,通常存放当前 webapp 自用的 web.xml
META-INF/: 当前 webapp 的私有资源目录,通常存放当前 webapp自用的 context.xml
classes/: 此 webapp 的私有类
lib/: 此 webapp 的私有类,被打包为 jar 格式类
index.jsp: webapp的主页
不过为了方便,一般都是在 webapps 目录下直接创建用户自定义的目录,这样类库文件就可以使用系统自带的类库文件
# pwd
/usr/local/tomcat/webapps
创建目录
# mkdir -pv test/{WEB-INF,META-INF}
# vim test/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>JSP Test Page</title>
</head>
<body>
<% out.println("Hello, world."); %>
</body>
</html>
直接在浏览器中输入 URL 进行访问,不需要重启:
可能大家有疑问,为什么在输入 URL 的时候后面需要加上 test?
刚才已经说过了,webapps 作为系统默认的访问入口,而 ROOT 又是 webapps 下的默认访问目录,所以我们在访问系统主页的时候可以直接使用 “地址+端口” 的形式进行访问。这个时候系统自动给我们重定向到了 ROOT 目录下,显示出来的结果是 ROOT/index.jsp 的结果。而现在我们需要访问我们自己定义的主页 test/index.jsp,所以这时候要在路径后面加上我们所定义的目录,这样才能访问到 test/index.jsp。
Tomcat 目录中 work 组成结构
work/
└── Catalina
└── localhost
├── _
│ └── org
│ └── apache
│ └── jsp
│ ├── index_jsp.class
│ └── index_jsp.java
├── docs
├── examples
├── host-manager
├── manager
└── test
└── org
└── apache
└── jsp
├── index_jsp.class
└── index_jsp.java
这是 work 目录的组成结构,我们会发现,我们自己所定义的 test/index.jsp 文件被编译成了 index-jsp.java 文件以及 index_jsp.class 字节码。这里要涉及到 Tomcat 的运行方式了:
这里就涉及到了 JSP 文档在 Tomcat 的运行方式了。JSP 文件首先会在被 JSP 的解释器解释成 Servlet 格式的 Java 语言,也就是 .java 格式的文件 (因为在 JSP 文件中有 html 格式的语言,而 Java 并不能够识别 html 格式的语言,所以这里要使用 JSP 的编译器 (Jasper) 将 html 格式的语言解释成纯 Java 代码,也就是 Servlet 格式的文件)。之后再通过 JVM 编译成 .class 文档才能运行。tomcat 运行时,JSP 文件第一次被编译的时候会在 Tomcat 所在的目录下的 work 目录下生成 .class 文件(注意,work 目录很深,这里可以使用 tree 命令查看),而在之后的访问中,Tomcat 就会直接从 work 目录下直接找 .class 文件。所以 Tomcat 有一个特性,那就是第一次访问会很慢,而在之后的访问中就会很快了。不仅如此,Tomcat 会自动监控源文件是否发生改变,如果发生改变,Tomcat 会自动将 JSP 文件重新解释成 Servlet 文件,然后编译成 clas s文件
而我们注意到 localhost 目录下放置的是 test 目录,而我们明明将 test
目录放置在了 webapps 目录下。这进一步证明 webapps 就是浏览器访问的根目录。而在 localhost 目录下就是没有 ROOT 目录,反而有一个 “-” 这个特殊符号。这就表示 ROOT 目录就是默认的访问路径。在这个目录下的命令方式很奇怪,都是以 org-apache-jsp 开始的。这是 Tomcat 独特的命名方式,因为 Tomcat 这个开源项目是 Apache 软件基金会旗下顶级项目。
END,未完待续