JMX获取Tomcat管理信息

1、首先配置JVM
JVM要放到NTFS卷中,在JVM路径下找到jmxremote.access及jmxremote.password.template两个文件。
将jmxremote.password.template复制一份为jmxremote.password,对运行用户可读,对普通用户不可读。

2、配置Tomcat启动参数
修改catalina.bat,增加下面一行

SET "JAVA_OPTS=%JAVA_OPTS% -Dcom.sun.management.jmxremote.port=8686 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true"

3、启动Tomcat

4、客户端程序JMXInfo.java

package com.neohope.jmx.test;

import java.io.IOException;
import java.lang.management.MemoryUsage;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class JMXInfo {
	public static void main(String[] args) throws Exception {
		JMXConnector connector = null;
		try {
			// 获取JMX连接
			String ip = "127.0.0.1";
			String port = "8686";
			JMXServiceURL serviceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + ip + ":" + port + "/jmxrmi");
			Map<String, String[]> map = new HashMap<String, String[]>();
			String[] credentials = new String[] { "controlRole", "R&D" };
			map.put("jmx.remote.credentials", credentials);
			connector = JMXConnectorFactory.connect(serviceURL, map);
			MBeanServerConnection mbsc = connector.getMBeanServerConnection();

			// 获取JVM信息
			ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime");
			System.out.println("厂商:" + (String) mbsc.getAttribute(runtimeObjName, "VmVendor"));
			System.out.println("程序:" + (String) mbsc.getAttribute(runtimeObjName, "VmName"));
			System.out.println("版本:" + (String) mbsc.getAttribute(runtimeObjName, "VmVersion"));
			
			// 获取JVM运行时间
			Date starttime = new Date((Long) mbsc.getAttribute(runtimeObjName, "StartTime"));
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			System.out.println("启动时间:" + df.format(starttime));
			Long timespan = (Long) mbsc.getAttribute(runtimeObjName, "Uptime");
			System.out.println("持续工作时间:" + JMXInfo.formatTimeSpan(timespan));

			// 获取JVM内存信息
			ObjectName heapObjName = new ObjectName("java.lang:type=Memory");
			MemoryUsage heapMemoryUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "HeapMemoryUsage"));
			long heapMaxMemory = heapMemoryUsage.getMax();
			long heapCommitMemory = heapMemoryUsage.getCommitted();
			long heapUsedMemory = heapMemoryUsage.getUsed();
			System.out.println("heap:" + (double) heapUsedMemory * 100 / heapCommitMemory + "%");

			MemoryUsage nonheapMemoryUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "NonHeapMemoryUsage"));
			long nonHeapCommitMemory = nonheapMemoryUsage.getCommitted();
			long nonHeapUsedMemory = heapMemoryUsage.getUsed();
			System.out.println("nonheap:" + (double) nonHeapUsedMemory * 100 / nonHeapCommitMemory + "%");

			ObjectName permObjName = new ObjectName("java.lang:type=MemoryPool,name=Perm Gen");
			MemoryUsage permGenUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(permObjName, "Usage"));
			long permCommitted = permGenUsage.getCommitted();
			long permUsed = heapMemoryUsage.getUsed();
			System.out.println("perm gen:" + (double) permUsed * 100 / permCommitted + "%");
			
			// All Domains
			for (int j = 0; j < mbsc.getDomains().length; j++) {
				System.out.println(mbsc.getDomains()[j]);
			}
			
			// All MBeans
			Set<ObjectInstance> MBeanset = mbsc.queryMBeans(null, null);
			System.out.println("MBeanset.size() : " + MBeanset.size());
			Iterator<ObjectInstance> MBeansetIterator = MBeanset.iterator();
			while (MBeansetIterator.hasNext()) {
				ObjectInstance objectInstance = (ObjectInstance) MBeansetIterator.next();
				ObjectName objectName = objectInstance.getObjectName();
				String canonicalName = objectName.getCanonicalName();
				System.out.println("canonicalName : " + canonicalName);
			}
			
			// 全部线程池
			ObjectName threadpoolObjName = new ObjectName("Catalina:type=ThreadPool,*");
			Set<ObjectName> s2 = mbsc.queryNames(threadpoolObjName, null);
			for (ObjectName obj : s2) {
				System.out.println("端口名:" + obj.getKeyProperty("name"));
				ObjectName objname = new ObjectName(obj.getCanonicalName());
				System.out.println("最大线程数:" + mbsc.getAttribute(objname, "maxThreads"));
				System.out.println("当前线程数:" + mbsc.getAttribute(objname, "currentThreadCount"));
				System.out.println("繁忙线程数:" + mbsc.getAttribute(objname, "currentThreadsBusy"));
			}
			
			//HTTP Thread Pool
			ObjectName threadPoolObjName = new ObjectName("Catalina:type=ThreadPool,*");
			Set<ObjectName> threadPoolObjNames = mbsc.queryNames(threadPoolObjName, null);
			for (ObjectName obj : threadPoolObjNames) {
				if (obj.getKeyProperty("name").contains("http")) {
					ObjectName objname = new ObjectName(obj.getCanonicalName());
					System.out.println("HTTP最大线程数:"+ mbsc.getAttribute(objname, "maxThreads").toString());// 最大线程数
					System.out.println("HTTP当前线程数:"+ mbsc.getAttribute(objname, "currentThreadCount").toString());// 当前线程数
					System.out.println("HTTP繁忙线程数:" + mbsc.getAttribute(objname, "currentThreadsBusy").toString());// 繁忙线程数
				}
			}

			// 全部应用
			ObjectName managerObjName = new ObjectName("Catalina:type=Manager,*");
			Set<ObjectName> s = mbsc.queryNames(managerObjName, null);
			for (ObjectName obj : s) {
				System.out.println("应用名:" + obj.getKeyProperty("path"));
				ObjectName objname = new ObjectName(obj.getCanonicalName());
				System.out.println("最大会话数:" + mbsc.getAttribute(objname, "maxActiveSessions"));
				System.out.println("会话数:" + mbsc.getAttribute(objname, "activeSessions"));
				System.out.println("活动会话数:" + mbsc.getAttribute(objname, "sessionCounter"));
			}
			
			
			//RequestProcessor
			ObjectName requestObjName = new ObjectName("Catalina:type=RequestProcessor,*");
			Set<ObjectName> requestObjNameSet = mbsc.queryNames(requestObjName, null);
			Integer aliveSocketsCount = 0;
			Long maxProcessingTime = 0L;
			Long processingTime = 0L;
			Long requstCount = 0L;
			Long errorCount = 0L;
			BigDecimal bytesReceived = BigDecimal.ZERO;
			BigDecimal bytesSend = BigDecimal.ZERO;
			for (ObjectName obj : requestObjNameSet) {
				if (mbsc.getAttribute(obj, "stage").toString().trim().equals("1"))
					aliveSocketsCount++;
				long nowMaxProcessingTime = Long.parseLong(mbsc.getAttribute(obj, "maxTime").toString());
				if (maxProcessingTime < nowMaxProcessingTime)
					maxProcessingTime = nowMaxProcessingTime;
				processingTime += Long.parseLong(mbsc.getAttribute(obj, "processingTime").toString());
				requstCount += Long.parseLong(mbsc.getAttribute(obj, "requestCount").toString());
				errorCount += Long.parseLong(mbsc.getAttribute(obj, "errorCount").toString());
				bytesReceived = bytesReceived.add(new BigDecimal(mbsc.getAttribute(obj, "bytesReceived").toString()));
				bytesSend = bytesSend.add(new BigDecimal(mbsc.getAttribute(obj, "bytesSent").toString()));
			}
			System.out.println("活动sockets计数:"+ aliveSocketsCount.toString());
			System.out.println("最大处理时间:"+ maxProcessingTime.toString());
			processingTime = processingTime / 1000;
			System.out.println("总处理时间:"+ processingTime.toString());
			System.out.println("请求总数:"+ requstCount.toString());
			System.out.println("错误总数:"+ errorCount.toString());
			System.out.println("接收字节数:"+ bytesReceived.divide(new BigDecimal(1024L * 1024))
					.setScale(2, RoundingMode.HALF_UP).toPlainString());
			System.out.println("发送字节数:"+
					bytesSend.divide(new BigDecimal(1024L * 1024)).setScale(2, RoundingMode.HALF_UP).toPlainString());

		} catch (Exception e) {
			e.printStackTrace();
		}
		finally
		{
			if(connector!=null)
			{
				try {
					connector.close();
				} catch (IOException e) {
				}
			}
		}
		
	}

	public static String formatTimeSpan(long span) {
		long minseconds = span % 1000;

		span = span / 1000;
		long seconds = span % 60;

		span = span / 60;
		long mins = span % 60;

		span = span / 60;
		long hours = span % 24;

		span = span / 24;
		long days = span;
		return (new Formatter()).format("%1$d天 %2$02d小时%3$02d分%4$02d秒%5$03d毫秒", days, hours, mins, seconds, minseconds)
				.toString();
	}
}

