本文目录导读:

我来为您提供一个完整的Spring Boot整合Prometheus的案例,包括监控指标采集、自定义指标和Grafana可视化。
项目依赖配置
Maven依赖 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-prometheus</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
<micrometer.version>1.9.5</micrometer.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Micrometer Prometheus Registry -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${micrometer.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 数据库相关(示例使用) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件
application.yml
server:
port: 8080
spring:
application:
name: springboot-prometheus-demo
# H2数据库配置(示例)
h2:
console:
enabled: true
path: /h2-console
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
# Actuator配置
management:
endpoints:
web:
exposure:
include: "*"
exclude: "env,beans"
endpoint:
health:
show-details: always
probes:
enabled: true
metrics:
enabled: true
prometheus:
enabled: true
metrics:
export:
prometheus:
enabled: true
step: 1m
descriptions: true
tags:
application: ${spring.application.name}
enable:
jvm: true
http: true
logback: true
distribution:
percentiles-histogram:
http.server.requests: true
slo:
http.server.requests: 10ms, 50ms, 100ms, 200ms, 500ms, 1s, 5s
percentiles:
http.server.requests: 0.5, 0.9, 0.95, 0.99
主应用类
package com.example.prometheus;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class PrometheusApplication {
public static void main(String[] args) {
SpringApplication.run(PrometheusApplication.class, args);
}
}
自定义指标示例
自定义指标注册器
package com.example.prometheus.metrics;
import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class CustomMetrics {
private final MeterRegistry meterRegistry;
@Autowired
public CustomMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
// 计数器示例
public Counter requestCounter;
// 仪表盘示例
public Gauge activeUsers;
// 直方图示例
public Timer requestTimer;
// 摘要示例
public DistributionSummary responseSize;
@PostConstruct
public void init() {
// 创建计数器
requestCounter = Counter.builder("custom_requests_total")
.description("Total number of requests")
.tag("type", "custom")
.register(meterRegistry);
// 创建仪表盘(返回一个函数)
AtomicInteger userCount = new AtomicInteger(0);
activeUsers = Gauge.builder("custom_active_users", userCount,
AtomicInteger::get)
.description("Current number of active users")
.tag("type", "custom")
.register(meterRegistry);
// 创建计时器
requestTimer = Timer.builder("custom_request_duration")
.description("Request processing time")
.publishPercentiles(0.5, 0.9, 0.95, 0.99)
.publishPercentileHistogram()
.sla(Duration.ofMillis(100), Duration.ofMillis(500))
.register(meterRegistry);
// 创建摘要
responseSize = DistributionSummary.builder("custom_response_size")
.description("Response size")
.baseUnit("bytes")
.register(meterRegistry);
}
}
业务服务示例
package com.example.prometheus.service;
import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.search.Search;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Random;
@Service
@Slf4j
public class OrderService {
@Autowired
private MeterRegistry meterRegistry;
private final Random random = new Random();
// 订单计数器
private final Counter orderCounter;
// 订单处理时间
private final Timer orderTimer;
// 活跃用户数
private final AtomicInteger activeUsers = new AtomicInteger(0);
public OrderService(MeterRegistry registry) {
this.orderCounter = registry.counter("orders_total", "type", "business");
this.orderTimer = registry.timer("order_processing_time");
// 注册仪表盘
registry.gauge("active_users", activeUsers, AtomicInteger::get);
}
/**
* 创建订单
*/
public Order createOrder(OrderRequest request) {
long startTime = System.currentTimeMillis();
try {
// 模拟业务处理
Thread.sleep(random.nextInt(200));
// 创建订单逻辑
Order order = new Order();
order.setId(System.currentTimeMillis());
order.setName(request.getName());
order.setAmount(request.getAmount());
// 增加订单计数
orderCounter.increment();
// 记录订单数量
meterRegistry.counter("orders_created_total", "type", "business", "status", "success")
.increment();
log.info("Order created: {}", order.getId());
return order;
} catch (Exception e) {
meterRegistry.counter("orders_created_total", "type", "business", "status", "failed")
.increment();
log.error("Create order failed", e);
throw new RuntimeException("Create order failed", e);
} finally {
// 记录订单处理时间
long duration = System.currentTimeMillis() - startTime;
orderTimer.record(Duration.ofMillis(duration));
responseSize.record(random.nextInt(1024));
}
}
/**
* 用户登录
*/
public void userLogin() {
activeUsers.incrementAndGet();
meterRegistry.counter("user_logins_total").increment();
}
/**
* 用户登出
*/
public void userLogout() {
if (activeUsers.get() > 0) {
activeUsers.decrementAndGet();
}
}
/**
* 获取活跃用户数
*/
public int getActiveUsers() {
return activeUsers.get();
}
}
控制器示例
package com.example.prometheus.controller;
import com.example.prometheus.metrics.CustomMetrics;
import com.example.prometheus.service.OrderService;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/api")
@Slf4j
public class ApiController {
@Autowired
private OrderService orderService;
@Autowired
private CustomMetrics customMetrics;
@Autowired
private MeterRegistry meterRegistry;
/**
* 创建订单接口
*/
@PostMapping("/orders")
@Timed(value = "api.orders.create", extraTags = {"version", "v1"})
public Map<String, Object> createOrder(@RequestBody OrderRequest request) {
Map<String, Object> response = new HashMap<>();
try {
// 记录请求计数
customMetrics.requestCounter.increment();
// 计时器
long startTime = System.nanoTime();
// 调用服务
Object order = orderService.createOrder(request);
// 记录请求时间
customMetrics.requestTimer.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
response.put("success", true);
response.put("data", order);
} catch (Exception e) {
response.put("success", false);
response.put("error", e.getMessage());
}
// 记录响应大小
customMetrics.responseSize.record(response.toString().length());
return response;
}
/**
* 用户登录
*/
@PostMapping("/login")
public String login(@RequestBody LoginRequest request) {
orderService.userLogin();
return "Login successful";
}
/**
* 用户登出
*/
@PostMapping("/logout")
public String logout() {
orderService.userLogout();
return "Logout successful";
}
/**
* 测试接口
*/
@GetMapping("/test")
public String test() {
// 模拟不同的响应时间
long startTime = System.currentTimeMillis();
try {
int delay = (int) (Math.random() * 300);
Thread.sleep(delay);
} catch (InterruptedException e) {
log.error("Test endpoint interrupted", e);
Thread.currentThread().interrupt();
}
customMetrics.requestCounter.increment();
customMetrics.requestTimer.record(System.currentTimeMillis() - startTime,
TimeUnit.MILLISECONDS);
return "Test endpoint - " + System.currentTimeMillis();
}
/**
* 获取当前指标
*/
@GetMapping("/metrics/status")
public Map<String, Object> getMetricsStatus() {
Map<String, Object> metrics = new HashMap<>();
metrics.put("active_users", orderService.getActiveUsers());
metrics.put("total_requests", customMetrics.requestCounter.count());
return metrics;
}
}
@Data
class OrderRequest {
private String name;
private Double amount;
}
@Data
class LoginRequest {
private String username;
private String password;
}
自定义注解支持
自定义计时器注解
package com.example.prometheus.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Timed {
String name() default "";
String[] extraTags() default {};
}
AOP切面
package com.example.prometheus.aspect;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class MetricsAspect {
@Autowired
private MeterRegistry meterRegistry;
@Around("@annotation(timed)")
public Object measureTime(ProceedingJoinPoint joinPoint, Timed timed) throws Throwable {
String methodName = timed.name().isEmpty()
? joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()
: timed.name();
Timer timer = Timer.builder(methodName)
.tags(timed.extraTags())
.publishPercentiles(0.5, 0.9, 0.99)
.register(meterRegistry);
long start = System.nanoTime();
try {
return joinPoint.proceed();
} finally {
timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
}
}
}
Prometheus配置
prometheus.yml
# Prometheus配置文件
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'spring-boot-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
labels:
application: 'springboot-prometheus-demo'
environment: 'development'
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
Docker Compose 配置
docker-compose.yml
version: '3.8'
services:
# Spring Boot应用
springboot-app:
build: .
container_name: springboot-prometheus-app
ports:
- "8080:8080"
networks:
- monitoring
# Prometheus
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
networks:
- monitoring
depends_on:
- springboot-app
# Grafana
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
volumes:
- grafana-data:/var/lib/grafana
networks:
- monitoring
depends_on:
- prometheus
# Node Exporter(可选)
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
ports:
- "9100:9100"
networks:
- monitoring
volumes:
prometheus-data:
grafana-data:
networks:
monitoring:
driver: bridge
Grafana Dashboard配置
dashboard.json (示例)
{
"dashboard": {
"id": null,: "Spring Boot Application Monitoring",
"tags": ["spring-boot", "prometheus"],
"timezone": "browser",
"schemaVersion": 16,
"version": 1,
"refresh": "5s",
"panels": [
{
"title": "HTTP Request Rate",
"type": "graph",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"targets": [
{
"expr": "rate(http_server_requests_seconds_count[5m])",
"legendFormat": "{{method}} - {{uri}}"
}
]
},
{
"title": "HTTP Request Duration",
"type": "graph",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))",
"legendFormat": "P95"
},
{
"expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))",
"legendFormat": "P99"
}
]
},
{
"title": "JVM Memory Usage",
"type": "graph",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8},
"targets": [
{
"expr": "jvm_memory_used_bytes{jvm_area='heap'}",
"legendFormat": "Heap"
},
{
"expr": "jvm_memory_used_bytes{jvm_area='non-heap'}",
"legendFormat": "Non-Heap"
}
]
},
{
"title": "Custom Metrics - Orders",
"type": "singlestat",
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 16},
"targets": [
{
"expr": "orders_total{type='business'}",
"legendFormat": "Total Orders"
}
],
"valueName": "total"
},
{
"title": "Request Counter",
"type": "singlestat",
"gridPos": {"h": 4, "w": 6, "x": 6, "y": 16},
"targets": [
{
"expr": "custom_requests_total{type='custom'}",
"legendFormat": "Total Requests"
}
],
"valueName": "current"
}
]
}
}
使用说明
测试步骤
-
启动应用
mvn clean package java -jar target/springboot-prometheus-1.0.0.jar
-
访问Prometheus指标
- 打开浏览器访问:
http://localhost:8080/actuator/prometheus - 查看自定义指标:
custom_requests_total、custom_active_users
- 调用接口生成指标
# 创建订单 curl -X POST http://localhost:8080/api/orders \ -H "Content-Type: application/json" \ -d '{"name": "Test Order", "amount": 100.50}'
测试接口
curl http://localhost:8080/api/test
模拟登录登出
curl -X POST http://localhost:8080/api/login \ -H "Content-Type: application/json" \ -d '{"username": "user1", "password": "pass123"}'
curl -X POST http://localhost:8080/api/logout
4. **配置Prometheus**
- 启动Prometheus:`docker-compose up prometheus`
- 访问:`http://localhost:9090/targets`
5. **配置Grafana**
- 启动Grafana:`docker-compose up grafana`
- 访问:`http://localhost:3000`(用户名/密码:admin/admin)
- 添加数据源:Configuration → Data Sources → Add data source → Prometheus
- 设置URL为:`http://prometheus:9090`
## 11. 常见指标说明
| 指标名称 | 类型 | 说明 |
|---------|------|------|
| `http_server_requests_seconds` | Histogram | HTTP请求耗时 |
| `jvm_memory_used_bytes` | Gauge | JVM内存使用 |
| `custom_requests_total` | Counter | 自定义请求总数 |
| `custom_active_users` | Gauge | 活跃用户数 |
| `orders_created_total` | Counter | 创建的订单数 |
| `order_processing_time` | Timer | 订单处理时间 |
这个完整的案例展示了Spring Boot与Prometheus集成的各个方面,包括基础配置、自定义指标、监控数据采集和可视化,您可以根据实际需求进行扩展和调整。