有時候咱們想獲取當前運行的Tomcat的各類參數,好比maxThreads、acceptThreadCount等。例以下面兩張圖:java
一、Http11Protocolapache
Http11Protocol.pngjson
一、Http11NioProtocolapi
Http11NioProtocol.pngtomcat
三、實現代碼框架
import com.google.common.collect.Maps; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import java.util.List; import java.util.Map; /** * Created by wangxindong on 2017/10/31. */ public class TomcatContainerMonitor { private static final Logger logger = LoggerFactory.getLogger(TomcatContainerMonitor.class); private static final String tomcatEmbedDomain = "Tomcat"; private static final String tomcatDomain = "Catalina"; private static final String bioProtocol="org.apache.coyote.http11.Http11Protocol"; private static final String nioProtocol="org.apache.coyote.http11.Http11NioProtocol"; public Object doMonitor() { Map<String, Object> map = Maps.newHashMap(); List<MBeanServer> mBeanServers = MBeanServerFactory.findMBeanServer(null); if (!mBeanServers.isEmpty()) { MBeanServer mBeanServer = mBeanServers.get(0); String domain = getTomcatDomian(mBeanServer); try { ObjectName[] objNames = (ObjectName[]) mBeanServer.getAttribute(new ObjectName(domain, "type", "Service"), "connectorNames"); for (ObjectName on : objNames) { Map<String, Object> connector = Maps.newHashMap(); Object protocol = mBeanServer.getAttribute(on, "protocol"); connector.put("protocol", protocol); Object acceptCount = mBeanServer.getAttribute(on, "acceptCount"); connector.put("acceptCount", acceptCount); Object connectionTimeout = mBeanServer.getAttribute(on, "connectionTimeout"); connector.put("connectionTimeout", connectionTimeout); Object protocolHandlerClassName = mBeanServer.getAttribute(on, "protocolHandlerClassName"); connector.put("protocolHandlerClassName", protocolHandlerClassName); Object enableLookups = mBeanServer.getAttribute(on, "enableLookups"); connector.put("enableLookups", enableLookups); Object uriEncoding = mBeanServer.getAttribute(on, "URIEncoding"); connector.put("URIEncoding", uriEncoding); Object useBodyEncodingForURI = mBeanServer.getAttribute(on, "useBodyEncodingForURI"); connector.put("useBodyEncodingForURI", useBodyEncodingForURI); Object localPort = mBeanServer.getAttribute(on, "port"); map.put("connector-" + localPort, connector); if (protocolHandlerClassName.toString().equals(nioProtocol)) {//NIO String threadPoolONStr = domain + ":type=ThreadPool,name=\"http-nio-" + localPort + "\""; ObjectName threadPoolON = new ObjectName(threadPoolONStr); Map<String, Object> threadPoolMap = Maps.newHashMap(); Object maxConnections = mBeanServer.getAttribute(threadPoolON, "maxConnections"); threadPoolMap.put("maxConnections", maxConnections); Object maxThreads = mBeanServer.getAttribute(threadPoolON, "maxThreads"); threadPoolMap.put("maxThreads", maxThreads); Object minSpareThreads = mBeanServer.getAttribute(threadPoolON, "minSpareThreads"); threadPoolMap.put("minSpareThreads", minSpareThreads); Object acceptorThreadCount = mBeanServer.getAttribute(threadPoolON, "acceptorThreadCount"); threadPoolMap.put("acceptorThreadCount", acceptorThreadCount); Object pollerThreadCount = mBeanServer.getAttribute(threadPoolON, "pollerThreadCount"); threadPoolMap.put("pollerThreadCount", pollerThreadCount); Object pollerThreadPriority = mBeanServer.getAttribute(threadPoolON, "pollerThreadPriority"); threadPoolMap.put("pollerThreadPriority", pollerThreadPriority); connector.put("threadPool", threadPoolMap); }else if(protocolHandlerClassName.toString().equals(bioProtocol)){ String threadPoolONStr = domain + ":type=ThreadPool,name=\"http-bio-" + localPort + "\""; ObjectName threadPoolON = new ObjectName(threadPoolONStr); Map<String, Object> threadPoolMap = Maps.newHashMap(); Object maxConnections = mBeanServer.getAttribute(threadPoolON, "maxConnections"); threadPoolMap.put("maxConnections", maxConnections); Object maxThreads = mBeanServer.getAttribute(threadPoolON, "maxThreads"); threadPoolMap.put("maxThreads", maxThreads); Object minSpareThreads = mBeanServer.getAttribute(threadPoolON, "minSpareThreads"); threadPoolMap.put("minSpareThreads", minSpareThreads); Object acceptorThreadCount = mBeanServer.getAttribute(threadPoolON, "acceptorThreadCount"); threadPoolMap.put("acceptorThreadCount", acceptorThreadCount); connector.put("threadPool", threadPoolMap); } } } catch (Exception e) { logger.warn("獲取信息失敗", e); } } return map; } private String getTomcatDomian(MBeanServer mBeanServer) { try { mBeanServer.getAttribute(new ObjectName(tomcatEmbedDomain, "type", "Service"), "connectorNames"); return tomcatEmbedDomain; } catch (Exception e) { return tomcatDomain; } } @Test public void test(){ TomcatContainerMonitor wcm = new TomcatContainerMonitor(); wcm.doMonitor(); } }
獲取MAP對象經過json序列化輸出到頁面,如上面兩張圖。dom
四、須要依賴ide
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.39</version> <!--<scope>provided</scope>--> </dependency> <dependency> <groupId>com.google.collections</groupId> <artifactId>google-collections</artifactId> <version>1.0</version> <!--<scope>provided</scope>--> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> <!--<scope>provided</scope>--> </dependency>
五、原理總結工具
public abstract class LifecycleMBeanBase extends LifecycleBase implements MBeanRegistration {}
Tomcat對server.xml文件解析,解析出來的組件和容器都繼承了LifecycleMBeanBase類,其父類LifecycleBase實現了容器的生命週期管理,其接口MBeanRegistration由Java JMX(Java Management Extensions)框架提供,用於監聽JMX註冊事件;LifecycleMBeanBase的子類都遵循JMX標準,經過getObjectNameKeyProperties()抽象方法定義類的註冊名稱,並在每一個對象初始化(執行生命週期init方法)時註冊到MBeanServer中,MBeanServer給出了外部管理系統訪問JMX框架的接口,所以外部系統或工具能夠實時監控到MBean的各類數據信息。這就是咱們可以經過MBeanServer獲取到Tomcat各類配置信息的原理。google
參考資料:
http://www.fanyilun.me/2016/10/10/Tomcat%E7%9A%84%E5%90%AF%E5%8A%A8%E5%88%86%E6%9E%90/