5.运行结果

厂商:Oracle Corporation
程序:Java HotSpot(TM) Client VM
版本:24.65-b04
启动时间:2016-06-21 20:57:37
持续工作时间:0天 00小时29分31秒018毫秒
heap:60.11998789417739%
nonheap:54.523986450299915%
perm gen:165.7018025716146%
Users
JMImplementation
com.sun.management
Catalina
java.nio
java.lang
java.util.logging
MBeanset.size() : 150
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Servlet,name=HTMLManager
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Servlet,name=Manager
canonicalName : java.lang:type=Memory
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=stock
canonicalName : JMImplementation:type=MBeanServerDelegate
canonicalName : Catalina:context=/host-manager,host=localhost,name=StandardContextValve,type=Valve
canonicalName : Catalina:port=8080,type=Connector
canonicalName : Catalina:context=/examples,host=localhost,name=foo/name1,resourcetype=Context,type=Environment
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Filter,name=Tomcat WebSocket (JSR356) Filter
canonicalName : Catalina:context=/host-manager,host=localhost,type=WebappClassLoader
canonicalName : java.nio:name=mapped,type=BufferPool
canonicalName : java.lang:name=MarkSweepCompact,type=GarbageCollector
canonicalName : Catalina:context=/manager,host=localhost,name=StandardContextValve,type=Valve
canonicalName : Catalina:context=/examples,host=localhost,name=name3,resourcetype=Context,type=Environment
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/,j2eeType=Filter,name=Tomcat WebSocket (JSR356) Filter
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=default
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/,j2eeType=Servlet,name=jsp
canonicalName : Catalina:host=localhost,name=ErrorReportValve,type=Valve
canonicalName : Catalina:context=/host-manager,host=localhost,type=Cache
canonicalName : java.lang:name=Tenured Gen,type=MemoryPool
canonicalName : Catalina:context=/manager,host=localhost,name=BasicAuthenticator,type=Valve
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Filter,name=Tomcat WebSocket (JSR356) Filter
canonicalName : Catalina:type=Engine
canonicalName : Catalina:context=/,host=localhost,type=Manager
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Servlet,name=JMXProxy
canonicalName : Catalina:context=/docs,host=localhost,type=WebappClassLoader
canonicalName : java.lang:name=Code Cache,type=MemoryPool
canonicalName : java.util.logging:type=Logging
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,name=jsp,type=JspMonitor
canonicalName : Catalina:realmPath=/realm0/realm0,type=Realm
canonicalName : Catalina:name=StandardEngineValve,type=Valve
canonicalName : Catalina:port=8009,type=ProtocolHandler
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=RequestParamExample
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/
canonicalName : Catalina:context=/manager,host=localhost,type=Manager
canonicalName : Catalina:context=/host-manager,host=localhost,name=BasicAuthenticator,type=Valve
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Filter,name=Set Character Encoding
canonicalName : Catalina:context=/,host=localhost,type=NamingResources
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Filter,name=Request Dumper Filter
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=ServletToJsp
canonicalName : Catalina:name=HttpRequest1,type=RequestProcessor,worker="http-apr-8080"
canonicalName : java.lang:type=Compilation
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Filter,name=SetCharacterEncoding
canonicalName : java.lang:name=Survivor Space,type=MemoryPool
canonicalName : Catalina:port=8080,type=ProtocolHandler
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=ChatServlet
canonicalName : Catalina:context=/examples,host=localhost,type=WebappClassLoader
canonicalName : Catalina:context=/examples,host=localhost,name=foo/bar/name2,resourcetype=Context,type=Environment
canonicalName : Catalina:type=StringCache
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/docs,j2eeType=Filter,name=Tomcat WebSocket (JSR356) Filter
canonicalName : java.lang:type=Threading
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Servlet,name=Status
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/manager
canonicalName : Catalina:host=localhost,name=StandardHostValve,type=Valve
canonicalName : Users:database=UserDatabase,rolename=manager-gui,type=Role
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Servlet,name=default
canonicalName : java.lang:name=Perm Gen,type=MemoryPool
canonicalName : Catalina:port=8009,type=Mapper
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=wsEchoStream
canonicalName : Catalina:context=/docs,host=localhost,type=Loader
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Servlet,name=jsp
canonicalName : Catalina:context=/examples,host=localhost,name=FormAuthenticator,type=Valve
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=wsSnake
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Servlet,name=jsp
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Servlet,name=HostManager
canonicalName : Catalina:name="http-apr-8080",type=GlobalRequestProcessor
canonicalName : Catalina:context=/docs,host=localhost,type=NamingResources
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=jsp
canonicalName : java.lang:name=Perm Gen [shared-rw],type=MemoryPool
canonicalName : Catalina:context=/,host=localhost,type=Cache
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=wsChat
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=CompressionFilterTestServlet
canonicalName : java.lang:name=CodeCacheManager,type=MemoryManager
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Servlet,name=HTMLHostManager
canonicalName : Catalina:host=localhost,type=Host
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/docs,j2eeType=Servlet,name=jsp
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=HelloWorldExample
canonicalName : Catalina:name=HttpRequest2,type=RequestProcessor,worker="http-apr-8080"
canonicalName : Catalina:name="ajp-apr-8009",type=GlobalRequestProcessor
canonicalName : java.lang:type=Runtime
canonicalName : java.nio:name=direct,type=BufferPool
canonicalName : java.lang:name=Copy,type=GarbageCollector
canonicalName : Catalina:name=HttpRequest3,type=RequestProcessor,worker="http-apr-8080"
canonicalName : Catalina:context=/host-manager,host=localhost,type=Manager
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,name=jsp,type=JspMonitor
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/,name=jsp,type=JspMonitor
canonicalName : Catalina:host=localhost,name=AccessLogValve,type=Valve
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/examples
canonicalName : Catalina:name="ajp-apr-8009",type=ThreadPool
canonicalName : Catalina:type=Service
canonicalName : com.sun.management:type=HotSpotDiagnostic
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/,j2eeType=Servlet,name=default
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Filter,name=Tomcat WebSocket (JSR356) Filter
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/docs,j2eeType=Servlet,name=default
canonicalName : Catalina:context=/,host=localhost,type=WebappClassLoader
canonicalName : java.lang:type=OperatingSystem
canonicalName : Catalina:context=/examples,host=localhost,name=StandardContextValve,type=Valve
canonicalName : Catalina:type=Server
canonicalName : Catalina:port=8009,type=Connector
canonicalName : Catalina:name="http-apr-8080",type=ThreadPool
canonicalName : Catalina:context=/,host=localhost,name=StandardContextValve,type=Valve
canonicalName : Catalina:class=org.apache.catalina.UserDatabase,name="UserDatabase",resourcetype=Global,type=Resource
canonicalName : Catalina:context=/manager,host=localhost,type=WebappClassLoader
canonicalName : Catalina:context=/examples,host=localhost,type=Manager
canonicalName : Catalina:context=/examples,host=localhost,type=Cache
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/host-manager
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/docs
canonicalName : Users:database=UserDatabase,type=UserDatabase
canonicalName : Catalina:context=/examples,host=localhost,name=foo/name4,resourcetype=Context,type=Environment
canonicalName : Catalina:context=/docs,host=localhost,name=StandardContextValve,type=Valve
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Filter,name=Compression Filter
canonicalName : Catalina:type=NamingResources
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=SessionExample
canonicalName : Catalina:context=/,host=localhost,type=Loader
canonicalName : Catalina:name=common,type=ServerClassLoader
canonicalName : Catalina:context=/examples,host=localhost,type=Loader
canonicalName : Catalina:context=/manager,host=localhost,type=Cache
canonicalName : Catalina:context=/docs,host=localhost,type=Cache
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Filter,name=CSRF
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=CookieExample
canonicalName : Users:database=UserDatabase,type=User,username="tomcat"
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Filter,name=SetCharacterEncoding
canonicalName : Catalina:host=localhost,type=Deployer
canonicalName : Catalina:type=MBeanFactory
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=RequestInfoExample
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Filter,name=Timing filter
canonicalName : Catalina:context=/examples,host=localhost,type=NamingResources
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,j2eeType=Servlet,name=default
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/manager,j2eeType=Filter,name=CSRF
canonicalName : Catalina:context=/manager,host=localhost,type=Loader
canonicalName : Users:database=UserDatabase,type=User,username="admin"
canonicalName : Catalina:context=/docs,host=localhost,type=Manager
canonicalName : java.lang:name=Eden Space,type=MemoryPool
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=RequestHeaderExample
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/docs,name=jsp,type=JspMonitor
canonicalName : java.lang:name=Perm Gen [shared-ro],type=MemoryPool
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/host-manager,name=jsp,type=JspMonitor
canonicalName : Catalina:context=/host-manager,host=localhost,type=NamingResources
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=async2
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=async3
canonicalName : Catalina:context=/examples,host=localhost,name=minExemptions,resourcetype=Context,type=Environment
canonicalName : Catalina:context=/manager,host=localhost,type=NamingResources
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=async0
canonicalName : java.lang:type=ClassLoading
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=async1
canonicalName : Catalina:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/examples,j2eeType=Servlet,name=wsEchoMessage
canonicalName : Catalina:realmPath=/realm0,type=Realm
canonicalName : Catalina:context=/host-manager,host=localhost,type=Loader
canonicalName : Users:database=UserDatabase,rolename=tomcat,type=Role
canonicalName : Catalina:port=8080,type=Mapper
端口名:"ajp-apr-8009"
最大线程数:200
当前线程数:0
繁忙线程数:0
端口名:"http-apr-8080"
最大线程数:200
当前线程数:10
繁忙线程数:0
HTTP最大线程数:200
HTTP当前线程数:10
HTTP繁忙线程数:0
应用名:null
最大会话数:-1
会话数:0
活动会话数:0
应用名:null
最大会话数:-1
会话数:0
活动会话数:0
应用名:null
最大会话数:-1
会话数:0
活动会话数:0
应用名:null
最大会话数:-1
会话数:0
活动会话数:0
应用名:null
最大会话数:-1
会话数:0
活动会话数:0
活动sockets计数:0
最大处理时间:176
总处理时间:0
请求总数:9
错误总数:0
接收字节数:0.00
发送字节数:0.07

