简介
Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。 应用程序作为Spring Boot Admin Client向为Spring Boot Admin Server注册(通过HTTP)或使用SpringCloud注册中心(例如Eureka,Consul)发现。 UI是的AngularJs应用程序,展示Spring Boot Admin Client的Actuator端点上的一些监控。常见的功能或者监控如下:
- 显示健康状况
- 显示详细信息,例如
JVM和内存指标
micrometer.io指标
数据源指标
缓存指标 - 显示构建信息编号
- 关注并下载日志文件
- 查看jvm系统和环境属性
- 查看Spring Boot配置属性
- 支持Spring Cloud的postable / env-和/ refresh-endpoint
- 轻松的日志级管理
- 与JMX-beans交互
- 查看线程转储
- 查看http跟踪
- 查看auditevents
- 查看http-endpoints
- 查看计划任务
- 查看和删除活动会话(使用spring-session)
- 查看Flyway / Liquibase数据库迁移
- 下载heapdump
- 状态变更通知(通过电子邮件,Slack,Hipchat,…)
- 状态更改的事件日志(非持久性)
引用Pom
<!-- 发送邮件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--暴露各种指标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- SpringBootAdmin -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.2.3</version>
</dependency>
<!-- 服务注册 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
Yml文件
spring:
application:
name: spring-boot-admin
main:
allow-bean-definition-overriding: true
boot:
admin:
discovery:
ignored-services: consul
#监控通知邮箱
notify:
mail:
from: 邮箱账号
to: 接收邮箱账号
#配置邮箱
mail:
host: smtp.163.com
username: 邮箱账号
password: 授权码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
#QQ邮箱必须加
ssl:
enable: true
cloud:
consul:
#配置consul服务器的host
host: localhost
#配置端口
port: 8500
discovery:
#配置健康检查时间间隔
health-check-interval: 15s
#配置实例id
instance-id: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
#配置服务注册
register: true
#表示注册时使用ip而不是hostname
prefer-ip-address: true
#健康检查失败多长时间取消注册
health-check-critical-timeout: 30s
全局配置
新建全局配置类:MonkeyConfiguration
package com.admin.admin;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
/**
* @Author: LailaiMonkey
* @Description:
* @Date:Created in 2020-09-29 15:03
* @Modified By:
*/
@Configuration
public class MonkeyConfiguration {
@Bean
public MonkeyCompositeNotifier monkeyCompositeNotifier(InstanceRepository instanceRepository,
JavaMailSender mailSender) {
return new MonkeyCompositeNotifier(instanceRepository, mailSender);
}
}
新建消息模型:MessageBody
```java
package com.admin.admin.sendMessage.model;
/**
* @Author: LailaiMonkey
* @Description:
* @Date:Created in 2020-11-06 15:48
* @Modified By:
*/
public class MessageBody {
/**
* 内容
*/
private String text;
/**
* 标题
*/
private String title;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
新建发送消息类:MonkeyCompositeNotifier
package com.admin.admin;
import com.admin.admin.sendMessage.SendAllMessage;
import com.admin.admin.sendMessage.model.MessageBody;
import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceDeregisteredEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceRegisteredEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.domain.values.Registration;
import de.codecentric.boot.admin.server.domain.values.StatusInfo;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import reactor.core.publisher.Mono;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
/**
* @Author: LailaiMonkey
* @Description:
* @Date:Created in 2020-09-29 15:07
* @Modified By:
*/
public class MonkeyCompositeNotifier extends AbstractEventNotifier {
private static final Logger logger = LoggerFactory.getLogger(MonkeyCompositeNotifier.class);
private JavaMailSender mailSender;
@Value("${spring.boot.admin.notify.mail.from}")
private String from;
@Value("${spring.boot.admin.notify.mail.to}")
private String to;
private final static Map<Class<?>, BiFunction<InstanceEvent, Instance, MessageBody>> cacheMap = new HashMap<>();
static {
//注册
cacheMap.put(InstanceRegisteredEvent.class, MonkeyCompositeNotifier::register);
//注销
cacheMap.put(InstanceDeregisteredEvent.class, MonkeyCompositeNotifier::deRegistered);
//状态变更
cacheMap.put(InstanceStatusChangedEvent.class, MonkeyCompositeNotifier::statusChanged);
}
public MonkeyCompositeNotifier(InstanceRepository repository, JavaMailSender mailSender) {
super(repository);
this.mailSender = mailSender;
}
@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
BiFunction<InstanceEvent, Instance, MessageBody> messageBiFunction = cacheMap.get(event.getClass());
if (messageBiFunction != null) {
MessageBody messageBody = messageBiFunction.apply(event, instance);
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, StandardCharsets.UTF_8.name());
try {
message.setText(messageBody.getText());
message.setSubject(messageBody.getTitle());
message.setTo(to);
message.setFrom(from);
mailSender.send(mimeMessage);
} catch (MessagingException e) {
e.printStackTrace();
logger.error("发送邮件异常!", e);
}
}
});
}
/**
* 注册通知
*
* @param event
* @param instance
* @return
*/
private static MessageBody register(InstanceEvent event, Instance instance) {
Registration registration = instance.getRegistration();
MessageBody body = new MessageBody();
body.setText("服务名称:" + registration.getName() + " 服务地址:" + registration.getServiceUrl());
body.setTitle("服务上线通知!");
return body;
}
/**
* 注销通知
*
* @param event
* @param instance
* @return
*/
private static MessageBody deRegistered(InstanceEvent event, Instance instance) {
Registration registration = instance.getRegistration();
MessageBody body = new MessageBody();
body.setText("服务名称:" + registration.getName() + " 服务地址:" + registration.getServiceUrl());
body.setTitle("服务下线通知!");
return body;
}
/**
* 状态变更通知
*
* @param event
* @param instance
* @return
*/
private static MessageBody statusChanged(InstanceEvent event, Instance instance) {
StatusInfo statusInfo = ((InstanceStatusChangedEvent) event).getStatusInfo();
Registration registration = instance.getRegistration();
MessageBody body = new MessageBody();
body.setText("服务名称:" + registration.getName() + " 服务地址:" + registration.getServiceUrl() + " 状态:" + statusInfo.getStatus());
body.setTitle("服务状态变量通知!");
return body;
}
}
如果看过源码的小伙伴知道,自带发送邮件服务继承AbstractStatusChangeNotifier
,而我们需要重写他的方法是无法收到消息,这是为什么呢?
它有一个shouldNotify
方法,把一些方法过滤了。所以我们继承AbstractEventNotifier
。
@Override
protected boolean shouldNotify(InstanceEvent event, Instance instance) {
if (event instanceof InstanceStatusChangedEvent) {
InstanceStatusChangedEvent statusChange = (InstanceStatusChangedEvent) event;
String from = getLastStatus(event.getInstance());
String to = statusChange.getStatusInfo().getStatus();
return Arrays.binarySearch(ignoreChanges, from + ":" + to) < 0
&& Arrays.binarySearch(ignoreChanges, "*:" + to) < 0
&& Arrays.binarySearch(ignoreChanges, from + ":*") < 0;
}
return false;
}
而且他本身的邮件通知只支持InstanceStatusChangedEvent(状态变更通知)
,没有注册、上下线通知,所以我们重写一个。
访问:http://localhost:8080出现管理界面
权限访问配置
- 添加Pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 配置文件
spring:
security:
user:
name: "admin"
password: "admin"
访问页面时候会弹出登录界面。