美文网首页Spring
Spring boot | Actuator

Spring boot | Actuator

作者: 不一样的卡梅利多 | 来源:发表于2020-05-30 12:16 被阅读0次

    1、简介

    Spring Boot Actuator 是一个为生产环境准备(Production-ready Features)的功能,提供了对生产环境的管理和监控功能。使用只需要添加一个依赖就可以了。

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    

    该功能由两子个项目组成,他的功能实现与配置都独立与spring-boot项目。


    Actuator Boot.png
    2、实现

    它通过向web 容器注册自己的servlet 来实现,在actuator 项目中定义为Endpoint(servlet), Endpoint实现类与请求的 URL向匹配。Operation与HTTP 方法对应,并且绑定Endpoint实现类的method。如何与SpringMVC DispatcherServlet 相兼容,见下文配置部分。


    Operation vs HTTP-Method.png
    1、注册servlet

    org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar

    actuator 项目注册逻辑:

    public class ServletEndpointRegistrar implements ServletContextInitializer {
    
    public void onStartup(ServletContext servletContext) throws ServletException {
            this.servletEndpoints.forEach((servletEndpoint) -> register(servletContext, servletEndpoint));
        }
    
    private void register(ServletContext servletContext, ExposableServletEndpoint endpoint) {
            String name = endpoint.getEndpointId().toLowerCaseString() + "-actuator-endpoint";
            String path = this.basePath + "/" + endpoint.getRootPath();
            String urlMapping = path.endsWith("/") ? path + "*" : path + "/*";
            EndpointServlet endpointServlet = endpoint.getEndpointServlet();
            Dynamic registration = servletContext.addServlet(name, endpointServlet.getServlet());
            registration.addMapping(urlMapping);
            registration.setInitParameters(endpointServlet.getInitParameters());
            registration.setLoadOnStartup(endpointServlet.getLoadOnStartup());
            logger.info("Registered '" + path + "' to " + name);
        }
    }
    

    actuator-autoconfigure
    判断有没有DispatcherServlet,DispatcherServlet 会影响注册的servlet 匹配路径,实现了与DispatcherServlet 兼容配置。
    ServletEndpointManagementContextConfiguration

    
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass(DispatcherServlet.class)
        public static class WebMvcServletEndpointManagementContextConfiguration {
    
            @Bean
            public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties,
                    ServletEndpointsSupplier servletEndpointsSupplier, DispatcherServletPath dispatcherServletPath) {
                return new ServletEndpointRegistrar(dispatcherServletPath.getRelativePath(properties.getBasePath()),
                        servletEndpointsSupplier.getEndpoints());
            }
    
        }
    
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass(ResourceConfig.class)
        @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
        public static class JerseyServletEndpointManagementContextConfiguration {
    
            @Bean
            public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties,
                    ServletEndpointsSupplier servletEndpointsSupplier, JerseyApplicationPath jerseyApplicationPath) {
                return new ServletEndpointRegistrar(jerseyApplicationPath.getRelativePath(properties.getBasePath()),
                        servletEndpointsSupplier.getEndpoints());
            }
    
        }
    

    实例化ServletEndpointRegistrar 依赖的ServletEndpointsSupplier。

    @Configuration(proxyBeanMethods = false)
        @ConditionalOnWebApplication(type = Type.SERVLET)
        static class WebEndpointServletConfiguration {
    
            @Bean
            @ConditionalOnMissingBean(ServletEndpointsSupplier.class)
            ServletEndpointDiscoverer servletEndpointDiscoverer(ApplicationContext applicationContext,
                    ObjectProvider<PathMapper> endpointPathMappers,
                    ObjectProvider<EndpointFilter<ExposableServletEndpoint>> filters) {
                return new ServletEndpointDiscoverer(applicationContext,
                        endpointPathMappers.orderedStream().collect(Collectors.toList()),
                        filters.orderedStream().collect(Collectors.toList()));
            }
    
        }
    

    ServletEndpointDiscoverer 会扫描SpringContext 里面被@Endpoint 注解的bean 定义。

        private Collection<EndpointBean> createEndpointBeans() {
    .....
            String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.applicationContext,
                    Endpoint.class);
    .....   
            return byId.values();
        }
    

    将EndpointBean 转换为ExposableEndpoint 然后在获取 EndpointServlet,这样就能注册到容器的中去。简言之,一个被@Endpoint注解的类,会被当成一个Servlet 注册到容器中。url 路径有默认值。

    2、方法调用

    通过http 请求的url 匹配(请求路径+请求方法)到对应的servlet ,由servlet 实现类调用到类里面具体的某一个方法。中间还有参数匹配与参数转换等等。。

    3、HealthEndpoint

    HealthEndpoint 是一个特殊的Endpoint,他对所有实现了HealthContributor 接口的bean 的聚合功能。

    3.1 HealthEndpoint 类

    请求health 接口时候会从 HealthContributorRegistry 注册中心返回匹配的HealthContributor ,然后调用getHealth方法。如果匹配到多个HealthContributor,将会聚合结果返回。

    @Endpoint(id = "health")
    public class HealthEndpoint extends HealthEndpointSupport<HealthContributor, HealthComponent>{
    
    public HealthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups groups) {
            super(registry, groups);
        }
    
    @ReadOperation
        public HealthComponent health() {
            HealthComponent health = health(ApiVersion.V3, EMPTY_PATH);
            return (health != null) ? health : DEFAULT_HEALTH;
        }
    」
    

    3.2 自动配置部分
    1、实例化HealthEndpoint
    2、将所有实现了HealthContributor 接口部分的类注册到HealthContributorRegistry中。

    @Configuration(proxyBeanMethods = false)
    class HealthEndpointConfiguration {
        @Bean
        @ConditionalOnMissingBean
        HealthContributorRegistry healthContributorRegistry(ApplicationContext applicationContext,
                HealthEndpointGroups groups) {
            Map<String, HealthContributor> healthContributors = new LinkedHashMap<>(
                    applicationContext.getBeansOfType(HealthContributor.class));
            if (ClassUtils.isPresent("reactor.core.publisher.Flux", applicationContext.getClassLoader())) {
                healthContributors.putAll(new AdaptedReactiveHealthContributors(applicationContext).get());
            }
            return new AutoConfiguredHealthContributorRegistry(healthContributors, groups.getNames());
        }
    
          @Bean
        @ConditionalOnMissingBean
        HealthEndpoint healthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups groups) {
            return new HealthEndpoint(registry, groups);
        }
    
    
    }
    

    3.3 自定义 HealthContributor 举例

    NacosConfigHealthIndicator 继承AbstractHealthIndicator

    public class NacosConfigHealthIndicator extends AbstractHealthIndicator {
    
        private final ConfigService configService;
    
        public NacosConfigHealthIndicator(ConfigService configService) {
            this.configService = configService;
        }
    
        @Override
        protected void doHealthCheck(Health.Builder builder) throws Exception {
            // Just return "UP" or "DOWN"
            String status = configService.getServerStatus();
            // Set the status to Builder
            builder.status(status);
            switch (status) {
            case "UP":
                builder.up();
                break;
            case "DOWN":
                builder.down();
                break;
            default:
                builder.unknown();
                break;
            }
        }
    
    }
    

    添加bean 定义

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnEnabledHealthIndicator("nacos-config")
        public NacosConfigHealthIndicator nacosConfigHealthIndicator() {
            return new NacosConfigHealthIndicator(nacosConfigManager.getConfigService());
        }
    

    访问health 接口将返回Nacos 配置状态。

    小结:

    对线上环境的监控非常重要,Spring Boot Actuator 为我们提供一些常用的监控和管理功能。我们在需要监控xx 的时候,可以先看下有没有现成的实现,它已经实现的大部分常用功能。我们在使用Spring Boot Actuator同时 ,还需要注意接口的安全性。避免非法调用,跨权限使用。


    Spring-Boot-Actuator.png

    Spring 专题

    相关文章

      网友评论

        本文标题:Spring boot | Actuator

        本文链接:https://www.haomeiwen.com/subject/rbmczhtx.html