Tomcat指定native library路径

一般,指定JVM的native library路径,只需要用下面的参数就好了

-Djava.library.path=PATH_TO_NATIVE_LIBRARY

Tomcat指定native library路径时,还是不要使用这边参数的好。
建议直接修改PATH环境变量,将dll或so放到环境变量PATH的路径下就好了。
TOMCAT默认将PATH赋值给-Djava.library.path参数的。

Redis与Tomcat集群集成

在网站访问量急剧上升时,通常需要使用集群的方法进行横向扩展。
对于没有状态的应用来说,直接用nginx进行处理即可。
但对于有状态的应用来说,比如登录状态等,除了使用nginx进行扩展外,就需要考虑到Session共享的问题了。

大家知道可以用apache+tomcat来实现Session共享,但效率太低了,而且容易出错。
今天说的主要是用nginx+tomcat+redis+tomcat-redis-session-manager的方式实现共享。
原理比较简单:

1、tomcat-redis-session-manage扩展了
org.apache.catalina.valves.ValveBase;
org.apache.catalina.session.ManagerBase;
org.apache.catalina.session.StandardSession;
并通过Tomcat配置,替代了这几个类。

2、Set属性时,用session id作为key,将Tomcat的整个Session拆分为SessionSerializationMetadata+RedisSession然后序列化为byte[],存放到Redis。

