侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 352 篇文章
  • 累计创建 135 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

JavaMelody应用监控使用指南

孔子说JAVA
2022-10-29 / 0 评论 / 0 点赞 / 87 阅读 / 17,117 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-10-29,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
广告 广告

JavaMelody的目标是监控QA和生产环境中的Java或Java EE应用程序。它不是模拟用户请求的工具,而是一个衡量并且计算在应用上的操作信息的工具,用于根据用户对应用程序的使用情况来测量和计算应用程序实际操作的统计信息。

1、介绍

1.1 监控工具的作用

在项目中,我们经常需要关注生产环境的服务器运行状况,以及服务器的负载,以往我们经常去会使用一些命令去观察服务器的状态,然后去观测系统的log作对应的分析,这种方法虽然能够达到预期的目的,但是我们获得一些信息并不是很直观,所以有的时候并不能及时发现服务器的异常状态,最后导致服务中断。

1.2 JavaMelody是什么

JavaMelody 能够监测Java或Java EE应用程序服务器,它并不是一个模拟请求类似JMeter的压力测试工具,而是一个衡量并且计算在应用上的操作信息的工具,也就是说,它只负责对行为进行监控,而不负责触发操作。它会以图表的方式显示一下监控内容:

  1. Java内存和CPU使用情况
  2. 用户Session数量
  3. JDBC连接数
  4. http请求
  5. sql请求
  6. jsp页面与业务接口方法(EJB3、Spring、 Guice)的执行数量
  7. 平均执行时间
  8. 错误百分比
  9. 垃圾回收等

图表可以按天,周,月,年或自定义时间段查看。JavaMelody基于请求统计生成模拟图表,并为我们的应用程序在QA或者开发上提供下面的帮助:

  1. 给出平均的响应时间以及执行数
  2. 在某些操作趋势变得严重前给出提示
  3. 优化响应
  4. 找出响应瓶颈的根本
  5. 证实优化策略的效果

1.3 JavaMelody使用条件

  • JDK版本要求:需要Java JDK在1.6或者1.6以上。
  • 浏览器:最好是Firefox、 Chrome、IE9以上

JavaMelody支持在以下应用服务器的部署以及监控:

  • servlet API在2.4以上
  • Tomcat 5.5 6 或者7
  • GlassFish v2或v3
  • JBoss 4,5,6,7
  • Jonas 4或5
  • Jetty 6或7
  • WebLogic 9,10,11

如果想要监控其他的服务器需要安装一些插件,详情请阅读 UserGuide

1.4 相关链接

github官网文档地址:https://github.com/javamelody/javamelody/wiki/UserGuide
github下载地址:https://github.com/javamelody/javamelody/releases

2、项目集成JavaMelody

JavaMelody监控是非常简单的,部署也很快。通常JavaMelody与应用的整个都是软件自动完成的,并不需要用户做任何的操作。只需要修改一点配置文件即可。监控与应用整合一般都不会超过10秒钟,通常都会自动的被编译环境发现:你需要做的知识拷贝两个jar包,添加10行xml的代码。对于springboot则更简单,只需要引入pom依赖即可。

2.1 jar包方式

普通的web项目(非maven项目)使用此方式,复制文件 javamelody.jarjrobin-x.jar, 到你的项目的 WEB-INF/lib 目录下。

image-1666834096054

2.2 pom方式

2.2.1 通用maven配置

如果您使用Maven,请在pom中添加javamemel核心依赖项(原生依赖包)。web项目(包括springboot方式)都可以使用此种方式

<dependency>
    <groupId>net.bull.javamelody</groupId>
    <artifactId>javamelody-core</artifactId>
    <version>1.76.0</version>
</dependency>

使用原生依赖包的话,则需要添加过滤拦截器。

1)通用web项目添加方式

在web.xml添加过滤器如下:

<filter>
    <filter-name>javamelody</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>javamelody</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ASYNC</dispatcher>
</filter-mapping>
<listener>
    <listener-class>net.bull.javamelody.SessionListener</listener-class>
