4. Spring Boot Admin 功能
点击监控页面上的在线的应用实例,可以跳转到应用实例详细的监控管理页面,也就是 Vue.js 实现的 web 展示。
Spring Boot Admin Server 监控页面
Spring Boot Admin Server 可以监控的功能很多,使用起来没有难度,下面描述下可以监测的部分内容:
- 应用运行状态,如时间、垃圾回收次数,线程数量,内存使用走势。
- 应用性能监测,通过选择 JVM 或者 Tomcat 参数,查看当前数值。
- 应用环境监测,查看系统环境变量,应用配置参数,自动配置参数。
- 应用 bean 管理,查看 Spring Bean ,并且可以查看是否单例。
- 应用计划任务,查看应用的计划任务列表。
- 应用日志管理,动态更改日志级别,查看日志。
- 应用 JVM 管理,查看当前线程运行情况,dump 内存堆栈信息。
- 应用映射管理,查看应用接口调用方法、返回类型、处理类等信息。
上面提到的日志管理,可以动态的更改日志级别,以及查看日志。默认配置下是只可以动态更改日志级别的,如果要在线查看日志,就需要手动配置日志路径了。
客户端上可以像下面这样配置日志路径以及日志高亮。
# 配置文件:application.yml logging: file: name: boot.log pattern: # 日志高亮 file: '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx'
下面是在 Spring Boot Admin 监测页面上查看的客户端应用日志。
Spring Boot Admin Server 查看日志
5. Spring Boot Admin 进阶
5.1. 邮件通知
Spring Boot Admin Server 支持常见的通知方式,比如邮件通知、电报通知、PagerDuty 通知等,下面将会演示常见的通知方式 - 邮件通知,最后也会演示如何通过监听时间进下设置自定义通知方式。
Spring Boot Admin Server 的邮件通知通过 Thymeleaf 模板发送 HTML 格式的电子邮件。因此,想要使用邮件通知首先要引入 Thymeleaf 依赖以及 spring-boot-starter-mail
依赖,并配置邮件发送者信息和接受者信息。
1. 添加依赖
<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> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <!-- Thymeleaf 模版,用于发送模版邮件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
2. 配置邮件
主要设置发送者信息和接收者信息。
spring: boot: admin: notify: mail: # 逗号分隔的邮件收件人列表 to: xxxx@126.com # 开启邮箱通知 enabled: true # 不需要发送通知的状态:从状态A:到状态B ignore-changes: {"UNKNOWN:UP"} # 逗号分隔的抄送收件人列表 cc: xxxx@126.com # 发件人 from: Spring Boot Admin<xxxx@126.com> # 邮件发送者信息 mail: host: smtp.126.com port: 25 username: xxxx@126.com default-encoding: utf-8 password: xxxx
如果想了解更多关于 Spring Boot 邮件发送信息,可以参考 Spring Boot 系列文章第十三篇。
配置好邮件通知之后,重启服务端和客户端,等客户端注册到服务端之后直接终止客户端的运行,稍等片刻就可以在配置的通知接收邮箱里收到客户端实例下线通知了。
Sping Boot Admin Server 邮件通知
邮件通知使用的模板存放在 server 依赖的 classpath:/META-INF/spring-boot-admin-server/mail/status-changed.html 路径,如果想要自定义模板内容。可以拷贝这个文件放到自己的 templates 目录下,修改成自己想要的效果,然后在配置中指定自定义模板路径。
spring: boot: admin: notify: mail: # 自定义邮件模版 template: classpath:/templates/notify.html
5.2 自定义通知
自定义通知只需要自己实现 Spring Boot Admin Server 提供的监听通知类即可,下面会演示如何在实例状态改变时输出实例相关信息。
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; 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.InstanceEvent; import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent; import de.codecentric.boot.admin.server.notify.AbstractEventNotifier; import de.codecentric.boot.admin.server.notify.LoggingNotifier; import reactor.core.publisher.Mono; @Component public class CustomNotifier extends AbstractEventNotifier { private static final Logger LOGGER = LoggerFactory.getLogger(LoggingNotifier.class); public CustomNotifier(InstanceRepository repository) { super(repository); } @Override protected Mono<Void> doNotify(InstanceEvent event, Instance instance) { return Mono.fromRunnable(() -> { if (event instanceof InstanceStatusChangedEvent) { LOGGER.info("Instance {} ({}) is {}", instance.getRegistration().getName(), event.getInstance(), ((InstanceStatusChangedEvent)event).getStatusInfo().getStatus()); } else { LOGGER.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(), event.getType()); } }); } }
5.2. 访问限制
上面提到过,因为客户端增加了暴漏运行信息的相关接口,所以在生产环境中使用存在风险,而服务端没有访问限制,谁的可以访问也是不合理的。
下面将会为客户端和服务端分别增加访问限制,客户端主要是限制敏感接口的访问权限,服务端则是全局的访问限制。这些访问限制都通过 spring 安全框架 security 来实现,所以首先要为客户端和服务端都增加 maven 依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
1. 服务端
在引入安全框架依赖之后,需要配置访问控制,比如静态资源不需要限制,登录登出页面指定等。
import java.util.UUID; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import de.codecentric.boot.admin.server.config.AdminServerProperties; import io.netty.handler.codec.http.HttpMethod; @Configuration(proxyBeanMethods = false) public class SecuritySecureConfig extends WebSecurityConfigurerAdapter { private final AdminServerProperties adminServer; public SecuritySecureConfig(AdminServerProperties adminServer) { this.adminServer = adminServer; } @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(this.adminServer.path("/")); http.authorizeRequests() .antMatchers(this.adminServer.path("/assets/**")).permitAll() .antMatchers(this.adminServer.path("/login")).permitAll() .anyRequest().authenticated() .and() .formLogin().loginPage(this.adminServer.path("/login")).successHandler(successHandler).and() .logout().logoutUrl(this.adminServer.path("/logout")).and() .httpBasic().and() .csrf() .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .ignoringRequestMatchers( new AntPathRequestMatcher(this.adminServer.path("/instances"), HttpMethod.POST.toString()), new AntPathRequestMatcher(this.adminServer.path("/instances/*"), HttpMethod.DELETE.toString()), new AntPathRequestMatcher(this.adminServer.path("/actuator/**")) ) .and() .rememberMe().key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600); // @formatter:on } // 代码配置用户名和密码的方式 // Required to provide UserDetailsService for "remember functionality" // @Override // protected void configure(AuthenticationManagerBuilder auth) throws Exception { // auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER"); // } }
在 application.yml 配置文件中配置用户名和密码。
spring: security: user: name: user password: 123
重启服务端,再次访问就需要用户名和密码进行登录了。
Spring Boot Admin Server 登录
2. 客户端
客户端在引入安全框架之后,也需要配置访问权限,主要是配置哪些路径可以访问,哪些路径访问需要登录限制,默认所有接口都需要登录限制。
同样的,客户端应用也需要在配置中配置客户端应用对于敏感接口的登录用户和密码,同时需要配置 Spring Boot Admin Server 的访问用户和密码,还要把自身的用户和密码注册时告诉服务端,不然服务端不能获取到监测数据。
spring: security: user: # 客户端敏感接口用户和密码 name: client password: 123 application: # 应用名称 name: sjfx-api-search jmx: enabled: true boot: admin: client: # 服务端 url url: http://127.0.0.1:9090 instance: # 客户端实例 url service-url: http://127.0.0.1:8080 prefer-ip: true # 客户端实例名称 name: sjfx-api-search metadata: # 客户端自身的用户和密码告诉服务端 user.name: client user.password: 123 # 服务端用户名密码 username: user password: 123
客户端敏感接口访问测试。
客户端应用访问
到这里,客户端的敏感接口访问需要登录,服务端的管理页面也需要登录,客户端和服务端的访问控制已经完成了。
文中代码已经上传到:github.com/niumoo/springboot/tree/master/springboot-admin
参考资料: