整合springboot admin 监控 – springboot(十五)

人生之路坎坎坷坷,跌跌撞撞在所难免。但是,不论跌了多少次,你都必须坚强勇敢地站起来。任何时候,无论你面临着生命的何等困惑抑或经受着多少挫折,无论道路多艰难,希望变得如何渺茫,请你不要绝望,再试一次,坚持到底,成功终将属于勇不言败的你。

导读:本篇文章讲解 整合springboot admin 监控 – springboot(十五),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

还是看官网文档省事!!!!!!
链接: springboot admin官方文档.

链接: Springboot + spring boot admin 监控 spring security权限控制.

链接: SpringBoot Admin安全配置.

链接: SpringSecurityGet请求可以响应,Post请求无法响应返回403 Forbidden.

链接: SpringBoot2整合SpringBootAdmin监控管理服务上下线.

链接: Springboot中日志logging.file过时以及配置方法【简单】.

链接: spring boot admin 404问题.

链接: 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

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!