</listener>

<async-supported>true</async-supported><dispatcher>ASYNC</dispatcher> 用于在servlet3.0中处理异步请求,一般我们用的是servlet2.3 或者 2.4 ,不使用这两个参数即可。

2)springboot项目添加方式

@Configuration
public class JavaMelodyConfig {

    /**
     * 配置javamelody监控
     * spring boot 会按照order值的大小,从小到大的顺序来依次过滤
     */
    @Bean
    @Order(Integer.MAX_VALUE-1)
    public FilterRegistrationBean<MonitoringFilter> monitoringFilter() {
        FilterRegistrationBean<MonitoringFilter>  registration = new FilterRegistrationBean<MonitoringFilter>();
        registration.setFilter(new MonitoringFilter());
        registration.addUrlPatterns("/*");
        registration.setName("monitoring");
        return registration;
    }

    /**
     *  配置javamelody监听器sessionListener
     */
    @Bean
    public ServletListenerRegistrationBean<SessionListener> servletListenerRegistrationBean() {
        ServletListenerRegistrationBean<SessionListener> slrBean = new ServletListenerRegistrationBean<SessionListener>();
        slrBean.setListener(new SessionListener());
        return slrBean;
    }
}

如果访问需要有token验证,可以排除对 /monitoring的访问限制

http.authorizeRequests()
                .antMatchers("/", "/*.html", "/favicon.ico", "/css/**", "/js/**", "/fonts/**", "/layui/**", "/img/**",
                        "/monitoring","/statics/**")
                .permitAll().anyRequest().authenticated();

2.2.2 springboot maven配置

如果你使用的是springboot,还可以用springboot特有的依赖项:

<dependency>
    <groupId>net.bull.javamelody</groupId>
    <artifactId>javamelody-spring-boot-starter</artifactId>
    <version>1.76.0</version>
</dependency>

在springboot的application.properties文件中可以配置相关的属性(以下配置也可以不添加,默认都为开启状态):

#启动javamelody
javamelody.enabled=true
#启动监控
javamelody.spring-monitoring-enabled=true
#显示日志
javamelody.init-parameters.log=true

注:这里只是列举了启动服务的基础配置,更多的配置属性可以到官网文档上查看。

yml配置详解

javamelody:
  #是否启用javaMelody
  enabled: true
  #排除不需要监控的数据源
#  excluded-datasources:
  #表示是否启用 spring的service与controller的监控,默认是true
  spring-moitoring-enabled: true
#  javaMelody的初始配置项
  init-parameters:
#    是否记录http请求
    log: true
    #哪些http请求不需要记录
    #url-exclude-pattern: (/webjars/.*|/css/.*|/images/.*|/fonts/.*|/js/.*)
    #转换http的请求路径 删除动态部分 如 /xiaohu/1 /xiaohu/2 他都只记录/xiaohu这个路径
#    http-transform-pattern: \d+
    #登录账号跟密码
    authorized-users: admin:pwd
    #javaMelody的存储目录 ${spring.application.name} 服务名,因为一般一个配置可能要配置多个服务,所以每个服务的javamelody配置都不样,防止文件膨胀
    storage-directory: d:/tmp/javamelody/${spring.application.name} 
    #启动后javaMelody的访问路径 /默认访问 /monitoring
    #monitoring-path: /admin/performance

image-1666833680300

2.2.3 其他功能pom配置

<!-- itext, 用于支持 PDF 导出 -->
<dependency>
    <groupId>com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>2.1.7</version>
    <exclusions>
        <exclusion>
            <artifactId>bcmail-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
        <exclusion>
            <artifactId>bcprov-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
        <exclusion>
            <artifactId>bctsp-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
    </exclusions>
</dependency>
<!-- 用于支持xml,json导出 -->
<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.2</version>
</dependency>
<!-- 监控核心类,包含在JavaMelody 核心jar包,不用单独添加 -->
<dependency>
    <groupId>org.jrobin</groupId>
    <artifactId>jrobin</artifactId>
    <version>1.5.9</version>