3、Get属性时,用session id作为key,从Redis获取byte[],然后反序列化为SessionSerializationMetadata+RedisSession,供Tomcat使用。

配置也很简单:
1、从github下载源码tomcat-redis-session-manager

2、用gradle进行编译

#master分支下面,要把signing段和uploadArchives段删掉,才能正常编译
#release就不需要了
gradle build

3、将三个Jar包拷贝到Tomcat的lib文件夹下

#%TOMCAT_HOME%/lib
tomcat-redis-session-manager-master-2.0.0.jar
commons-pool2-2.2.jar
jedis-2.5.2.jar

4、修改context.xml配置文件,新增下面内容就搞定咯

<!--%TOMCAT_HOME%/conf/context.xml-->
  <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
  <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" 
  host="localhost" port="6379" database="0" maxInactiveInterval="60"/>

好处是:不需要修改应用
坏处是:要耗费一定的时间来(序列化+保存到Redis)、(反序列化+从Redis读取)。

Build Tomcat Lesson101

1. Download one source tag from Apache
For example, I used this tag:

http://svn.apache.org/repos/asf/tomcat/tc6.0.x/tags/TOMCAT_6_0_41

2. Read this:

http://tomcat.apache.org/tomcat-6.0-doc/building.html

3. Prepare JDK and Ant

