tomcat官方提供了自身的管理界面,我们可以根据其实现原理改造和移植其相关功能。主要有以下功能:
(1)每个war服务状态,并提供了启动(start)、停止(stop)、卸载(Undeploy)、重新发布(Reload)以及设置session过期时间等。
(2)查看JVM相关内存使用情况
(3)查看对外服务提供的请求等处理情况等
(4)每个war服务中相关请求的执行处理情况等。
首先对于tomcat中war服务,我们可以对实现这些war服务进行启动、停止、卸载、重新加载及获取所有war服务状态的功能。
1、创建MyHostConfig用来继承Tomcat的HostConfig类,主要目的是获取Tomcat的Host对象
public class MyHostConfig extends HostConfig {
private static final Log log = LogFactory.getLog(MyHostConfig.class);
//获取tomcat的host对象
public static Host myHost = null;
//重写HostConfig的lifecycleEvent方法
@Override
public void lifecycleEvent(LifecycleEvent event) {
// Identify the host we are associated with
try {
host = (Host) event.getLifecycle();
if (host instanceof StandardHost) {
setCopyXML(((StandardHost) host).isCopyXML());
setDeployXML(((StandardHost) host).isDeployXML());
setUnpackWARs(((StandardHost) host).isUnpackWARs());
setContextClass(((StandardHost) host).getContextClass());
//获取tomcat的host对象
myHost = host;
}
} catch (ClassCastException e) {
log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
return;
}
// Process the event that has occurred
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}
}
将我们自己实现的MyHostConfig对象配置到tomcat的server.xml中,目的是取代其自身实现的HostConfig对象。
然后将MyHostConfig类所在的jar包打包放到tomcat的lib目录下即可,这样我们就可以获取到Host对象,就可以对war包进行启动、停止、重写加载和卸载等操作了。
2、创建一个web服务并在Servlet中获取到myHost对象,代码实现如下:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.util.ContextName;
import com.alibaba.fastjson.JSON;
import com.tianjunwei.tomcat.mointor.MyHostConfig;
public class WarMonitorServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
doGet(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException{
Host host = MyHostConfig.myHost;
//path名称为war的上下文名称
String path = request.getParameter("path");
ContextName cn = null;
if (path != null) {
cn = new ContextName(path, request.getParameter("version"));
}
//path路径为start、stop、reload、status和undeploy命令
String command = request.getPathInfo();
PrintWriter writer = response.getWriter();
if(command == null) {
writer.write("command is null");
}else if (command.equalsIgnoreCase("/start")) {
boolean result = start(host, cn);
writer.write(""+result);
}else if (command.equalsIgnoreCase("/stop")) {
boolean result = stop(host, cn);
writer.write(""+result);
}else if (command.equalsIgnoreCase("/reload")) {
boolean result = reload(host, cn);
writer.write(""+result);
}else if (command.equalsIgnoreCase("/undeploy")) {
boolean result = undeploy(host, cn);
writer.write(""+result);
}else if (command.equalsIgnoreCase("/status")) {
String status = status(host);
writer.write(status);
}
writer.flush();
}
/*
* 获取所有war服务状态
*/
public static String status(Host host) {
Map warStatus = new HashMap();
if(host != null){
Container [] containers = host.findChildren();
for(int i=0; i< containers.length;i++){
String name = containers[i].getName();
String status = containers[i].getStateName();
if(name != null && name.length() > 0){
warStatus.put(name, status);
}else {
warStatus.put("/", status);
}
}
}
return JSON.toJSONString(warStatus);
}
/*
* 启动war服务
*/
public static boolean start(Host host,ContextName cn) {
Context context = (Context) host.findChild(cn.getName());
if (context == null) {
return false;
}
try {
context.start();
} catch (LifecycleException e) {
return false;
}
return true;
}
/*
* 停止war服务
*/
public static boolean stop(Host host,ContextName cn) {
Context context = (Context) host.findChild(cn.getName());
if (context == null) {
return false;
}
try {
context.stop();
} catch (LifecycleException e) {
return false;
}
return true;
}
/*
* 重新加载war服务
*/
public static boolean reload(Host host,ContextName cn) {
Context context = (Context) host.findChild(cn.getName());
if (context == null) {
return false;
}
try {
context.reload();
} catch (Exception e) {
return false;
}
return true;
}
/*
* 卸载war服务,并删除war文件
*/
public static boolean undeploy(Host host,ContextName cn) {
String name = cn.getName();
String baseName = cn.getBaseName();
Context context = (Context) host.findChild(name);
try {
context.stop();
} catch (LifecycleException e) {
return false;
}
try {
File war = new File(host.getAppBaseFile(), baseName + ".war");
File dir = new File(host.getAppBaseFile(), baseName);
if (war.exists() && !war.delete()) {
return false;
} else if (dir.exists() && !undeployDir(dir)) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
/*
* 清理超过某个时间的session
*/
public static boolean expire(Host host,ContextName cn, int idle) {
Context context = (Context) host.findChild(cn.getName());
if(context == null) {
return false;
}
Manager manager = context.getManager() ;
if(manager == null) {
return false;
}
int maxCount = 60;
int histoInterval = 1;
int maxInactiveInterval = context.getSessionTimeout();
if (maxInactiveInterval > 0) {
histoInterval = maxInactiveInterval / maxCount;
if (histoInterval * maxCount < maxInactiveInterval)
histoInterval++;
if (0 == histoInterval)
histoInterval = 1;
maxCount = maxInactiveInterval / histoInterval;
if (histoInterval * maxCount < maxInactiveInterval)
maxCount++;
}
Session [] sessions = manager.findSessions();
for (int i = 0; i < sessions.length; i++) {
int time = (int) (sessions[i].getIdleTimeInternal() / 1000L);
if (idle >= 0 && time >= idle*60) {
sessions[i].expire();
}
}
return true;
}
protected static boolean undeployDir(File dir) {
String files[] = dir.list();
if (files == null) {
files = new String[0];
}
for (int i = 0; i < files.length; i++) {
File file = new File(dir, files[i]);
if (file.isDirectory()) {
if (!undeployDir(file)) {
return false;
}
} else {
if (!file.delete()) {
return false;
}
}
}
return dir.delete();
}
}
在web.xml中配置servlet的信息
war-monitor
com.tianjunwei.tomcat.servlet.WarMonitorServlet
war-monitor
/war_monitor/*
将war包放到tomcat的webapp目录下启动,接下来通过浏览器可以进行servlet调用进行war服务的状态查看、启动、停止、重新加载和卸载操作(这个权限还是很大的,可以做一些登录限制或者基础SSO或oauth等)。
(1)查看所有war状态:http://localhost:8080/war_mointor/war_monitor/status
war的状态有:NEW,INITIALIZING,INITIALIZED,STARTING_PREP,STARTING,STARTED,STOPPING_PREP,STOPPING,STOPPED,DESTROYING,DESTROYED,FAILED
(2)war停止:http://localhost:8080/war_mointor/war_monitor/stop?path=/examples
(3)war启动:http://localhost:8080/war_mointor/war_monitor/start?path=/examples
代码地址Github