</dependency>

2.2.4 访问路径及设置密码

javamelody的默认访问路径是monitoring且没有密码,我们可以重新定义访问路径及设置密码。

<filter>
    <filter-name>javamelody</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <init-param>
        <param-name>monitoring-path</param-name>
        <param-value>/moni</param-value>
    </init-param>
    <init-param>
        <param-name>authorized-users</param-name>
        <param-value>user1:password1,user2:password2,user3:password3...</param-value>
    </init-param>
    <!--<async-supported>true</async-supported>-->
</filter>

javamelody有很多参数都可以让使用者去设置的。在JavaMelody中有一个枚举类 public enum net.bull.javamelody.Parameter,它里面的所有属性都可以设置为参数。

3、访问监控

启动应用服务器后就可以打开网址查看监控效果了。网址:http://<host>/<context>/monitoring

  • <host> 是web应用服务器的部署IP,通常是localhost:8080 或者 127.0.0.1:8080, 具体看你自己的应用服务器
  • <context>是你的web应用的名字。

例如:http://localhost:8080/test-project/monitoring

image-1666832705331

image-1666833826783

注意:

  • 如果在启动过程中出错,出错信息含有window server,那么检查一下你是否使用了其他版本的server。并且添加系统参数-Djava.awt.headless=true

  • 如果使用到额是tomcat,那么在conf/catalina.properties中添加java.awt.headless=true

然后重启服务器。

4、JavaMelody缓存文件

JavaMelody的缓存文件存放在tomcat下的temp中了,目录是tomcat/temp/javamelody/应用名字_主机名字,你可以多次启动JavaMelody,可以发现之前的监测数据都还在,就是存放在这个目录中。

image-1666833419242

如果删除这两个文件,再次启动tomcat后,你就会发现数据被清空了,所有的监测结果都归零了。

所有的记录的监控信息都在这个文件夹中,进入这个目录可以发现,都是RRD的文件,无法直接读取,但是从名字就可以看到它都记录什么数据。比如sql线程数,内存等等。

image-1666833468385

5、JavaMelody监控SQL配置

监控页面打开时看不到监控数据,SQL一栏无论如何都是0,要不就是NaN。这个问题其实还是因为数据源的部分没有配置正确,这里介绍两种配置的方式。

5.1 添加额外的jdbc驱动

直接配置数据源,添加额外的jdbc驱动。按照UserGuide的文档来说,可以使用Jndi配置数据源的方式,比如如果使用Hibernate,那么在hinernate.cfg.xml中配置如下:

# 这行是关键
<property name="hibernate.connection.driver_class">net.bull.javamelody.JdbcDriver</property>
<property name="hibernate.connection.driver">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/myschema</property>
<property name="hibernate.connection.username">myuser</property>
<property name="hibernate.connection.password">mypassword</property>  

只要保证原有的connection.driver是真实的驱动,上面添加一个参数connection.driver_class是javamelody的那个jdbc驱动即可。

下面是oracle的驱动配置:

<?xml version="1.0" encoding="GBK"?> 
<!-- 指定Hibernate配置文件的DTD信息 --> 
<!DOCTYPE hibernate-configuration PUBLIC 
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 
<!-- hibernate- configuration是连接配置文件的根元素 --> 
<hibernate-configuration> 
<session-factory> <!-- 看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-->
<!-- 指定连接数据库所用的驱动  注意下面这句哦!!!!就是这句话起关键性的作用--> 
<property name="connection.driver_class">net.bull.javamelody.JdbcDriver</property> 

