不让人省心的Tomcat,前前后后让我折腾了好长时间。
Tomcat介绍
在英语世界里,tomcat 是指 “经常找女人鬼混的一类男人”。
在Java世界里,是一个 坑虽然多 但依然被广泛应用的 免费的 开源的 Web应用服务器 。
在我的眼里,Tomcat是一只有些调皮惹人烦的猫,不然它也不会让我折腾这么久了。
背景 & 目标
我最初接触动态网站开发是从PHP(The best language in the world)开始的,大三开始接触Java并用这门语言来开发网站,内心是有一些排斥的。
与PHP比起来,用Java开发Web的效率很低(其中有很大一部分原因是因为我不熟悉Java),总感觉Java语法繁琐不优雅(不敢和 Object C 这门语言比),然而Java又有很多优势是PHP无可比拟的。因此,通过对 PHP这只“大象” 以及 Tomcat这只“色情猫” 的认识和了解,我今后在做 后端 和 动态网站的开发 我有选择的权利的情况下,我会将两门语言的优势和短板充分考虑,在不同的场景下做出不同的选择。
目标分为如下三个:
- 项目导出 - 将开发好的Java Web项目导出为War包。
- 项目配置 - 装配Tomcat - 安装和配置Web应用服务器Tomcat,其中写XML配置文件会消耗大量的功力。
- 项目部署 - 把项目成功部署到Linux服务器上。
项目导出
我用的是IntelliJ IDEA这款IDE进行的Java web项目的开发。
首先来了解一下这两个项目结构设置中的概念。
Facets
facets - 相近的英文解释为 “某方面的特征”,在这里表示某个Module的特性。
Facets表述了在Module中使用的各种各样的框架、技术和语言。 这些Facets让Intellij IDEA知道怎么对待module内容,并保证与相应的框架和语言保持一致。 使用Facets能让我们下载并配置framework所必须的组件,会自动生成各种各样的描述符,并存储在适当的位置等信息。
Artifacts
artifacts - 相近的英文解释为“人工制造的产品”,在这里是 maven 中的一个概念。
artifact是一个项目资源的组合体。 例如,一个已编译的java类的集合,一个已打包的java应用。 artifacts打包出来的形式有多种,如 jar、war、war exploded、ear 等。
配置好了Artifacts的module才能打包成War包。
开始导出
在IDEA中进入Project Structure菜单(右击项目->Open Module Settings)进入 Facets 和 Artifacts 的配置。
点击Facets选项卡,检查Facets中是否已经存在Modules。往里面添加内容,如果存在,就可以开始设置导出War包。
点击Artifacts选项卡,进行War包的配置,详细步骤省略(因为不是本文讨论的重点)。
点击Build进行构建,构造完成之后打开out文件夹检查构建好的内容。
查看out文件夹中,artifacts文件夹中导出的以war为后缀的文件便是我们后续步骤要用到的War包。
项目配置
假定已经安装配置好了Tomcat,主要讨论一下Tomcat的配置文件的编写。
server.xml
server.xml 中每一个元素都对应了Tomcat中的一个组件,通过对xml文件中元素的配置,可以实现对Tomcat中各个组件的控制。
顶层元素:和
元素是整个配置文件的根元素
元素则代表一个Engine元素以及一组与之相连的Connector元素
连接器:
代表了外部客户端发送请求到特定Service的接口;同时也是外部客户端从特定Service接收响应的接口。
容器:
容器的功能是处理Connector接收进来的请求,并产生相应的响应。
Engine、Host和Context都是容器,但它们不是平行的关系,而是父子关系:Engine包含Host,Host包含Context。
一个Engine组件可以处理Service中的所有请求,
一个Host组件可以处理发向一个特定虚拟主机的所有请求,
一个Context组件可以处理一个特定Web应用的所有请求。
配置实例
配置Tomcat启动后,将 /www/wwwroot/EasyDataTable 目录下的 war 包自动解压。
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" />
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log" suffix=".txt" />
</Host>
<Host appBase="/www/wwwroot/EasyDataTable" autoDeploy="false" name="data.share-man.com" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
<Context path="" docBase="/www/wwwroot/EasyDataTable/EasyDataTableWar" reloadable="false" />
</Host>
</Engine>
</Service>
</Server>
项目部署
我们的项目部署需要让 Nginx 和 Tomcat 配合起来使用。
虽然 Nginx / Apache 和 Tomcat 都是 Web Server,但两者有着不同的分工。
Nginx / Apache 是 HTTP Web Server。
一个 HTTP Server 关心的是 HTTP 协议层面的传输和访问控制,所以在 Apache/Nginx 上你可以看到代理、负载均衡等功能。 客户端通过 HTTP Server 访问服务器上存储的资源(HTML 文件、图片文件等等)。 通过 CGI 技术,也可以将处理过的内容通过 HTTP Server 分发,但是一个 HTTP Server 始终只是把服务器上的文件如实的通过 HTTP 协议传输给客户端。
Tomcat 是 Application Web Server (Servlet / JSP)。
而应用服务器,则是一个应用执行的容器。 它首先需要支持开发语言的 Runtime(对于 Tomcat 来说,就是 Java),保证应用能够在应用服务器上正常运行。 其次,需要支持应用相关的规范,例如类库、安全方面的特性。 对于 Tomcat 来说,就是需要提供 JSP/Sevlet 运行需要的标准类库、Interface 等。 为了方便,应用服务器往往也会集成 HTTP Server 的功能,但是不如专业的 HTTP Server 那么强大,所以应用服务器往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server 分发到客户端。
Nginx配置
如下配置中着重看 #TOMCAT-START 和 #TOMCAT-END 之间的内容。
这里的配置指明 Nginx 这个 HTTP Web Server 如何代理请求并交由 Tomcat 这个 Application Web Server 。
server
{
listen 80;
server_name data.share-man.com;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/EasyDataTable/EasyDataTableWar;
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
error_page 404 /404.html;
error_page 502 /502.html;
#ERROR-PAGE-END
#TOMCAT-START
location /
{
proxy_pass "http://data.share-man.com:8080";
proxy_set_header Host data.share-man.com;
proxy_set_header X-Forwarded-For $remote_addr;
}
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
expires 12h;
}
#TOMCAT-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log off;
access_log off;
}
location ~ .*\.(js|css)?$
{
expires 12h;
error_log off;
access_log off;
}
access_log /www/wwwlogs/data.share-man.com.log;
error_log /www/wwwlogs/data.share-man.com.error.log;
}
通过 proxy_pass 配置请求转发地址。即当访问 data.share-man.com 的80端口时,请求会跳转至 data.share-man.com 的8080端口处。