8

我需要实现一个基于 Web 的应用程序,该应用程序一旦部署在 tomcat 上,就可以监视部署在同一个 tomcat 上的所有应用程序的活动会话。

假设 tomcat 有 2 个应用程序作为 1) ReportGenerator 2) DataSyncManager 运行。我需要使用以下统计信息显示这 2 个应用程序的活动会话。

Seesion #   Application    Session Start Time

1234    ReportGenerator     XXXX
56748   DataSyncManager     XXXX
55565   DataSyncManager     XXXX

我还需要即时终止会话。可能吗?请指教。

我知道这是类似于 tomcat/ 的管理控制台。但我需要将其实现为具有自定义日志记录和监视功能的自定义应用程序。请告诉我我可以使用哪个框架/api来捕获tomcat上的活动会话及其统计信息。

4

4 回答 4

10

我已经通过使用标准 API 和规范的通用方法实现了此功能,没有第三方框架或库。该解决方案已广泛用于部署在 glassfish 应用程序服务器和 jboss 中的许多企业级系统。它也已成功地与 weblogic (12c) 一起使用。但是,该方法应该适用于任何支持标准 JMX 规范的应用程序服务器或 servlet 容器。

tldr ; 这个版本是创建两个 JMX bean 接口和一个 http 会话侦听器。其中一个 JMX bean 接口为每个受监视的应用程序创建一个实例,并负责跟踪来自每个受监视应用程序的所有会话,它基本上提供每个应用程序的所有会话的统计信息。另一个 JMX bean 接口为每个受监视应用程序中创建的每个会话创建一个实例。http 会话监听器监视每个应用程序的会话并做两件事。通知与此应用程序对应的第一个 JMX bean 有关创建/销毁的会话的信息,以便更新统计信息。从 JMX 服务注册或取消注册与会话对应的 JMX 实例。

一切设置好后,就可以从 jdk 附带的 jconsole 和 visualvm 等 JMX 客户端使用它。从 jmx 客户端可以查看 JMX bean 的所有属性并调用它们的任何方法。

以下屏幕截图来自使用 jconsole 的测试应用程序。

在此处输入图像描述

这些是来自 JMX bean 实例的属性,对应于每个受监视的应用程序。

在此处输入图像描述

这些是可以在选定的特定会话上执行的操作。

如果监控多个应用程序,则每个 jmx bean 接口下将出现更多具有自己结构的应用程序上下文,即 /TestApplication 、 /Application2 等。

如何

最初需要创建两个 JMX bean 接口(简单教程),然后是一个 HttpSessionListener(网上有很多教程)。

1.第一个 JMX bean 接口对于每个受监控的应用程序只有一个实例,并将存储与从任何受监控的应用程序创建的会话相关的所有信息。它基本上用于持久性。我只将数据保存在内存中,这意味着如果服务器宕机,数据将会丢失,但通常只要服务器启动,只需检查统计信息。如果您想将数据保存到日志或数据库中以便始终拥有这些信息,您当然可以在接口的实现中做到这一点。

所以这可能如下,

public interface SessionsMXBean {

    /**
     * Get Indicates whether the data should be persisted in memory.
     */
    public boolean getPersistData();

    /**
     * Set Indicates whether the data should be persisted in memory.
     */
    public void setPersistData(boolean value);

    /**
     * Get All active sessions that have been persisted.
     */
    public String getActiveSessions();

    /**
     * Get All dates of each active session that has been persisted.
     */
    public String getDatesOfSessions();

    /**
     * Get The threshold for the number of session, after which persistence will
     * take place. If -1 all are persisted.
     */
    public int getSessionsThreshold();

    /**
     * Set The threshold for the number of session, after which persistence will
     * take place. If -1 all are persisted.
     */
    public void setSessionsThreshold(int value);

    /**
     * Set The limit of size to be persisted in KB. If -1 then no size limit.
     */
    public void setPersistenceSize(long value);

    /**
     * Clears all persisted data.
     */
    public void clearData();

    /**
     * Unregisters this instance
     */
    public void unregisterThis();
}

