JavaMelody In Action
前言:
在項目的實際運作過程中,我們想知道項目具體運作情況到底是怎麼樣的,比如,我們關心java虛拟機使用的記憶體是多少?執行sql的數量及單個sql執行的時間是怎麼樣的?http 請求有沒有錯誤?定時任務有沒有按時觸發 …等等,但是,大多數情況這些消息對我們是透明的,我們也很難根據項目的實際運作情況進行針對性的優化。這也就導入了我們今天的主題JavaMelody 。
JavaMelody
-
什麼是 JavaMelody
JavaMelody是用來在QA和實際運作生産環境中監控Java或Java EE應用程式伺服器的一個開源架構。主要基于請求的資料統計來演化圖表。
在Spring Boot項目中使用JavaMelody
JavaMelody 已經對 Spring Boot 2 有了充分的內建(spring-boot-starter)的支援,但是對于Spring Boot 1 的工程,是不相容的,不過使用方法與正常的spring項目一緻。
-
Spring Boot 2 內建
隻需要在我們的pom檔案裡面添加上依賴
<dependency>
<groupId>net.bull.javamelody</groupId>
<artifactId>javamelody-spring-boot-starter</artifactId>
<version>1.77.0</version>
</dependency>
然後我們就可以運作我們的項目,打開url:http://localhost:8080/monitoring 看到對應的監控記錄了
我們可以進行對應的針對性的參數設定
javamelody:
# 是否自動裝配,default: true
enabled: true
#排除哪些資料源
excluded-datasources: secretSource,topSecretSource
# 啟動對service和controller的監控, default: true
spring-monitoring-enabled: true
# 初始化JavaMelody中的參數
# See: https://github.com/javamelody/javamelody/wiki/UserGuide#6-optional-parameters
init-parameters:
# log http requests:
log: true
# 排除對某些url的監控:
#url-exclude-pattern: (/webjars/.*|/css/.*|/images/.*|/fonts/.*|/js/.*)
# to aggregate digits in http requests:
#http-transform-pattern: \d+
# 添加基本的資訊驗證
#authorized-users: admin:pwd
# 設定存儲位址:
#storage-directory: /tmp/javamelody
# 設定監控 "/monitoring" 位址:
#monitoring-path: /admin/performance
具體參數請見: https://github.com/javamelody/javamelody/wiki/UserGuide#6-optional-parameters
-
設定預設的url端口
剛才我們談到,預設的url是需要打開8080 端口進行映射的,那如果端口被占用或者我們想換個其他的端口來進行監控資料的話,該怎麼做呢?
- pom檔案添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 配置檔案設定(yml或者properties檔案),以yml檔案為例
- 啟用管理端點并在yml(或properties)中通過http進行端口暴露
management.endpoints.web.exposure.include: info,health,monitoring
javamelody:
management-endpoint-monitoring-enabled: true
-
驗證
http://localhost:8081/actuator/monitoring
大概資訊如下:下面有對應的明細記錄
在Spring Boot 1.x 項目中使用JavaMelody
剛才介紹了在SpringBoot2.0項目中進行元件的內建,那麼對于一般的普通Spring Boot 1.x的項目也很簡單,是以由此也可以看出來,JavaMelody是一個無侵入性的非常優秀的監控架構
-
spring 項目的內建
1)加入pom依賴
<!-- javamelody-core -->
<dependency>
<groupId>net.bull.javamelody</groupId>
<artifactId>javamelody-core</artifactId>
<version>1.77.0</version>
</dependency>
<!-- 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.10</version>
</dependency>
<dependency>
<groupId>org.jrobin</groupId>
<artifactId>jrobin</artifactId>
<version>1.5.9</version>
</dependency>
2)複制下面的配置類
package hello;
import java.util.Arrays;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.sql.DataSource;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.Pointcuts;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import net.bull.javamelody.MonitoredWithAnnotationPointcut;
import net.bull.javamelody.MonitoredWithSpring;
import net.bull.javamelody.MonitoringFilter;
import net.bull.javamelody.MonitoringSpringAdvisor;
import net.bull.javamelody.Parameter;
import net.bull.javamelody.SessionListener;
import net.bull.javamelody.SpringContext;
import net.bull.javamelody.SpringDataSourceBeanPostProcessor;
import net.bull.javamelody.SpringRestTemplateBeanPostProcessor;
/**
* Spring configuration for JavaMelody.
*
*/
@Configuration
@ConditionalOnWebApplication
public class JavaMelodyConfiguration {
/**
* Name of the FilterRegistrationBean.
*/
public static final String REGISTRATION_BEAN_NAME = "javamelody-registration";
/**
* Registers the JavaMelody {@link SessionListener}.
* @param servletContext ServletContext
* @return ServletListenerRegistrationBean
*/
@Bean
public ServletListenerRegistrationBean<EventListener> monitoringSessionListener(
ServletContext servletContext) {
final ServletListenerRegistrationBean<EventListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>(
new SessionListener());
if (servletContext.getFilterRegistration("javamelody") != null) {
// if webapp deployed as war in a container with MonitoringFilter and SessionListener already added by web-fragment.xml,
// do not add again
servletListenerRegistrationBean.setEnabled(false);
}
return servletListenerRegistrationBean;
}
/**
* Registers the JavaMelody {@link MonitoringFilter}.
* @param servletContext ServletContext
* @return FilterRegistrationBean
*/
@Bean(name = REGISTRATION_BEAN_NAME)
public FilterRegistrationBean monitoringFilter(ServletContext servletContext) {
final FilterRegistrationBean registrationBean = new FilterRegistrationBean();
// Create the monitoring filter and set its configuration parameters.
final MonitoringFilter filter = new MonitoringFilter();
filter.setApplicationType("Spring Boot");
// Wrap the monitoring filter in the registration bean.
registrationBean.setFilter(filter);
registrationBean.setAsyncSupported(true);
registrationBean.setName("javamelody");
registrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
// Set the initialization parameter for the monitoring filter.
// see the list of parameters:
// https://github.com/javamelody/javamelody/wiki/UserGuide#6-optional-parameters
registrationBean.addInitParameter(Parameter.LOG.getCode(), Boolean.toString(true));
// to exclude images, css, fonts and js urls from the monitoring:
// javaMelody.addInitParameter(Parameter.URL_EXCLUDE_PATTERN.getCode(), "(/webjars/.*|/css/.*|/images/.*|/fonts/.*|/js/.*)");
// to add basic auth:
// javaMelody.addInitParameter(Parameter.AUTHORIZED_USERS.getCode(), "admin:pwd");
// to change the default storage directory:
// javaMelody.addInitParameter(Parameter.STORAGE_DIRECTORY.getCode(), "/tmp/javamelody");
// Set the URL patterns to activate the monitoring filter for.
registrationBean.addUrlPatterns("/*");
final FilterRegistration filterRegistration = servletContext
.getFilterRegistration("javamelody");
if (filterRegistration != null) {
// if webapp deployed as war in a container with MonitoringFilter already added by web-fragment.xml,
// do not try to add it again
registrationBean.setEnabled(false);
for (final Map.Entry<String, String> entry : registrationBean.getInitParameters()
.entrySet()) {
filterRegistration.setInitParameter(entry.getKey(), entry.getValue());
}
}
return registrationBean;
}
// Note: if you have auto-proxy issues, you can add the following dependency in your pom.xml:
// <dependency>
// <groupId>org.springframework.boot</groupId>
// <artifactId>spring-boot-starter-aop</artifactId>
// </dependency>
@Bean
@ConditionalOnMissingBean(DefaultAdvisorAutoProxyCreator.class)
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
/**
* Monitoring of JDBC {@link DataSource}s
* @param excludedDatasources Comma separated list of excluded datasources
* @return SpringDataSourceBeanPostProcessor
*/
@Bean
public SpringDataSourceBeanPostProcessor monitoringDataSourceBeanPostProcessor(
@Value("${javamelody.excluded-datasources:}") String excludedDatasources) {
final SpringDataSourceBeanPostProcessor processor = new SpringDataSourceBeanPostProcessor();
if (excludedDatasources != null && excludedDatasources.trim().length() > 0) {
processor.setExcludedDatasources(
new HashSet<>(Arrays.asList(excludedDatasources.split(","))));
}
return processor;
}
/**
* Monitoring of beans and methods having the {@link MonitoredWithSpring} annotation.
* @return MonitoringSpringAdvisor
*/
@Bean
public MonitoringSpringAdvisor monitoringSpringAdvisor() {
return new MonitoringSpringAdvisor(new MonitoredWithAnnotationPointcut());
}
/**
* Monitoring of beans having the {@link Service} annotation.
* @return MonitoringSpringAdvisor
*/
@Bean
public MonitoringSpringAdvisor monitoringSpringServiceAdvisor() {
return new MonitoringSpringAdvisor(new AnnotationMatchingPointcut(Service.class));
}
/**
* Monitoring of beans having the {@link Controller} annotation.
* @return MonitoringSpringAdvisor
*/
@Bean
public MonitoringSpringAdvisor monitoringSpringControllerAdvisor() {
return new MonitoringSpringAdvisor(new AnnotationMatchingPointcut(Controller.class));
}
/**
* Monitoring of beans having the {@link RestController} annotation.
* @return MonitoringSpringAdvisor
*/
@Bean
public MonitoringSpringAdvisor monitoringSpringRestControllerAdvisor() {
return new MonitoringSpringAdvisor(new AnnotationMatchingPointcut(RestController.class));
}
/**
* Monitoring of beans or methods having the {@link Async} annotation.
* @return MonitoringSpringAdvisor
*/
@Bean
public MonitoringSpringAdvisor monitoringSpringAsyncAdvisor() {
return new MonitoringSpringAdvisor(
Pointcuts.union(new AnnotationMatchingPointcut(Async.class),
new AnnotationMatchingPointcut(null, Async.class)));
}
/**
* Monitoring of beans methods having the {@link Scheduled} or {@link Schedules} annotations.
* @return MonitoringSpringAdvisor
*/
// @Bean
// public MonitoringSpringAdvisor monitoringSpringScheduledAdvisor() {
// return new MonitoringSpringAdvisor(
// Pointcuts.union(new AnnotationMatchingPointcut(null, Scheduled.class),
// new AnnotationMatchingPointcut(null, Schedules.class)));
// }
/**
* Monitoring of {@link RestTemplate} beans.
* @return SpringRestTemplateBeanPostProcessor
*/
@Bean
public SpringRestTemplateBeanPostProcessor monitoringRestTemplateBeanPostProcessor() {
return new SpringRestTemplateBeanPostProcessor();
}
/**
* @return Reference to the Spring context.
*/
@Bean
public SpringContext javamelodySpringContext() {
return new SpringContext();
}
}
正常情況下,這個時候已經能夠正常運作了,如果不能運作,檢查是否動态代理有問題,如果有問題的話添加aop包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在Spring MVC 項目中使用JavaMelody
-
整合到Spring 項目中
1)添加POM依賴
<!--JavaMelody監控-->
<dependency>
<groupId>net.bull.javamelody</groupId>
<artifactId>javamelody-core</artifactId>
<version>1.74.0</version>
</dependency>
2)在Spring-config.xml中導入配置
<!--javamelody 監控-->
<import resource="classpath:net/bull/javamelody/monitoring-spring.xml"/>
<import resource="classpath:net/bull/javamelody/monitoring-spring-datasource.xml"/>
<import resource="classpath:net/bull/javamelody/monitoring-spring-aspectj.xml"/>
啟動項目,然後打開url:http://localhost:8080/monitoring 檢驗下結果吧!
參考:https://github.com/javamelody/javamelody