简单介绍
Spring Boot Actuator 是 Spring Boot 自带的一个功能模块,
提供了一组已经开箱即用的生产环境下常用的特性和服务,比如应用程序的健康检查、信息暴露、度量收集、日志记录等。
在实际项目中,Actuator 可以帮助我们快速了解应用程序的运行状态和性能瓶颈。
整合SpringBoot-Admin监控,Spring Boot Admin 就是将 Spring Boot Actuator中提供的endpoint信息可视化展示。
环境
Springboot: 2.1.1.RELEASE
注意:不同的SpringBoot版本,所用到的依赖会不一致。本版本亲测可用哦。
服务端简单搭建
核心依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.1.6</version>
</dependency><dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-server-ui-login</artifactId><version>1.5.7</version>
</dependency>
启动类
@EnableAdminServer //开启admin服务端
@SpringBootApplication
public class BootAdminServerApplication {public static void main(String[] args) {SpringApplication.run(BootAdminServerApplication.class, args);}}
配置文件
server:port: 8001servlet:context-path: /admin-server
spring:application:name: admin-server
启动服务后,访问:http://localhost:8001/admin-server
安全认证
核心依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
SecuritySecureConfig 拦截器Code
@EnableWebSecurity
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {private final String adminContextPath;public SecuritySecureConfig(AdminServerProperties adminServer) {this.adminContextPath = adminServer.getContextPath();}@Overrideprotected void configure(HttpSecurity http) throws Exception {SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();successHandler.setTargetUrlParameter("redirectTo");successHandler.setDefaultTargetUrl(adminContextPath + "/");http.authorizeRequests().antMatchers(adminContextPath + "/login",adminContextPath + "/assets/**",adminContextPath + "/manage/**",adminContextPath + "/actuator/**",adminContextPath + "/login.html").permitAll().anyRequest().authenticated().and().formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and().logout().logoutUrl(adminContextPath + "/logout").and().httpBasic().and().csrf().disable();}}
修改配置
新增以下配置
spring:security:user:name: adminpassword: admin
启动服务后,访问:http://localhost:8001/admin-server
输入用户名,密码即可。
客户端
核心依赖
<!--加入spring-boot-admin连接端-->
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId><version>2.1.6</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
配置文件
如果你不想开启安全认证请参考以下的配置。
admin-server 未开启安全认证
server:port: 7001spring:application:name: admin-client# 配置spring-boot-admin服务端的地址boot:admin:client:url: 'http://localhost:8001/admin-server'#展示全部细节信息
management:endpoints:web:exposure:include: '*'#允许admin工程远程停止本应用endpoint:health:enabled: trueshow-details: alwaysshutdown:enabled: true
admin-server 开启安全认证
server:port: 7001spring:application:name: admin-client# 配置spring-boot-admin服务端的地址boot:admin:client:url: 'http://localhost:8001/admin-server'username: adminpassword: admin#展示全部细节信息
management:endpoints:web:exposure:include: '*'#允许admin工程远程停止本应用endpoint:health:enabled: trueshow-details: alwaysshutdown:enabled: true
查看Admin-Server端页面
如何实现服务 告警通知
当我们的服务发生异常时, 可以通过邮件、微信、钉钉等发送告警信息。
Server 端新增以下配置类。
@Component
public class AdminNotifier extends AbstractStatusChangeNotifier {private static final Logger log = LoggerFactory.getLogger(AdminNotifier.class);/*** 消息模板*/private static final String template = "<<<%s>>> \n 【服务名】: %s(%s) \n 【状态】: %s(%s) \n 【服务ip】: %s \n 【详情】: %s";private String titleAlarm = "系统告警";private String titleNotice = "系统通知";private String[] ignoreChanges = new String[]{"UNKNOWN:UP", "DOWN:UP", "OFFLINE:UP"};public AdminNotifier(InstanceRepository repository) {super(repository);}@Overrideprotected boolean shouldNotify(InstanceEvent event, Instance instance) {if (!(event instanceof InstanceStatusChangedEvent)) {return false;} else {InstanceStatusChangedEvent statusChange = (InstanceStatusChangedEvent) event;String from = this.getLastStatus(event.getInstance());String to = statusChange.getStatusInfo().getStatus();return Arrays.binarySearch(this.ignoreChanges, from + ":" + to) < 0 && Arrays.binarySearch(this.ignoreChanges, "*:" + to) < 0 && Arrays.binarySearch(this.ignoreChanges, from + ":*") < 0;}}@Overrideprotected Mono<Void> doNotify(InstanceEvent event, Instance instance) {return Mono.fromRunnable(() -> {if (event instanceof InstanceStatusChangedEvent) {log.info("Instance {} ({}) is {}", instance.getRegistration().getName(),event.getInstance(),((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();String messageText = null;switch (status) {// 健康检查没通过case "DOWN":log.info("发送 健康检查没通过 的通知!");messageText = String.format(template, titleAlarm, instance.getRegistration().getName(), event.getInstance(),((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "健康检查没通过通知",instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));log.info(messageText);break;// 服务离线case "OFFLINE":log.info("发送 服务离线 的通知!");messageText = String.format(template, titleAlarm, instance.getRegistration().getName(), event.getInstance(),((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服务离线通知",instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));log.info(messageText);break;//服务上线case "UP":log.info("发送 服务上线 的通知!");messageText = String.format(template, titleNotice, instance.getRegistration().getName(), event.getInstance(),((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服务上线通知",instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));log.info(messageText);break;// 服务未知异常case "UNKNOWN":log.info("发送 服务未知异常 的通知!");messageText = String.format(template, titleAlarm, instance.getRegistration().getName(), event.getInstance(),((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服务未知异常通知",instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));log.info(messageText);break;default:break;}} else {log.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),event.getType());}});}
}
如下图所示: