还是看官网文档省事!!!!!!
链接: springboot admin官方文档.
链接: Springboot + spring boot admin 监控 spring security权限控制.
链接: SpringBoot Admin安全配置.
链接: SpringSecurityGet请求可以响应,Post请求无法响应返回403 Forbidden.
链接: SpringBoot2整合SpringBootAdmin监控管理服务上下线.
链接: Springboot中日志logging.file过时以及配置方法【简单】.
链接: Spring MVC容器的web九大组件之—HandlerAdapter源码详解—HttpMessageConverter的匹配规则(选择原理).
监控服务端
导入所需依赖
<!--添加actuator依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--spring boot admin依赖-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.3.1</version>
</dependency>
<!-- security 权限 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.4.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
开启@EnableAdminServer
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableAdminServer
@SpringBootApplication
public class ActuatorApplication {
public static void main(String[] args) {
SpringApplication.run(ActuatorApplication.class, args);
}
}
yml配置
server:
port: 8088
服务端配置用户认证
import de.codecentric.boot.admin.server.config.AdminServerProperties;
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.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl("/");
http.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").successHandler(successHandler).and()
.logout().logoutUrl("/logout").and()
.httpBasic().and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers(
"/instances",
"/actuator/**"
);
}
/**
* 在内存中配置一个用户,admin/admin分别是用户名和密码,这个用户拥有USER角色。
* withDefaultPasswordEncoder 被遗弃,原因是不安全,只能在例子中使用
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("admin")
.password(encoder.encode("admin"))
.roles("ADMIN");
}
}
访问http://127.0.0.1:8088
客户端
导入依赖
<!--添加actuator依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--spring boot admin依赖-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.3.1</version>
</dependency>
<!-- security 权限 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.4.5</version>
</dependency>
客户端配置用户认证
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.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
/***
* 指定让它拦截actuator的接口即可,业务相关的接口由业务权限系统去控制
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/actuator/**").authenticated().anyRequest().permitAll();
// 关闭CSRF,否则POST请求必须带上token
http.csrf().disable();
}
/**
* 在内存中配置一个用户,admin/admin分别是用户名和密码,这个用户拥有USER角色。
* withDefaultPasswordEncoder 被遗弃,原因是不安全,只能在例子中使用
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("user")
.password(encoder.encode("user"))
.roles("USER");
}
}
导入依赖
spring:
boot:
admin:
client:
url: http://127.0.0.1:8088 # 监控端地址
username: admin
password: admin
instance:
service-base-url: http://127.0.0.1:8080 # 本项目的地址
metadata:
user.name: user
user.password: user
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
访问http://127.0.0.1:8080/actuator
认证配置成功
也已经连接监控端成功
注意 项目中使用druid 数据连接池的话 得以下加上配置,否则监控面板查看配置属性时,监控的对应项目会down掉,原因不明待研究
# 开启连接池回收
remove-abandoned: true
# 超时连接回收时间,单位秒
remove-abandoned-timeout: 30
注意 2.4.0版本会报错 (强迫中断一个远程连接主机 ),所以降低到 2.3.1 版本 原因不明待研究
springboot 版本 2.4.4
spring-boot-admin-starter-server 2.4.0
spring-boot-admin-starter-client 2.4.0
注意配置查看日志时
链接: springboot 整合 Druid 及 Log4j2(六).
spring:
boot:
admin:
client:
url: http://127.0.0.1:8088 # 监控端地址
username: admin
password: admin
instance:
service-base-url: http://127.0.0.1:8080 # 本项目的地址
metadata:
user.name: user
user.password: user
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
logfile:
external-file: D:/log/demoLog/all.log
info:
version: 23333
name: 测试项目
author: zm
blog: https://blog.csdn.net/qq_41604890
logging:
config: classpath:log4j2.xml
level:
root: info
# 方便Spring Boot Admin页面上实时查看日志
file:
name: all.log
path: D:/log/demoLog
服务端端自定义通知
可是使用责任链模式或策略模式设计分等级的通知机制
整合邮件通知(小问题)
整合钉钉推送(大问题)
import com.alibaba.fastjson.JSONObject;
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.AbstractStatusChangeNotifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Arrays;
@Component
public class StatusChangeNotifier extends AbstractStatusChangeNotifier {
private static Logger log = LoggerFactory.getLogger(StatusChangeNotifier.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"};
public StatusChangeNotifier(InstanceRepository repository) {
super(repository);
}
@Override
protected boolean shouldNotify(InstanceEvent event, Instance instance) {
if (event instanceof InstanceStatusChangedEvent) {
InstanceStatusChangedEvent statusChange = (InstanceStatusChangedEvent) event;
String from = this.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;
}
@Override
protected 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 noticeContent = "服务未知异常通知";
String title = titleAlarm;
if ("DOWN".equals(status)) {
noticeContent = "健康检查没通过通知";
}
if ("OFFLINE".equals(status)) {
noticeContent = "服务离线通知";
}
if ("UP".equals(status)) {
title = titleNotice;
noticeContent = "服务上线通知";
}
String messageText = String
.format(template, title, instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), noticeContent,
instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
System.out.println(messageText);
// 通知机制在这里写
// .......
return;
}
log.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
event.getType());
});
}
}
客户端client 的自定义检测
import cn.hutool.system.RuntimeInfo;
import cn.hutool.system.SystemUtil;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 自定义的健康检查
*/
@Component
public class DivIndicator implements HealthIndicator {
private BigDecimal ALARM_RATIO = new BigDecimal("20");
private BigDecimal cardinalNumber = new BigDecimal("100");
@Override
public Health health() {
Health health;
RuntimeInfo runtimeInfo = SystemUtil.getRuntimeInfo();
long freeMemory = runtimeInfo.getFreeMemory();
long totalMemory = runtimeInfo.getTotalMemory();
BigDecimal remainingMemoryRatio = new BigDecimal(String.valueOf(freeMemory))
.divide(new BigDecimal(String.valueOf(totalMemory)), 2, BigDecimal.ROUND_HALF_UP)
.multiply(cardinalNumber);
String percentage = remainingMemoryRatio + "%";
if(remainingMemoryRatio.compareTo(ALARM_RATIO) == -1){
health = Health.down()
.withDetail("memoryRatio", percentage)
.withDetail("message", "JVM可用内存不足" + percentage)
.build();
}else {
health = Health.up()
.withDetail("memoryRatio", percentage)
.withDetail("message", "JVM可用内存剩余"+ percentage)
.build();
}
return health;
}
}
出现Connection prematurely closed BEFORE response问题
解决链接: springcloud gateway 采用 netty作为服务容器中的bug.
额外配置
spring:
#配置actuator admin主机地址
boot:
admin:
client:
url: http://xxxxxxxx:8088 # server服务端的地址
username: root
password: xxxxx # server服务端密码
instance:
service-base-url: http://xxxxxxxx:8082 # 本项目的地址
metadata: # 本项目的用户名 密码
user.name: user
user.password: xxxxx
name: dd-platform # 本项目的名称
#配置actuator-client设置
management:
endpoint:
health:
show-details: ALWAYS #显示具体健康信息
endpoints:
web:
exposure:
include: "*" #开启暴露所有端口信息
exclude: configprops,mappings #不暴露的端口信息
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/133941.html