然后你必须创建这个接口的实现,最终将保存这种数据。

    public class SessionsImpl implements SessionsMXBean {
    /*
    here you need to implement the interface and have all kind of objects you require
    */
      public synchronized void incrementSessions() {
        ....
      }

      public synchronized void decrementSessions() {
        .....
      }

2.第二个 JMX bean 接口将为每个受监控应用程序中创建的每个会话创建一个实例。此接口将存储会话对象,并且还将具有可以从 jmx 客户端调用的方法,以使这些会话无效。这可以如下,

public interface HttpSessionMXBean {

    /**
     * Get HTTP Session id
     */
    public String getSessionId();

    /**
     * Get the date created
     */
    public String getDateCreated();

    /**
     * Get the date created in milliseconds
     */
    public long getMillisCreated();

    /**
     * Get attributes from http session
     *
     * @param attrName Attribute Name
     * @return java.lang.String
     */
    public String getAttribute(String attrName);

    /**
     * Invalidate this session
     */
    public void invalidate();

    /**
     * Unregisters this instance
     */
    public void unregisterThis();
}

再次需要一个实现,

public class HttpSessionMXBeanImpl implements HttpSessionMXBean {
....

3.然后创建 HttpSessionListener,它将创建/删除第二个 bean 接口的实例,并从服务器的 JMX 服务中注册/注销它们。这将在会话创建和失效/过期时发生。因此,每个应用程序都有一个侦听器,并在其 web.xml 中定义了它。

HttpSessionListener

        ....
        public class MyJMXHTTPSessionListener implements HttpSessionListener {
        ....
          private SessionsImpl sesssionsImpl;
          private Map<String, HttpSessionMXBeanImpl> httpSessionMXBeans

          @Override
          public void sessionCreated(HttpSessionEvent se) {
            //requires synchronized block here with this i.e.
            synchronized (this) {
            /*check if a jmx bean instance of the 1st interface exists otherwise create one*/
    if(sessionsImpl==null){
    sesssionsImpl= new SesssionsImpl();
/* take care here to create a nice and unique path per instance 
of the application in order to be nicely presented on the JMX tree of the JMX clients  */
                        String id = ("services.jmx.beans:type=Sessions,"+ "realm=" + se.getSession().getServletContext().getContextPath());
                        sessionManagerMXBean.setId(id);
                        ObjectName objectName = new ObjectName(id);
                        if (ManagementFactory.getPlatformMBeanServer().isRegistered(objectName)) {
                            ManagementFactory.getPlatformMBeanServer().
                                    unregisterMBean(objectName);
                        }
                        ManagementFactory.getPlatformMBeanServer().
                                registerMBean(sesssionsImpl,
                                objectName);
    }

    sesssionsImpl.inrementSessions();

    /*

               create a jmx bean instance of the 2nd interface

 and register it to the jmx service as already shown using the unique session id

 and a nice path indicating the 2nd interface jmx beans.
    */

          }

          @Override
          public void sessionDestroyed(HttpSessionEvent se) {
            //requires synchronized block here with this i.e.
            synchronized (this) {
            /*unregister the jmx bean instance of the 2nd interface, 

remove it from the list 

and call decrementSessions() on the jmx bean instance corresponding to this app*/
            }
          }
        }

如果您通过添加以下几行在 web.xml 文件中定义 HttpSessionListener,则可以随时为任何 Web 应用程序轻松激活此功能,

web.xml

<listener>
  <listener-class>
    myservices.myhttpsessionlisteners.MyJMXHTTPSessionListener
  </listener-class>
</listener>
于 2013-11-09T11:58:21.027 回答
3

你检查过psi-probe项目吗?

它是 Apache Tomcat 的高级管理器和监视器,源自 Lambda Probe。

于 2013-11-14T13:50:11.353 回答
2

@melc 的答案提供了一个很好的通用解决方案。如果它只在 Tomcat 上运行,您还可以使用更简单的版本:

在您的一个 servlet 中实现该org.apache.catalina.ContainerServlet接口(您可以在 <Tomcat 安装路径>\lib\catalina.jar 中找到它)。

import org.apache.catalina.Context;
import org.apache.catalina.Session;
import org.apache.catalina.Wrapper;

public void setWrapper(Wrapper w) {
    this.wrapper = w;
    context = (Context) wrapper.getParent();
    // This'll give you all sessions:
    org.apache.catalina.Session[] sessions = context.getManager().findSessions();
    for (int i = 0; i < sessions.length; i++) {
        System.out.println(sessions[i]);
    }
    host = (Host) context.getParent();
    // contexts are the list of applications deployed on Tomcat
    Context[] contexts = (Context[]) host.findChildren();
    for (Context context:contexts) {
        //Or to access session list by application, 
        //call findSessions() on the target context
        org.apache.catalina.Session[] sessions = context.getManager().findSessions();
    }
}

顺便说一句,您需要在 context.xml 中将 Context 定义为特权:

<Context privileged="true">
于 2013-11-09T15:43:45.780 回答
0

Tomcat插件

Lambda Probe版本(以前称为 Tomcat Probe)——实时监控和管理 Apache Tomcat 实例的终极工具。Lambda Probe 将帮助您通过易于使用和友好的 Web 界面可视化有关 Apache Tomcat 实例的实时信息。

PSI Probe是 Apache Tomcat 的高级管理器和监视器,从 Lambda Probe 分支到 GitHub。

安装 ApacheTomcat : 下载War文件并放置在 webapp 文件夹中,通过将 manager-gui 角色添加到任何用户来更改配置文件

<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>
于 2019-06-06T06:32:15.297 回答