zoukankan      html  css  js  c++  java
  • 如何做自己的服务监控?spring boot 2.x服务监控揭秘

    Actuatorspring boot项目中非常强大一个功能,有助于对应用程序进行监视和管理,通过 restful api请求来监管、审计、收集应用的运行情况,针对微服务而言它是必不可少的一个环节。

    spring 2.x actuator相对于spring 1.x actuator做了较大的改变。

    如何做自己的服务监控?spring boot 1.x服务监控揭秘

     ****提供了更多的endpoint管理

    IDDescriptionEnabled by default

    auditevents

    Exposes audit events information for the current application.

    Yes

    beans

    Displays a complete list of all the Spring beans in your application.

    Yes

    caches

    Exposes available caches.

    Yes

    conditions

    Shows the conditions that were evaluated on configuration and auto-configuration classes and the reasons why they did or did not match.

    Yes

    configprops

    Displays a collated list of all @ConfigurationProperties.

    Yes

    env

    Exposes properties from Spring’s ConfigurableEnvironment.

    Yes

    flyway

    Shows any Flyway database migrations that have been applied.

    Yes

    health

    Shows application health information.

    Yes

    httptrace

    Displays HTTP trace information (by default, the last 100 HTTP request-response exchanges).

    Yes

    info

    Displays arbitrary application info.

    Yes

    integrationgraph

    Shows the Spring Integration graph.

    Yes

    loggers

    Shows and modifies the configuration of loggers in the application.

    Yes

    liquibase

    Shows any Liquibase database migrations that have been applied.

    Yes

    metrics

    Shows ‘metrics’ information for the current application.

    Yes

    mappings

    Displays a collated list of all @RequestMapping paths.

    Yes

    scheduledtasks

    Displays the scheduled tasks in your application.

    Yes

    sessions

    Allows retrieval and deletion of user sessions from a Spring Session-backed session store. Not available when using Spring Session’s support for reactive web applications.

    Yes

    shutdown

    Lets the application be gracefully shutdown.

    No

    threaddump

    Performs a thread dump.

    Yes

    If your application is a web application (Spring MVC, Spring WebFlux, or Jersey), you can use the following additional endpoints:

    IDDescriptionEnabled by default

    heapdump

    Returns an hprof heap dump file.

    Yes

    jolokia

    Exposes JMX beans over HTTP (when Jolokia is on the classpath, not available for WebFlux).

    Yes

    logfile

    Returns the contents of the logfile (if logging.file or logging.path properties have been set). Supports the use of the HTTP Range header to retrieve part of the log file’s content.

    Yes

    prometheus

    Exposes metrics in a format that can be scraped by a Prometheus server.

    Yes

    ********更多的metrics

    • JVM metrics, report utilization of:

      • Various memory and buffer pools
      • Statistics related to garbage collection
      • Threads utilization
      • Number of classes loaded/unloaded
    • CPU metrics
    • File descriptor metrics
    • Kafka consumer metrics
    • Log4j2 metrics: record the number of events logged to Log4j2 at each level
    • Logback metrics: record the number of events logged to Logback at each level
    • Uptime metrics: report a gauge for uptime and a fixed gauge representing the application’s absolute start time
    • Tomcat metrics
    • Spring Integration metrics

    *********内部实现也发生了较大的变化,使用micrometer第三方工具来完成metric的实现。下面我们就亲自看看吧!

    1.准备源码

    https://github.com/tjanusz-personal/springbootrestdemo/tree/master/src/main/java/com/demo/springbootrestdemo

    2.导入并启动项目

    ( ( )\___ | '_ | '_| | '_ / _` |    
     \/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.0.4.RELEASE)
    
    2019-01-17 11:20:39.076  INFO 5180 --- [           main] c.d.s.SpringbootrestdemoApplication      : Starting SpringbootrestdemoApplication on DESKTOP-405G2C8 with PID 5180 (E:documentspringbootrestdemouildclassesjavamain started by dell in E:documentspringbootrestdemo)
    2019-01-17 11:20:39.080  INFO 5180 --- [           main] c.d.s.SpringbootrestdemoApplication      : No active profile set, falling back to default profiles: default
    2019-01-17 11:20:39.147  INFO 5180 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6f01b95f: startup date [Thu Jan 17 11:20:39 CST 2019]; root of context hierarchy
    WARNING: An illegal reflective access operation has occurred
    WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (file:/D:/gradle/caches/modules-2/files-2.1/org.springframework/spring-core/5.0.8.RELEASE/dc39c49e3246cdf73d3786ac41119140aed3fa08/spring-core-5.0.8.RELEASE.jar) to method java.lang.ClassLoader.defineClass(java.lang.Stri
    ng,byte[],int,int,java.security.ProtectionDomain)
    WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1
    WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
    WARNING: All illegal access operations will be denied in a future release
    2019-01-17 11:20:40.341  INFO 5180 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.hateoas.config.HateoasConfiguration' of type [org.springframework.hateoas.config.HateoasConfiguration$$EnhancerBySpringCGLIB$$ecf2a812] is not eligible for getting processed by a
    ll BeanPostProcessors (for example: not eligible for auto-proxying)
    2019-01-17 11:20:40.982  INFO 5180 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
    2019-01-17 11:20:41.015  INFO 5180 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2019-01-17 11:20:41.016  INFO 5180 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.32
    2019-01-17 11:20:41.029  INFO 5180 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [D:softwarejdk11in;C:WindowsSunJavain;C:Windowssys
    tem32;C:Windows;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:WindowsSystem32OpenSSH;D:softwarejdk11in;D:softwareTortoiseGitin;D:softwareGitcmd;D:softwareapache-maven-3.5.4in;D:softwaregradle-4.10.2in;D:softwaregoin;D:s
    oftwareantin;D:softwareanaconda;D:softwareanacondaScripts;D:softwareanacondaLibraryin;C:UsersdellAppDataLocalMicrosoftWindowsApps;;.]
    2019-01-17 11:20:41.162  INFO 5180 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2019-01-17 11:20:41.168  INFO 5180 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2035 ms
    2019-01-17 11:20:41.832  INFO 5180 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
    2019-01-17 11:20:41.832  INFO 5180 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'webMvcMetricsFilter' to: [/*]
    2019-01-17 11:20:41.832  INFO 5180 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpTraceFilter' to: [/*]
    2019-01-17 11:20:41.833  INFO 5180 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
    2019-01-17 11:20:41.960  INFO 5180 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/saveUrl],methods=[POST],consumes=[application/json;charset=UTF-8 || application/x-www-form-urlencoded],produces=[application/json;charset=UTF-8 || application/xml]}" onto public com.demo.spring
    bootrestdemo.domain.response.SaveUrlResponse com.demo.springbootrestdemo.web.DemoController.saveUrl(com.demo.springbootrestdemo.domain.request.SaveUrlRequest,java.lang.String,java.lang.String)
    2019-01-17 11:20:41.961  INFO 5180 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/alive],methods=[GET]}" onto public com.demo.springbootrestdemo.domain.response.DemoPingResponse com.demo.springbootrestdemo.web.DemoController.alive()
    2019-01-17 11:20:41.964  INFO 5180 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http
    .HttpServletRequest,javax.servlet.http.HttpServletResponse)
    2019-01-17 11:20:41.964  INFO 5180 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.err
    or(javax.servlet.http.HttpServletRequest)
    2019-01-17 11:20:42.038  INFO 5180 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6f01b95f: startup date [Thu Jan 17 11:20:39 CST 2019]; root of context hierar
    chy
    2019-01-17 11:20:42.087  INFO 5180 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : Detected @ExceptionHandler methods in restResponseEntityExceptionHandler
    2019-01-17 11:20:42.529  INFO 5180 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 14 endpoint(s) beneath base path '/actuator'
    2019-01-17 11:20:42.538  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/auditevents],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.serv
    let.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.539  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/beans],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.Ab
    stractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.539  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.A
    bstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.540  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/conditions],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servl
    et.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.540  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/configprops],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.serv
    let.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.540  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/env/{toMatch}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.se
    rvlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.541  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/env],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.Abst
    ractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.541  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.Abs
    tractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.541  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/loggers/{name}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.s
    ervlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.542  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/loggers/{name}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.
    servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.542  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/loggers],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.
    AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.543  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/heapdump],methods=[GET],produces=[application/octet-stream]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$Op
    erationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.543  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/threaddump],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servl
    et.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.543  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/metrics],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.
    AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.544  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/metrics/{requiredMetricName}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.
    endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.544  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/scheduledtasks],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.s
    ervlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.544  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/httptrace],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servle
    t.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.545  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/mappings],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet
    .AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
    2019-01-17 11:20:42.546  INFO 5180 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springfr
    amework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
    2019-01-17 11:20:42.590  INFO 5180 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2019-01-17 11:20:42.641  INFO 5180 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2019-01-17 11:20:42.648  INFO 5180 --- [           main] c.d.s.SpringbootrestdemoApplication      : Started SpringbootrestdemoApplication in 4.008 seconds (JVM running for 4.517)
    <=========----> 75% EXECUTING [25s]
    > :bootRun

    3.获取EndPoint

    3.0 来源

            "webEndpointServletHandlerMapping": {
              "aliases": [
                
              ],
              "scope": "singleton",
              "type": "org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping",
              "resource": "class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/servlet/WebMvcEndpointManagementContextConfiguration.class]",
              "dependencies": [
                "webEndpointDiscoverer",
                "servletEndpointDiscoverer",
                "controllerEndpointDiscoverer",
                "endpointMediaTypes",
                "management.endpoints.web.cors-org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties",
                "management.endpoints.web-org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties"
              ]
            }

     spring.factories定义了

    org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=
    org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyManagementChildContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementChildContextConfiguration,
    org.springframework.boot.actuate.autoconfigure.web.servlet.WebMvcEndpointChildContextConfiguration

    3.1 映射

        @Bean
        @ConditionalOnMissingBean
        public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(
                WebEndpointsSupplier webEndpointsSupplier,
                ServletEndpointsSupplier servletEndpointsSupplier,
                ControllerEndpointsSupplier controllerEndpointsSupplier,
                EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
                WebEndpointProperties webEndpointProperties) {
            List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
            Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier
                    .getEndpoints();
            allEndpoints.addAll(webEndpoints);
            allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
            allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
            EndpointMapping endpointMapping = new EndpointMapping(
                    webEndpointProperties.getBasePath());
            return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints,
                    endpointMediaTypes, corsProperties.toCorsConfiguration(),
                    new EndpointLinksResolver(allEndpoints,
                            webEndpointProperties.getBasePath()));
        }

    3.2 获取EndPoint

    3.2.1 EndPoint定义

    /**
     * Identifies a type as being an actuator endpoint that provides information about the
     * running application. Endpoints can be exposed over a variety of technologies including
     * JMX and HTTP.
     * <p>
     * Most {@code @Endpoint} classes will declare one or more
     * {@link ReadOperation @ReadOperation}, {@link WriteOperation @WriteOperation},
     * {@link DeleteOperation @DeleteOperation} annotated methods which will be automatically
     * adapted to the exposing technology (JMX, Spring MVC, Spring WebFlux, Jersey etc.).
     * <p>
     * {@code @Endpoint} represents the lowest common denominator for endpoints and
     * intentionally limits the sorts of operation methods that may be defined in order to
     * support the broadest possible range of exposure technologies. If you need deeper
     * support for a specific technology you can either write an endpoint that is
     * {@link FilteredEndpoint filtered} to a certain technology, or provide
     * {@link EndpointExtension extension} for the broader endpoint.
     *
     * @author Andy Wilkinson
     * @author Phillip Webb
     * @since 2.0.0
     * @see EndpointExtension
     * @see FilteredEndpoint
     * @see EndpointDiscoverer
     */

    使用了@Endpoint注解的类

     3.2.2 获取所有的EndPoint

        @Override
        public final Collection<E> getEndpoints() {
            if (this.endpoints == null) {
                this.endpoints = discoverEndpoints();
            }
            return this.endpoints;
        }
    
        private Collection<E> discoverEndpoints() {
            Collection<EndpointBean> endpointBeans = createEndpointBeans();
            addExtensionBeans(endpointBeans);
            return convertToEndpoints(endpointBeans);
        }
    
        private Collection<EndpointBean> createEndpointBeans() {
            Map<EndpointId, EndpointBean> byId = new LinkedHashMap<>();
            String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(
                    this.applicationContext, Endpoint.class);
            for (String beanName : beanNames) {
                if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                    EndpointBean endpointBean = createEndpointBean(beanName);
                    EndpointBean previous = byId.putIfAbsent(endpointBean.getId(),
                            endpointBean);
                    Assert.state(previous == null,
                            () -> "Found two endpoints with the id '" + endpointBean.getId()
                                    + "': '" + endpointBean.getBeanName() + "' and '"
                                    + previous.getBeanName() + "'");
                }
            }
            return byId.values();
        }
    
        private EndpointBean createEndpointBean(String beanName) {
            Object bean = this.applicationContext.getBean(beanName);
            return new EndpointBean(beanName, bean);
        }
    
        private void addExtensionBeans(Collection<EndpointBean> endpointBeans) {
            Map<EndpointId, EndpointBean> byId = endpointBeans.stream()
                    .collect(Collectors.toMap(EndpointBean::getId, Function.identity()));
            String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(
                    this.applicationContext, EndpointExtension.class);
            for (String beanName : beanNames) {
                ExtensionBean extensionBean = createExtensionBean(beanName);
                EndpointBean endpointBean = byId.get(extensionBean.getEndpointId());
                Assert.state(endpointBean != null,
                        () -> ("Invalid extension '" + extensionBean.getBeanName()
                                + "': no endpoint found with id '"
                                + extensionBean.getEndpointId() + "'"));
                addExtensionBean(endpointBean, extensionBean);
            }
        }

    3.3 WebMvcEndpointHandlerMapping

    3.3.0 spring mvc的流程复习

    其中:

     第2步获取HandlerMapping,其层次结构

    其中RequestMappingHandlerMapping用来处理@RequestMapping注解

        private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
            RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
            RequestCondition<?> condition = (element instanceof Class ?
                    getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
            return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
        }

    第3步获取HandlerAdapter,其层次结构

     

    默认handlerMapping和handlerAdapter定义在DispatcherServlet.properties

    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
        org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
        org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
        org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

    3.3.1 获取WebMvcEndpointHandlerMapping

        /**
         * Creates a new {@code WebMvcEndpointHandlerMapping} instance that provides mappings
         * for the given endpoints.
         * @param endpointMapping the base mapping for all endpoints
         * @param endpoints the web endpoints
         * @param endpointMediaTypes media types consumed and produced by the endpoints
         * @param corsConfiguration the CORS configuration for the endpoints or {@code null}
         * @param linksResolver resolver for determining links to available endpoints
         */
        public WebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
                Collection<ExposableWebEndpoint> endpoints,
                EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration,
                EndpointLinksResolver linksResolver) {
            super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration);
            this.linksResolver = linksResolver;
            setOrder(-100);
        }

    父类实现了initHandlerMethods()

        @Override
        protected void initHandlerMethods() {
            for (ExposableWebEndpoint endpoint : this.endpoints) {
                for (WebOperation operation : endpoint.getOperations()) {
                    registerMappingForOperation(endpoint, operation);
                }
            }
            if (StringUtils.hasText(this.endpointMapping.getPath())) {
                registerLinksMapping();
            }
        }

    将endpoint的Operation映射到Method级别,类似于@RequestMapping

        private void registerMappingForOperation(ExposableWebEndpoint endpoint,
                WebOperation operation) {
            ServletWebOperation servletWebOperation = wrapServletWebOperation(endpoint,
                    operation, new ServletWebOperationAdapter(operation));
            registerMapping(createRequestMappingInfo(operation),
                    new OperationHandler(servletWebOperation), this.handleMethod);
        }
    
        /**
         * Hook point that allows subclasses to wrap the {@link ServletWebOperation} before
         * it's called. Allows additional features, such as security, to be added.
         * @param endpoint the source endpoint
         * @param operation the source operation
         * @param servletWebOperation the servlet web operation to wrap
         * @return a wrapped servlet web operation
         */
        protected ServletWebOperation wrapServletWebOperation(ExposableWebEndpoint endpoint,
                WebOperation operation, ServletWebOperation servletWebOperation) {
            return servletWebOperation;
        }
    
        private RequestMappingInfo createRequestMappingInfo(WebOperation operation) {
            WebOperationRequestPredicate predicate = operation.getRequestPredicate();
            PatternsRequestCondition patterns = patternsRequestConditionForPattern(
                    predicate.getPath());
            RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition(
                    RequestMethod.valueOf(predicate.getHttpMethod().name()));
            ConsumesRequestCondition consumes = new ConsumesRequestCondition(
                    StringUtils.toStringArray(predicate.getConsumes()));
            ProducesRequestCondition produces = new ProducesRequestCondition(
                    StringUtils.toStringArray(predicate.getProduces()));
            return new RequestMappingInfo(null, patterns, methods, null, null, consumes,
                    produces, null);
        }

     3.3.2 获取ServletWebOperationAdapter 

    AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle

            @Override
            public Object handle(HttpServletRequest request,
                    @RequestBody(required = false) Map<String, String> body) {
                Map<String, Object> arguments = getArguments(request, body);
                try {
                    return handleResult(
                            this.operation.invoke(new InvocationContext(
                                    new ServletSecurityContext(request), arguments)),
                            HttpMethod.valueOf(request.getMethod()));
                }
                catch (InvalidEndpointRequestException ex) {
                    throw new BadOperationRequestException(ex.getReason());
                }
            }

    4.触发机制

    If you add a @Bean annotated with @Endpoint, any methods annotated with @ReadOperation@WriteOperation, or @DeleteOperation are automatically exposed over JMX and, in a web application, over HTTP as well. Endpoints can be exposed over HTTP using Jersey, Spring MVC, or Spring WebFlux.

    if you need access to web-framework-specific functionality, you can implement Servlet or Spring @Controller and @RestController endpoints at the cost of them not being available over JMX or when using a different web framework.

    EndpointDiscoverer

        @Override
        public final Collection<E> getEndpoints() {
            if (this.endpoints == null) {
                this.endpoints = discoverEndpoints();
            }
            return this.endpoints;
        }
    
        private Collection<E> discoverEndpoints() {
            Collection<EndpointBean> endpointBeans = createEndpointBeans();
            addExtensionBeans(endpointBeans);
            return convertToEndpoints(endpointBeans);
        }

    调用 @ReadOperation@WriteOperation, or @DeleteOperation方法

        private void addOperations(MultiValueMap<OperationKey, O> indexed, EndpointId id,
                Object target, boolean replaceLast) {
            Set<OperationKey> replacedLast = new HashSet<>();
            Collection<O> operations = this.operationsFactory.createOperations(id, target);
            for (O operation : operations) {
                OperationKey key = createOperationKey(operation);
                O last = getLast(indexed.get(key));
                if (replaceLast && replacedLast.add(key) && last != null) {
                    indexed.get(key).remove(last);
                }
                indexed.add(key, operation);
            }
        }

    其中DiscoveredOperationsFactory定义了@ReadOperation@WriteOperation, or @DeleteOperation方法

        private static final Map<OperationType, Class<? extends Annotation>> OPERATION_TYPES;
    
        static {
            Map<OperationType, Class<? extends Annotation>> operationTypes = new EnumMap<>(
                    OperationType.class);
            operationTypes.put(OperationType.READ, ReadOperation.class);
            operationTypes.put(OperationType.WRITE, WriteOperation.class);
            operationTypes.put(OperationType.DELETE, DeleteOperation.class);
            OPERATION_TYPES = Collections.unmodifiableMap(operationTypes);
        }
    
        private final ParameterValueMapper parameterValueMapper;
    
        private final Collection<OperationInvokerAdvisor> invokerAdvisors;
    
        DiscoveredOperationsFactory(ParameterValueMapper parameterValueMapper,
                Collection<OperationInvokerAdvisor> invokerAdvisors) {
            this.parameterValueMapper = parameterValueMapper;
            this.invokerAdvisors = invokerAdvisors;
        }
    
        public Collection<O> createOperations(EndpointId id, Object target) {
            return MethodIntrospector.selectMethods(target.getClass(),
                    (MetadataLookup<O>) (method) -> createOperation(id, target, method))
                    .values();
        }
    
        private O createOperation(EndpointId endpointId, Object target, Method method) {
            return OPERATION_TYPES.entrySet().stream()
                    .map((entry) -> createOperation(endpointId, target, method,
                            entry.getKey(), entry.getValue()))
                    .filter(Objects::nonNull).findFirst().orElse(null);
        }

    总结:

    1.若一个Bean在类上使用@Endpoint注解,并且在方法上使用@ReadOperation@WriteOperation, or @DeleteOperation注解,那么自动可以使用jmx或者http访问,http提供服务的可以是Jersey, Spring MVC或者Spring WebFlux.

    2.http提供服务的基本机制

    2.1 使用HandlerMapping映射请求
    2.2 使用HandlerAdapter(自定义)聚合EndPoint,并代理EndPoint的请求。

    参考文献

    【1】https://terasolunaorg.github.io/guideline/1.0.x/en/Overview/SpringMVCOverview.html

    【2】https://docs.spring.io/spring-boot/docs/2.1.2.RELEASE/reference/htmlsingle/#production-ready-enabling

  • 相关阅读:
    Springcloudalibaba之Nacos服务注册和配置中心
    SpringBoot监控工具包Actuator使用
    服务注册中心之Consul使用
    微服务项目SpringcloudAlibaba
    微服务之链路跟踪SpringCloudSleuth
    微服务之消息驱动SpringCloudStream
    微服务之消息总线SpringCloudBus
    微服务之配置中心Config
    深入理解javascript原型和闭包(1)——一切都是对象
    js中函数创建的三种方式
  • 原文地址:https://www.cnblogs.com/davidwang456/p/10281420.html
Copyright © 2011-2022 走看看