<property name="connection.driver">oracle.jdbc.driver.OracleDriver</property> 
<!-- 指定连接数据库的url,hibernate连接的数据库名 --> 
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property> 
<property name="connection.useUnicode">true</property> 
<property name="connection.characterEncoding">gbk</property> 
<!-- 指定连接数据库的用户名 --> 
<property name="connection.username">test</property> 
<!-- 指定连接数据库的密码 --> 
<property name="connection.password">test</property> 
<!-- C3P0连接池设定--> 
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> 
<!-- 指定连接池里最大连接数 --> 
<property name="hibernate.c3p0.max_size">20</property> 
<!-- 指定连接池里最小连接数 --> 
<property name="hibernate.c3p0.min_size">1</property> 
<!-- 指定连接池里连接的超时时长 --> 
<property name="hibernate.c3p0.timeout">120</property> 
<!-- 指定连接池里最大缓存多少个Statement对象 --> 
<property name="hibernate.c3p0.max_statements">0</property> 
<property name="hibernate.c3p0.idle_test_period">60</property> 
<property name="hibernate.c3p0.acquire_increment">2</property> 
<property name="hibernate.c3p0.validate">true</property> 
<property name="hibernate.c3p0.preferredTestQuery ">select sysdate from dual </property> 
<property name="hibernate.c3p0.idleConnectionTestPeriod ">120</property> 
<property name="hibernate.c3p0.maxIdleTime">1800</property> 
<property name="hibernate.c3p0.testConnectionOnCheckout">true</property> 

<!-- 指定数据库方言 --> 
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property> 
<!-- 根据需要自动创建数据库 --> 
<property name="hbm2ddl.auto">update</property> 
<!-- 显示Hibernate持久化操作所生成的SQL --> 
<property name="show_sql">true</property> 
<!-- 将SQL脚本进行格式化后再输出--> 
<property name="hibernate.format_sql">true</property> 
<!-- 罗列所有的映射文件--> 
<mapping resource="Person.hbm.xml"/> 

</session-factory> 
</hibernate-configuration>

打开监控页面,就可以看到SQL相关的参数了。

5.2 spring配置方式

另一种情况就是使用spring,是不需要额外设置驱动类的。前提是,必须在加载web.xml的时候指定加载的spring配置文件。需要在web.xml中实现一个监听,这个监听会使web应用在读取web.xml时,加载指定的spring文件。

<listener> 
<listener-class> 
org.springframework.web.context.ContextLoaderListener 
</listener-class> 
</listener> 

然后我们通过设置参数,设置启动的spring文件

<context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>
                classpath:net/bull/javamelody/monitoring-spring.xml
                classpath:context/services.xml
                classpath:context/data-access-layer.xml
                /WEB-INF/applicationContext.xml
          </param-value>
</context-param>

注意monitoring-spring.xml与applicaitonContext.xml的位置。整个web.xml的配置文件,参考下面:

<?xml version="1.0" encoding="GBK"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> 
<!-- 指定spring的配置文件 -->
<context-param> 
<param-name> contextConfigLocation</param-name> 
<param-value> 

classpath:net/bull/javamelody/monitoring-spring.xml classpath:bean.xml
</param-value> 
</context-param> 

<filter> 
<filter-name>struts</filter-name> 
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> 

<init-param> 
<param-name>struts.action.extension</param-name> 
<param-value>action</param-value> 
</init-param> 
</filter> 
<filter-mapping> 
<filter-name>struts</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 

<filter> 
<filter-name>monitoring</filter-name> 
<filter-class>net.bull.javamelody.MonitoringFilter</filter-class> 

<init-param> 
<param-name>log</param-name> 
<param-value>true</param-value> 
</init-param> 
</filter> 
<filter-mapping> 
<filter-name>monitoring</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 
<listener> 
<listener-class> net.bull.javamelody.SessionListener</listener-class> 
</listener> 
<!-- 下面这个用于指定监听,会使web应用去加载spring的配置文件,而不是每次等到用的时候读取-->
<listener> 
<listener-class> 
org.springframework.web.context.ContextLoaderListener 
</listener-class> 
</listener> 
<welcome-file-list> 
<welcome-file>index.jsp</welcome-file> 
</welcome-file-list> 
</web-app>

另外,根据官方文档,如果你的应用与monitoring-spring.xml或者AOP之类的有冲突,那么使用monitoring-spring-datasource.xml文件替代monitoring-spring.xml就可以了,这个文件仅仅包含一个datasource的发送进程以及SpringDataSourceFactoryBean的一个例子。

