簡介
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"
通路頁面時候會彈出登入界面。