Tomcat学习--war服务相关状态信息监控

Tomcat官方管理

    tomcat官方提供了自身的管理界面,我们可以根据其实现原理改造和移植其相关功能。主要有以下功能:

(1)每个war服务状态,并提供了启动(start)、停止(stop)、卸载(Undeploy)、重新发布(Reload)以及设置session过期时间等。

Tomcat学习--war服务相关状态信息监控_第1张图片

(2)查看JVM相关内存使用情况

Tomcat学习--war服务相关状态信息监控_第2张图片

(3)查看对外服务提供的请求等处理情况等

Tomcat学习--war服务相关状态信息监控_第3张图片

(4)每个war服务中相关请求的执行处理情况等。

Tomcat学习--war服务相关状态信息监控_第4张图片

Tomcat管理改造

首先对于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


你可能感兴趣的:(Tomcat原理及源码学习,Tomcat原理学习)