6、JavaMelody监控spring

JavaMelody针对于spring的监控是到方法级别的,我们可以监控到某个类的某个方法,因此需要使用到AOP里面的pointcut进行监听。

  1. 第一步,导入必备的jar包
  2. 第二步,加载monitoring-spring.xml以及我们自己的applicationContext.xml配置文件。
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<context-param>
    <param-name> contextConfigLocation</param-name>
    <param-value>
        classpath:net/bull/javamelody/monitoring-spring.xml
        /WEB-INF/classes/bean.xml
    </param-value>
 </context-param>

上面第一行,定义了监控应用的spring配置文件,下面是我们自己的spring的配置文件。

  1. 第三步,通过正则表达式,定位方法
<bean id="facadeMonitoringAdvisor" class="net.bull.javamelody.MonitoringSpringAdvisor">
  <property name="pointcut">
   <bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="pattern" value="com.test.*.*" />
   </bean>
  </property>
</bean>

这里面主要是使用了JdkRegexpMethodPointcut,也就是正则表达式定位业务方法。下面的参数可能是pattern或者patterns,参数如下:

com.test.*.* 意思是对应com.test包下的所有类的所有方法
com.test.*.doGet 意思是对应com.test包下所有类的叫doGet的方法
.*Test.* 意思是所有以Test结尾的类的所有方法

具体的配置详情,还需要去学习一下AOP中关于切入点pointcut的使用。如果不会的话,多看一下相关的知识吧。

  1. 第四步,针对想要监控的bean,添加这个拦截器:
<bean id="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="target">
   <ref bean="Computer" />
  </property>
  <property name="interceptorNames">
   <list>
    <value>facadeMonitoringAdvisor</value>
   </list>
  </property>
</bean>

这样在使用ProxyFactoryBean的时候,就会自动调用拦截器interceptorNames,定位到facadeMonitoringAdvisor中的方法,并在方法前后出发net.bull.javamelody.MonitoringSpringAdvisor,进行信息的监控。

7、切面的编程代码

相应切面的编程代码这里也直接附上,有兴趣的可以运行试验下,主要是理解这个思想,就可以监控自己感兴趣的业务了。

public class People{
    // 讲话
     public void speak() {
         System.out.println("Hello,我是People!");
     }
     // 跑步
     public void Running() {
         System.out.println("我在跑……跑…………逃……");
     }
     // 恋爱
     public void Loving() {
        System.out.println("我在和MM恋爱……别来打搅我!");
     }
    // 死亡
     public void died() {
         System.out.println("完了,我死了");
     }
 }

advice类

public class LogerPeople implements MethodBeforeAdvice {

 public void before(Method method, Object[] args, Object target)
   throws Throwable {
  System.out.println(target.getClass().getSimpleName() + "正在" +
 method.getName()+ "!");
  System.out.println("before!________________");

 }
}

TestMain

public class TestMain {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                "bean1.xml");

        //通过ProxyFactoryBean获取IComputer接口实现类的实例
        People c = (People) ac.getBean("ProxyFactoryBean");
        c.speak();
        c.Running();
        c.Loving();
        c.died();
    }
}

spring配置文件

<bean id="Computer" class="com.test.People"></bean>
 <bean id="LogerComputer" class="com.test.LogerPeople" />

 <bean id="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="target">
   <ref bean="Computer" />
  </property>
  <property name="interceptorNames">
   <list>
    <value>DefaultAdvisor</value>
   </list>
  </property>
 </bean>

 <bean id="DefaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
  <property name="pointcut" ref="JdkRegexpPointcut" />
  <property name="advice" ref="LogerComputer" />
 </bean>
 <bean id="JdkRegexpPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
  <property name="patterns">
   <list>
    <value>.*spea.*</value>
    <value>.*ing</value>
    <value>.*di.*</value>
   </list>
  </property>
  <property name="excludedPattern" value=".*Run.*" />
 </bean>
0

评论区