SET JAVA_HOME=C:\Languages\Java\JDK\jdk_x86_1.6.0_34
SET ANT_HOME=C:\Languages\Java\JavaTools\apache-ant-1.9.0
SET PATH=%ANT_HOME%\bin;%JAVA_HOME%\bin;%PATH%
CMD

4. Copy build.properties.default to build.properties

5. Edit build.properties and set base.path

base.path=the path to store thirdpart libs

6. Run “Ant download”

7. Run “Ant”

8. Rename files

move eclipse.classpath .classpath
move eclipse.project .project

9. Use eclipse to import this project

10. Set break point and debug

Tomcat强制使用HTTPS

配置好Tomcat的SSL后,强制使用HTTPS方法如下:

1、全局强制HTTPS
修改%tomcat_home%\conf\web.xml,在文件底部,后面加上这样一段:

    <login-config>  
        <!-- Authorization setting for SSL -->  
        <auth-method>CLIENT-CERT</auth-method>  
        <realm-name>Client Cert Users-only Area</realm-name>  
    </login-config>  
    <security-constraint>  
        <!-- Authorization setting for SSL -->  
        <web-resource-collection >  
            <web-resource-name >SSL</web-resource-name>  
            <url-pattern>/*</url-pattern>  
        </web-resource-collection>  
        <user-data-constraint>  
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
        </user-data-constraint>  
    </security-constraint>  

2、某个webapp强制使用HTTPS
编辑该webapp的web.xml文件,增加以下内容:

	<security-constraint>
	    <web-resource-collection>
	        <web-resource-name>securedapp</web-resource-name>
	        <url-pattern>/*</url-pattern>
	    </web-resource-collection>
	    <user-data-constraint>
	        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
	    </user-data-constraint>
	</security-constraint>

关闭 SSL,只需要将CONFIDENTIAL改为NONE即可。

Java Https Soap Server(Tomcat-Axis2)

1、%Tomcat%/server/server.xml
找到下面一段:

<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
-->

替换为:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"  
	    maxThreads="150" scheme="https"  secure="true"
	    clientAuth="false" sslProtocol="TLS"
	    disableUploadTimeout="true" enableLookups="false"
	    keystoreFile="D:/JavaContainer/apache-tomcat-6.0.35-x86/myKeyStore.jks"
	    keystorePass="sslTestPwd"
/>

这样,就可以用https://127.0.0.1:8443访问Tomcat了。

2、在需要使用https项目的axis2.xml文件中,增加下面内容

        <!--修改-->
	<transportReceiver name="http"
		class="org.apache.axis2.transport.http.AxisServletListener">
		<parameter name="port">8080</parameter>
	</transportReceiver>
        <!--新增-->
	<transportReceiver name="https"
		class="org.apache.axis2.transport.http.AxisServletListener">
		<parameter name="port">8443</parameter>
	</transportReceiver>

这样,该WebService就可以使用https进行访问了:)

Tomcat如何编译JSP

以Tomcat为例,说明一下容器如何编译JSP

1.1 命令行方式

java -classpath %CLASS_PATH% org.apache.jasper.JspC -uriroot PATH_TO_WEB\website\ -d PATH_TO_WEB\website\WEB-INF\jspclasses -p com.neohope.pages -c hello -javaEncoding UTF-8 -compile PATH_TO_WEB\website\jsp\hello.jsp

上面的命令行是,将website项目中jsp\hello.jsp文件,生成对应的java文件,文件输出路径为WEB-INF\jspclasses,类包名为com.neohope.pages,类名hello,编码为UTF-8

1.2 Java代码方式

package com.neohope.jsp.complier;

import org.apache.jasper.JspC;

public class MyComplier {
	public static void main(String args[]) {
		try {
			JspC jspc = new JspC();
			jspc.setUriroot("PATH_TO_WEB\\JSP\\JSPComplier\\website");
			jspc.setJspFiles("PATH_TO_WEB\\JSP\\JSPComplier\\website\\jsp\\hello.jsp");
			jspc.setOutputDir("PATH_TO_WEB\\JSP\\JSPComplier\\website\\WEB-INF\\jspclasses");
			jspc.setPackage("com.neohope.pages");
			jspc.setClassName("hello");
			jspc.setJavaEncoding("UTF-8");
			jspc.setCompile(true);
			jspc.execute();
			
			System.out.println("job done!");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

代码地址:
JSPComplierSample

Tomcat7安装为Windows Service

Tomcat7采用服务模式运行,主要靠两个EXE和一个BAT文件:
Tomcat7w.exe用于配置、监控服务
Tomcat7.exe用于服务的安装、卸载、更新、运行、停止等
service.bat提供了一些预设的脚本方便大家安装卸载服务

1、Tomcat7w.exe //XX//ServiceName

#服务配置界面
Tomcat7w //ES//ServiceName
#服务监控
Tomcat7w //MS//ServiceName

2、Tomcat7.exe //XX//ServiceName

#命令行运行服务
Tomcat7 //TS//ServiceName
#启动服务
Tomcat7 //RS//ServiceName
#关闭服务
Tomcat7 //SS//ServiceName
#更新服务参数
Tomcat7 //US//ServiceName
#安装服务
Tomcat7 //IS//ServiceName
#删除服务
Tomcat7 //DS//ServiceName

其他可用参数有:

ParameterName Default Description
–Description Service name description (maximum 1024 characters)
–DisplayName ServiceName Service display name
–Install procrun.exe //RS//ServiceName Install image
–Startup manual Service startup mode can be either auto or manual
++DependsOn List of services that this service depend on. Dependent services
are separated using either # or ; characters
++Environment List of environment variables that will be provided to the service
in the form key=value. They are separated using either
# or ; characters. If you need to use either the #
or ; character within a value then the entire value must be
enclosed inside single quotes.
–User User account used for running executable. It is used only for
StartMode java or exe and enables running applications
as service under account without LogonAsService privilege.
–Password Password for user account set by –User parameter
–JavaHome JAVA_HOME Set a different JAVA_HOME than defined by JAVA_HOME environment
variable
–Jvm auto Use either auto (i.e. find the JVM from the Windows registry)
or specify the full path to the jvm.dll.
You can use the environment variable expansion here.
++JvmOptions -Xrs List of options in the form of -D or -X that will be
passed to the JVM. The options are separated using either
# or ; characters. (Not used in exe mode.)
–Classpath Set the Java classpath. (Not used in exe mode.)
–JvmMs Initial memory pool size in MB. (Not used in exe mode.)
–JvmMx Maximum memory pool size in MB. (Not used in exe mode.)
–JvmSs Thread stack size in KB. (Not used in exe mode.)
–StartMode One of jvm, Java or exe. The modes are:

  • jvm – start Java in-process. Depends on jvm.dll, see –Jvm.
  • Java – same as exe, but automatically uses the default Java
    executable, i.e. %JAVA_HOME%\bin\java.exe. Make sure JAVA_HOME is set
    correctly, or use –JavaHome to provide the correct location.
    If neither is set, procrun will try to find the default JDK (not JRE)
    from the Windows registry.
  • exe – run the image as a separate process
–StartImage Executable that will be run. Only applies to exe mode.
–StartPath Working path for the start image executable.
–StartClass Main Class that contains the startup method. Applies to the jvm and
Java modes. (Not used in exe mode.)
–StartMethod main Method name if differs then main
++StartParams List of parameters that will be passed to either StartImage or
StartClass. Parameters are separated using either # or
; character.
–StopMode One of jvm, Java or exe. See –StartMode
for further details.
–StopImage Executable that will be run on Stop service signal. Only applies to
exe mode.
–StopPath Working path for the stop image executable. Does not apply to jvm
mode.
–StopClass Main Class that will be used on Stop service signal. Applies to the
jvm and Java modes.
–StopMethod main Method name if differs then main
++StopParams List of parameters that will be passed to either StopImage or
StopClass. Parameters are separated using either # or
; character.
–StopTimeout No Timeout Defines the timeout in seconds that procrun waits for service to
exit gracefully.
–LogPath %SystemRoot%\System32\LogFiles\Apache Defines the path for logging. Creates the directory if necessary.
–LogPrefix commons-daemon Defines the service log filename prefix. The log file is created in the
LogPath directory with .YEAR-MONTH-DAY.log suffix
–LogLevel Info Defines the logging level and can be either Error,
Info, Warn or Debug. (Case insensitive).
–StdOutput Redirected stdout filename.
If named auto then file is created inside LogPath with the
name service-stdout.YEAR-MONTH-DAY.log.
–StdError Redirected stderr filename.
If named auto then file is created inside LogPath with the
name service-stderr.YEAR-MONTH-DAY.log.
–PidFile Defines the file name for storing the running process id. Actual file is
created in the LogPath directory

3、service.bat安装卸载服务

service.bat install/uninstall/remove ServiceName

4、启动关闭服务

net start ServiceName
net stop ServiceName

MuleESB3发布到Tomcat

今天把Mule ESB集成到Tomcat时,出现了下面的错误:

Already in lifecycle phase 'start', cannot fire the same phase twice

解决方法:
把MuleESB官方网站建议的:

<listener-class>org.mule.config.builders.MuleXmlBuilderContextListener</listener-class>

替换为:

<listener-class>org.mule.config.builders.DeployableMuleXmlContextListener</listener-class>

就可以了

Tomcat配置TLS

%TOMCAT_HOME%/conf/server.xml中添加以下配置即可

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
	       clientAuth="false" sslProtocol="TLS"
               keystoreFile="TOMCAT_HOME\conf\AXDS_2012_Keystore.jks"
               keystorePass="password"
	       truststoreFile="TOMCAT_HOME\conf\AXDS_2012_Truststore.jks" 
	       truststorePass="password"            
	       />