为了将Tomcat服务器嵌入到 Java应用中,需要用到Tomcat API中的一些类,最主要的一个类是 org.apache.catalina.startup.Tomcat类。Tomcat类的主要方法描述见下表,也可以参考Tomcat的API文档,网址为:http://tomcat.apache.org/tomcat-9.0-doc/api/index.html
方法 | 描述 |
---|---|
setBaseDir | 设置Tomcat服务器的跟路径 |
getServer | 返回Server对象。如果Server不存在,就创建一个标准的Server,并将它返回 |
getEngine | 返回Engine对象。如果Engine不存在,就创建一个标准的Engine,并将它返回 |
getHost | 返回Host对象。如果Host不存在,就创建一个标准的Host,并将它返回 |
getConnector | 返回HTTP Connector对象。如果Connector不存在,就创建一个默认的Connector,并将它返回 |
addWebapp | 把一个Web应用加入到Tomcat的服务器中 |
start | 启动Tomcat服务器 |
stop | 停止Tomcat服务器 |
默认情况下,这些组件在server.xml文件中进行配置。如果把Tomcat嵌入到Java应用中,这个配置文件就无用了,所以必须通过程序来配置这些组件的实例。
Tomcat类的start()的方法负责启动Tomcat服务器,它会先调用 getServer()方法:
public void start() throws LifecycleException {
getServer();
server.start();
}
Tomcat类的getServer()方法返回Server对象,如果Server对象不存在,会创建标准的 Server对象和 Service对象,然后将再让他们返回:
public Server getServer() {
if (server != null) {
return server;
}
System.setProperty("catalina.userNaming", "false");
server = new StandardServer();
initBaseDir();
server.setPort(-1);
Service service = new StandardService();
service.setName("Tomcat");
server.addService(service);
return server;
}
Tomcat类的addWebapp()方法责把一个Web应用加入到Tomcat服务器中,并且返回相应的Context对象。addWebapp()方法有多种重载形式,这些重载形式的addWebapp()方法会先调用getHost()方法,确保Host对象已经创建:
public Context addWebapp(Host host, String contextPath, String docBase) {
LifecycleListener listener = null;
try{
Class<?> clazz = Class.forName(getHost().getConfigClass());
listener = (LifecycleListener) clazz.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(e);
}
return addWebapp(host, contextPath, docBase, listener);
}
而Tomcat类的 getHost()方法会先调用的 getEngine()方法,确保Engine对象已经创建。并且如果Host不存在,会创建标准的Host对象:
publicf Host getHost() {
Engine engine = getEngine();
if (engine.findChildren().length > 0) {
return (Host) engine.findChildren()[0];
}
Host host = new StandardHost();
host.setName(hostname);
getEngine().addChild(host);
return host;
}
下面创建一个EmbeddedTomcat类,在该程序中创建了一个嵌入式 Tomcat服务器,并且加入了一个默认的Web应用,以及examples应用和docs应用。
import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
public class EmbeddedTomcat {
private Tomcat tomcat;
public void start(int port,String baseDir) throws LifecycleException {
tomcat = new Tomcat();
//设置服务器以及虚拟主机的根路径
tomcat.setBaseDir(".");
tomcat.getHost().setAppBase(baseDir);
//设置监听端口
tomcat.setPort(port);
//获得连接器,如果还没有连接器,就会先创建一个默认的连接器
Connector connector=tomcat.getConnector();
//加入默认的web应用
Context context1=tomcat.addWebapp("", baseDir+"/ROOT");
//加入examples应用
Context context2=tomcat.addWebapp("/examples", baseDir+"/examples");
//加入docs应用
Context context3=tomcat.addWebapp("/docs", baseDir+"/docs");
tomcat.start();
//启动服务器(启动后台线程)
//终止服务器的办法一:主线程调用Tomcat类的stop()方法
/*
try{
//主线程睡眠60*60秒后关闭服务器
Thread.sleep(60000*60);
stop();
}catch(Exception e){e.printStackTrace();}
*/
//终止服务器的办法二:监听8005端口的SHUTDOWN命令
StandardServer server = (StandardServer) tomcat.getServer();
//设置服务器监听SHUTDOWN命令的端口
server.setPort(8005);
server.await(); //主线程进入等待状态,直到接收到SHUTDOWN命令
}
public void stop() throws LifecycleException {
tomcat.stop();
//关闭Tomcat服务器
}
public static void main(String[] args) {
try{
int port=8080;
String baseDir = "C:/tomcat/webapps";
EmbeddedTomcat tomcat = new EmbeddedTomcat();
tomcat.start(port, baseDir);
}catch (Exception e) {
e.printStackTrace();
}
}
}
分析上述代码:
创建Tomcat对象,并且设置它的根路径,接收HTTP请求使用的端口号,以及他的虚拟主机的根路径:
tomcat = new Tomcat();
//设置服务器以及虚拟主机的根路径
tomcat.setBaseDir(".");
tomcat.getHost().setAppBase(baseDir);
//设置监听端口
tomcat.setPort(port);
通过Tomcat的对象的getConnector()方法创建并返回默认的HTTP Connector连接器。在Tomcat9以前的版本中,这不是必须的步骤。而在Tomcat9中,这个步骤是必须的,他确保创建默认的连接器,:
Connector connector=tomcat.getConnector();
向Tomcat的服务器中加入Web应用:
//加入默认的web应用
Context context1=tomcat.addWebapp("", baseDir+"/ROOT");
//加入examples应用
Context context2=tomcat.addWebapp("/examples", baseDir+"/examples");
//加入docs应用
Context context3=tomcat.addWebapp("/docs", baseDir+"/docs");
Tomcat类的 addWebapp(String contextPath, String docBase) 方法的第一个参数 contextPath 指定访问Web应用的 URL入口。当 contextPath 参数的值为"",表示虚拟主机的默认Web应用,第二个参数docBase指定 Web应用所在的文件路径的根路径。访问以上三个Web应用的URL分别为:
http://localhost:8080
http://localhost:8080/examples
http://localhost:8080/docs
启动Tomcat服务,main 主线程进入等待状态:
tomcat.start(); //启动服务器(启动后台线程)
StandardServer server = (StandardServer) tomcat.getServer();
//设置服务器监听SHUTDOWN命令的端口
server.setPort(8005);
server.await(); //main主线程进入等待状态,直到接收到SHUTDOWN命令,就会终止服务器
tomcat.start()方法启动Tomcat的服务器,该服务器启动工作线程池来响应客户端的HTTP请求。线程池中的工作线程为后台线程。所谓后台线程,是指它的生命周期依赖于 main主线程。只要主线程未结束生命周期,后台线程也会一直运行,当主线程结束生命周期,后台线程也会自动结束生命周期。
有两种办法。
下面创建一个TomcatManager类,他利用 Socket向8005端发送 “SHUTDOWN” 命令,从而终止服务器。
import java.net.*;
import java.io.*;
import java.util.*;
public class TomcatManager {
public static void main(String args[]){
Socket socket=null;
String host="localhost";
int port=8005;
try{
socket=new Socket(host,port); //与Tomcat建立FTP连接
}catch(Exception e){e.printStackTrace();}
try{
String command="SHUTDOWN";
/*发送HTTP请求*/
OutputStream socketOut=socket.getOutputStream();//获得输出流
socketOut.write(command.getBytes());
Thread.sleep(2000); //睡眠2秒
System.out.println("已经发送SHUTDOWN命令");
}catch(Exception e){
e.printStackTrace();
}finally{
try{
socket.close();
}catch(Exception e){e.printStackTrace();}
}
}
}
编译和运行本范例程序时,应该到官方网站下载与嵌入式Tomcat服务器相关的类库,下载得到的文件为apache-tomcat-X-embed.zip,解压这个文件,把其中所有的 JAR文件加入到 lib目录中。