zoukankan      html  css  js  c++  java
  • Spring Boot Actuator 使用

    转载于:https://www.jianshu.com/p/af9738634a21

    Spring Boot 的 Actuator 提供了很多生产级的特性,比如监控和度量Spring Boot 应用程序。Actuator 的这些特性可以通过众多 REST 接口、远程 shell 和 JMX 获得。

    一、Actuator 的 REST 接口

    Spring Boot Actuator 的关键特性是在应用程序里提供众多 Web 接口,通过它们了解应用程序运行时的内部状况。Actuator 提供了 13 个接口,可以分为三大类:配置接口、度量接口和其它接口,具体如下表所示。

    HTTP 方法路径描述
    GET /autoconfig 提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没通过
    GET /configprops 描述配置属性(包含默认值)如何注入Bean
    GET /beans 描述应用程序上下文里全部的Bean,以及它们的关系
    GET /dump 获取线程活动的快照
    GET /env 获取全部环境属性
    GET /env/{name} 根据名称获取特定的环境属性值
    GET /health 报告应用程序的健康指标,这些值由HealthIndicator的实现类提供
    GET /info 获取应用程序的定制信息,这些信息由info打头的属性提供
    GET /mappings 描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系
    GET /metrics 报告各种应用程序度量信息,比如内存用量和HTTP请求计数
    GET /metrics/{name} 报告指定名称的应用程序度量值
    POST /shutdown 关闭应用程序,要求endpoints.shutdown.enabled设置为true
    GET /trace 提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

    要启用 Actuator 的端点,只要在项目中引入 Actuator 的依赖即可。对于 Maven 依赖,引入的依赖是这样的:

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

    1. 查看配置明细

    Actuator 有一些接口不仅可以显示组件映射关系,还可以告诉你自动配置在配置 Spring 应用程序上下文时做了哪些决策。

    1.1 获得 Bean 装配报告

    要了解应用程序中 Spring 上下文的情况,最重要的接口就是 /beans。它会返回一个 JSON 文档,描述上下文里每个 bean 的情况,包括其 Java 类型以及注入的其它 bean。返回的信息如下所示:

    [
        {
            "context": "application",
            "parent": null,
            "beans": [
                {
                    "bean": "demoApplication",
                    "aliases": [],
                    "scope": "singleton",
                    "type": "com.example.DemoApplication$$EnhancerBySpringCGLIB$$88686e04",
                    "resource": "null",
                    "dependencies": []
                },
                {
                    "bean": "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory",
                    "aliases": [],
                    "scope": "singleton",
                    "type": "org.springframework.core.type.classreading.CachingMetadataReaderFactory",
                    "resource": "null",
                    "dependencies": []
                }
            ]
        }
    ]
    

    所有的 Bean 条目都有五类信息:

    • bean:Spring 应用程序上下文中的 Bean 名称或 ID。
    • resource:.class 文件的物理位置,通常是一个 URL,指向构建出的 JAR 文件。这会随着应用程序的构建和运行方式发生变化。
    • dependencies:当前 Bean 注入的 Bean ID 列表。
    • scope:Bean 的作用域(通常是单例,这也是默认作用域)。
    • type:Bean 的 Java 类型。
    1.2 详解自动配置

    /autoconfig接口能告诉你为什么会有这个 bean ,或者为什么没有这个 bean。

    {
        "positiveMatches": {
            "AuditAutoConfiguration#auditListener": [
                {
                    "condition": "OnBeanCondition",
                    "message": "@ConditionalOnMissingBean (types: org.springframework.boot.actuate.audit.listener.AbstractAuditListener; SearchStrategy: all) did not find any beans"
                }
            ],
            "MultipartAutoConfiguration#multipartConfigElement": [
                {
                    "condition": "OnBeanCondition",
                    "message": "@ConditionalOnMissingBean (types: javax.servlet.MultipartConfigElement; SearchStrategy: all) did not find any beans"
                }
            ]
        },
        "negativeMatches": {
            "AuditAutoConfiguration#authenticationAuditListener": {
                "notMatched": [
                    {
                        "condition": "OnClassCondition",
                        "message": "@ConditionalOnClass did not find required class 'org.springframework.security.authentication.event.AbstractAuthenticationEvent'"
                    }
                ],
                "matched": []
            },
            "AuditAutoConfiguration#authorizationAuditListener": {
                "notMatched": [
                    {
                        "condition": "OnClassCondition",
                        "message": "@ConditionalOnClass did not find required class 'org.springframework.security.access.event.AbstractAuthorizationEvent'"
                    }
                ],
                "matched": []
            }
        }
    }
    
    1.3 查看配置属性

    /env接口会生成应用程序可用的所有环境属性的列表,无论这些属性是否用到。这其中包括环境变量、JVM 属性、命令行参数,以及 application.properties 或 application.yml 文件提供的属性。

    {
        "profiles": [],
        "server.ports": {
            "local.server.port": 8080
        },
        "servletContextInitParams": {},
        "systemProperties": {
            "java.runtime.name": "Java(TM) SE Runtime Environment",
            "spring.output.ansi.enabled": "always",
            "sun.boot.library.path": "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib",
            "java.vm.version": "25.121-b13",
            "gopherProxySet": "false",
            "java.vm.vendor": "Oracle Corporation",
            "java.vendor.url": "http://java.oracle.com/",
            "path.separator": ":",
            "idea.launcher.port": "7532",
            "java.vm.name": "Java HotSpot(TM) 64-Bit Server VM",
            "file.encoding.pkg": "sun.io",
            "user.country": "CN",
            "sun.java.launcher": "SUN_STANDARD",
            "sun.os.patch.level": "unknown",
            "PID": "2716",
            "java.vm.specification.name": "Java Virtual Machine Specification",
            "user.dir": "/Users/FlySheep/FlySheep/Code/ServerCode/SpringBoot_Demo/demo",
            "java.runtime.version": "1.8.0_121-b13",
            "java.awt.graphicsenv": "sun.awt.CGraphicsEnvironment",
            "org.jboss.logging.provider": "slf4j",
            "java.endorsed.dirs": "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/endorsed",
            "os.arch": "x86_64",
            "visualvm.id": "11136812717769",
            "java.io.tmpdir": "/var/folders/d6/zn9yrwns46j4pwbl1_mv_6hw0000gn/T/",
            "line.separator": "
    ",
            "java.vm.specification.vendor": "Oracle Corporation",
            "os.name": "Mac OS X",
            "sun.jnu.encoding": "UTF-8",
            "spring.beaninfo.ignore": "true",
            "java.library.path": "/Users/FlySheep/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.",
            "java.specification.name": "Java Platform API Specification",
            "java.class.version": "52.0",
            "sun.management.compiler": "HotSpot 64-Bit Tiered Compilers",
            "os.version": "10.11",
            "user.home": "/Users/FlySheep",
            "catalina.useNaming": "false",
            "user.timezone": "Asia/Shanghai",
            "java.awt.printerjob": "sun.lwawt.macosx.CPrinterJob",
            "file.encoding": "UTF-8",
            "idea.launcher.bin.path": "/Applications/IntelliJ IDEA.app/Contents/bin",
            "java.specification.version": "1.8",
            "catalina.home": "/private/var/folders/d6/zn9yrwns46j4pwbl1_mv_6hw0000gn/T/tomcat.6698906163877756728.8080",
            "java.class.path": "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/lib/tools.jar:/Users/FlySheep/FlySheep/Code/ServerCode/SpringBoot_Demo/demo/target/classes:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-starter-web/1.5.2.RELEASE/spring-boot-starter-web-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-starter/1.5.2.RELEASE/spring-boot-starter-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot/1.5.2.RELEASE/spring-boot-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.5.2.RELEASE/spring-boot-autoconfigure-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-starter-logging/1.5.2.RELEASE/spring-boot-starter-logging-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/ch/qos/logback/logback-classic/1.1.11/logback-classic-1.1.11.jar:/Users/FlySheep/.m2/repository/ch/qos/logback/logback-core/1.1.11/logback-core-1.1.11.jar:/Users/FlySheep/.m2/repository/org/slf4j/jcl-over-slf4j/1.7.24/jcl-over-slf4j-1.7.24.jar:/Users/FlySheep/.m2/repository/org/slf4j/jul-to-slf4j/1.7.24/jul-to-slf4j-1.7.24.jar:/Users/FlySheep/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.24/log4j-over-slf4j-1.7.24.jar:/Users/FlySheep/.m2/repository/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/1.5.2.RELEASE/spring-boot-starter-tomcat-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.11/tomcat-embed-core-8.5.11.jar:/Users/FlySheep/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/8.5.11/tomcat-embed-el-8.5.11.jar:/Users/FlySheep/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.11/tomcat-embed-websocket-8.5.11.jar:/Users/FlySheep/.m2/repository/org/hibernate/hibernate-validator/5.3.4.Final/hibernate-validator-5.3.4.Final.jar:/Users/FlySheep/.m2/repository/javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.jar:/Users/FlySheep/.m2/repository/org/jboss/logging/jboss-logging/3.3.0.Final/jboss-logging-3.3.0.Final.jar:/Users/FlySheep/.m2/repository/com/fasterxml/classmate/1.3.3/classmate-1.3.3.jar:/Users/FlySheep/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.8.7/jackson-databind-2.8.7.jar:/Users/FlySheep/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar:/Users/FlySheep/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.8.7/jackson-core-2.8.7.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-web/4.3.7.RELEASE/spring-web-4.3.7.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-aop/4.3.7.RELEASE/spring-aop-4.3.7.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-beans/4.3.7.RELEASE/spring-beans-4.3.7.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-context/4.3.7.RELEASE/spring-context-4.3.7.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-webmvc/4.3.7.RELEASE/spring-webmvc-4.3.7.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-expression/4.3.7.RELEASE/spring-expression-4.3.7.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-starter-actuator/1.5.2.RELEASE/spring-boot-starter-actuator-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/springframework/boot/spring-boot-actuator/1.5.2.RELEASE/spring-boot-actuator-1.5.2.RELEASE.jar:/Users/FlySheep/.m2/repository/org/slf4j/slf4j-api/1.7.24/slf4j-api-1.7.24.jar:/Users/FlySheep/.m2/repository/org/springframework/spring-core/4.3.7.RELEASE/spring-core-4.3.7.RELEASE.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar",
            "user.name": "FlySheep",
            "java.vm.specification.version": "1.8",
            "sun.java.command": "com.intellij.rt.execution.application.AppMain com.example.DemoApplication",
            "java.home": "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre",
            "sun.arch.data.model": "64",
            "user.language": "zh",
            "java.specification.vendor": "Oracle Corporation",
            "awt.toolkit": "sun.lwawt.macosx.LWCToolkit",
            "java.vm.info": "mixed mode",
            "java.version": "1.8.0_121",
            "java.ext.dirs": "/Users/FlySheep/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java",
            "sun.boot.class.path": "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/classes",
            "java.awt.headless": "true",
            "java.vendor": "Oracle Corporation",
            "catalina.base": "/private/var/folders/d6/zn9yrwns46j4pwbl1_mv_6hw0000gn/T/tomcat.6698906163877756728.8080",
            "file.separator": "/",
            "java.vendor.url.bug": "http://bugreport.sun.com/bugreport/",
            "sun.io.unicode.encoding": "UnicodeBig",
            "sun.cpu.endian": "little",
            "sun.cpu.isalist": ""
        },
        "systemEnvironment": {
            "PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/bin:/usr/local/mysql/bin:/Users/FlySheep/FlySheep/JavaTools/apache-maven-3.3.9/bin/bin",
            "SHELL": "/bin/zsh",
            "PAGER": "less",
            "LSCOLORS": "Gxfxcxdxbxegedabagacad",
            "OLDPWD": "/Applications/IntelliJ IDEA.app/Contents/bin",
            "USER": "FlySheep",
            "VERSIONER_PYTHON_PREFER_32_BIT": "no",
            "ZSH": "/Users/FlySheep/.oh-my-zsh",
            "TMPDIR": "/var/folders/d6/zn9yrwns46j4pwbl1_mv_6hw0000gn/T/",
            "SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.vZEKsGdZ1T/Listeners",
            "JAVA_MAIN_CLASS_2716": "com.intellij.rt.execution.application.AppMain",
            "XPC_FLAGS": "0x0",
            "VERSIONER_PYTHON_VERSION": "2.7",
            "__CF_USER_TEXT_ENCODING": "0x1F5:0x19:0x34",
            "Apple_PubSub_Socket_Render": "/private/tmp/com.apple.launchd.5VgRuDCQ5D/Render",
            "LOGNAME": "FlySheep",
            "LESS": "-R",
            "LC_CTYPE": "",
            "PWD": "/Users/FlySheep/FlySheep/Code/ServerCode/SpringBoot_Demo/demo",
            "XPC_SERVICE_NAME": "com.jetbrains.intellij.136992",
            "HOME": "/Users/FlySheep"
        },
        "applicationConfig: [classpath:/application.properties]": {
            "management.security.enabled": "false"
        }
    }
    

    基本上,任何能给Spring Boot 应用程序提供属性的属性源都会列在 /env 的结果里,同时会显示具体的属性。
      为了避免敏感信息暴露到 /env 里,所有名为password、secret、key(或者名字中最后一段是这些)的属性在 /env 里都会加上“*”。举个例子,如果有一个属性名字是database.password,那么它在/env中的显示效果是这样的:

    "database.password":"******"
    

    /env 接口还能用来获取单个属性的值,只需要在请求时在 /env 后加上属性名即可。

    1.4 查看属性的使用方法

    /configprops 接口会生成一个报告,说明属性如何进行设置(注入或其他方式)。

    {
        "endpoints-org.springframework.boot.actuate.endpoint.EndpointProperties": {
            "prefix": "endpoints",
            "properties": {
                "enabled": true,
                "sensitive": null
            }
        },
        "management.info-org.springframework.boot.actuate.autoconfigure.InfoContributorProperties": {
            "prefix": "management.info",
            "properties": {
                "git": {
                    "mode": "SIMPLE"
                }
            }
        },
        "metricsEndpoint": {
            "prefix": "endpoints.metrics",
            "properties": {
                "id": "metrics",
                "sensitive": true,
                "enabled": true
            }
        },
        "spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties": {
            "prefix": "spring.jackson",
            "properties": {
                "propertyNamingStrategy": null,
                "defaultPropertyInclusion": null,
                "dateFormat": null,
                "timeZone": null,
                "locale": null,
                "jodaDateTimeFormat": null
            }
        },
        "heapdumpMvcEndpoint": {
            "prefix": "endpoints.heapdump",
            "properties": {
                "path": "/heapdump",
                "sensitive": true,
                "enabled": true
            }
        },
        "endpoints.cors-org.springframework.boot.actuate.autoconfigure.EndpointCorsProperties": {
            "prefix": "endpoints.cors",
            "properties": {
                "allowedOrigins": [],
                "maxAge": 1800,
                "exposedHeaders": [],
                "allowedHeaders": [],
                "allowedMethods": [],
                "allowCredentials": null
            }
        },
        "environmentMvcEndpoint": {
            "prefix": "endpoints.env",
            "properties": {
                "path": "/env"
            }
        },
        "environmentEndpoint": {
            "prefix": "endpoints.env",
            "properties": {
                "id": "env",
                "sensitive": true,
                "enabled": true
            }
        },
        "spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties": {
            "prefix": "spring.http.multipart",
            "properties": {
                "maxRequestSize": "10MB",
                "fileSizeThreshold": "0",
                "location": null,
                "maxFileSize": "1MB",
                "enabled": true,
                "resolveLazily": false
            }
        },
        "spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties": {
            "prefix": "spring.info",
            "properties": {
                "build": {
                    "location": {}
                },
                "git": {
                    "location": {}
                }
            }
        },
        "auditEventsEndpoint": {
            "prefix": "endpoints.auditevents",
            "properties": {
                "enabled": true
            }
        },
        "traceEndpoint": {
            "prefix": "endpoints.trace",
            "properties": {
                "id": "trace",
                "sensitive": true,
                "enabled": true
            }
        },
        "metricsMvcEndpoint": {
            "prefix": "endpoints.metrics",
            "properties": {
                "path": "/metrics"
            }
        },
        "infoEndpoint": {
            "prefix": "endpoints.info",
            "properties": {
                "id": "info",
                "sensitive": false,
                "enabled": true
            }
        },
        "auditEventMvcEndpoint": {
            "prefix": "endpoints.auditevents",
            "properties": {
                "path": "/auditevents",
                "sensitive": true,
                "enabled": true
            }
        },
        "management.trace-org.springframework.boot.actuate.trace.TraceProperties": {
            "prefix": "management.trace",
            "properties": {
                "include": [
                    "COOKIES",
                    "REQUEST_HEADERS",
                    "RESPONSE_HEADERS",
                    "ERRORS"
                ]
            }
        },
        "spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties": {
            "prefix": "spring.resources",
            "properties": {
                "cachePeriod": null,
                "addMappings": true,
                "chain": {
                    "cache": true,
                    "htmlApplicationCache": false,
                    "gzipped": false,
                    "strategy": {
                        "fixed": {
                            "enabled": false,
                            "paths": [
                                "/**"
                            ],
                            "version": null
                        },
                        "content": {
                            "enabled": false,
                            "paths": [
                                "/**"
                            ]
                        }
                    }
                },
                "staticLocations": [
                    "/",
                    "classpath:/META-INF/resources/",
                    "classpath:/resources/",
                    "classpath:/static/",
                    "classpath:/public/"
                ]
            }
        },
        "management.health.status-org.springframework.boot.actuate.autoconfigure.HealthIndicatorProperties": {
            "prefix": "management.health.status",
            "properties": {
                "order": null
            }
        },
        "healthMvcEndpoint": {
            "prefix": "endpoints.health",
            "properties": {
                "path": "/health"
            }
        },
        "serverProperties": {
            "prefix": "server",
            "properties": {
                "address": null,
                "maxHttpPostSize": 0,
                "undertow": {
                    "maxHttpPostSize": 0,
                    "bufferSize": null,
                    "buffersPerRegion": null,
                    "ioThreads": null,
                    "workerThreads": null,
                    "directBuffers": null,
                    "accesslog": {
                        "enabled": null,
                        "pattern": "common",
                        "prefix": "access_log.",
                        "suffix": "log",
                        "dir": "/Users/FlySheep/FlySheep/Code/ServerCode/SpringBoot_Demo/demo/logs",
                        "rotate": true
                    }
                },
                "tomcat": {
                    "accesslog": {
                        "enabled": false,
                        "pattern": "common",
                        "directory": "logs",
                        "prefix": "access_log",
                        "suffix": ".log",
                        "rotate": true,
                        "renameOnRotate": false,
                        "requestAttributesEnabled": false,
                        "buffered": true
                    },
                    "internalProxies": "10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.1[6-9]{1}\.\d{1,3}\.\d{1,3}|172\.2[0-9]{1}\.\d{1,3}\.\d{1,3}|172\.3[0-1]{1}\.\d{1,3}\.\d{1,3}",
                    "protocolHeader": null,
                    "protocolHeaderHttpsValue": "https",
                    "portHeader": "X-Forwarded-Port",
                    "remoteIpHeader": null,
                    "basedir": null,
                    "backgroundProcessorDelay": 30,
                    "maxThreads": 0,
                    "minSpareThreads": 0,
                    "maxHttpPostSize": 0,
                    "redirectContextRoot": null,
                    "uriEncoding": null,
                    "maxConnections": 0,
                    "acceptCount": 0,
                    "additionalTldSkipPatterns": []
                },
                "displayName": "application",
                "session": {
                    "timeout": null,
                    "trackingModes": null,
                    "persistent": false,
                    "storeDir": null,
                    "cookie": {
                        "name": null,
                        "domain": null,
                        "path": null,
                        "comment": null,
                        "httpOnly": null,
                        "secure": null,
                        "maxAge": null
                    }
                },
                "contextPath": null,
                "error": {
                    "path": "/error",
                    "includeStacktrace": "NEVER"
                },
                "ssl": null,
                "serverHeader": null,
                "useForwardHeaders": null,
                "port": null,
                "maxHttpHeaderSize": 0,
                "servletPath": "/",
                "jspServlet": null,
                "jetty": {
                    "maxHttpPostSize": 0,
                    "acceptors": null,
                    "selectors": null
                },
                "connectionTimeout": null
            }
        },
        "spring.metrics.export-org.springframework.boot.actuate.metrics.export.MetricExportProperties": {
            "prefix": "spring.metrics.export",
            "properties": {
                "excludes": null,
                "statsd": {
                    "host": null,
                    "port": 8125,
                    "prefix": null
                },
                "includes": null,
                "enabled": true,
                "redis": {
                    "prefix": "spring.metrics.application.7a5b013db041f4a1b6c45b6456487d05",
                    "key": "******"
                },
                "aggregate": {
                    "prefix": "application.7a5b013db041f4a1b6c45b6456487d05",
                    "keyPattern": "k.d"
                }
            }
        },
        "configurationPropertiesReportEndpoint": {
            "prefix": "endpoints.configprops",
            "properties": {
                "id": "configprops",
                "sensitive": true,
                "enabled": true
            }
        },
        "healthEndpoint": {
            "prefix": "endpoints.health",
            "properties": {
                "timeToLive": 1000,
                "id": "health",
                "sensitive": false,
                "enabled": true
            }
        },
        "loggersMvcEndpoint": {
            "prefix": "endpoints.loggers",
            "properties": {
                "path": "/loggers"
            }
        },
        "loggersEndpoint": {
            "prefix": "endpoints.loggers",
            "properties": {
                "id": "loggers",
                "sensitive": true,
                "enabled": true
            }
        },
        "endpoints.metrics.filter-org.springframework.boot.actuate.autoconfigure.MetricFilterProperties": {
            "prefix": "endpoints.metrics.filter",
            "properties": {
                "counterSubmissions": [
                    "MERGED"
                ],
                "gaugeSubmissions": [
                    "MERGED"
                ]
            }
        },
        "dumpEndpoint": {
            "prefix": "endpoints.dump",
            "properties": {
                "id": "dump",
                "sensitive": true,
                "enabled": true
            }
        },
        "autoConfigurationReportEndpoint": {
            "prefix": "endpoints.autoconfig",
            "properties": {
                "id": "autoconfig",
                "sensitive": true,
                "enabled": true
            }
        },
        "endpoints.jmx-org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportProperties": {
            "prefix": "endpoints.jmx",
            "properties": {
                "uniqueNames": false,
                "enabled": true,
                "domain": ""
            }
        },
        "spring.http.encoding-org.springframework.boot.autoconfigure.web.HttpEncodingProperties": {
            "prefix": "spring.http.encoding",
            "properties": {
                "charset": "UTF-8",
                "force": false,
                "mapping": null,
                "forceRequest": false,
                "forceResponse": false
            }
        },
        "shutdownEndpoint": {
            "prefix": "endpoints.shutdown",
            "properties": {
                "id": "shutdown",
                "sensitive": true,
                "enabled": false
            }
        },
        "beansEndpoint": {
            "prefix": "endpoints.beans",
            "properties": {
                "id": "beans",
                "sensitive": true,
                "enabled": true
            }
        },
        "managementServerProperties": {
            "prefix": "management",
            "properties": {
                "security": {
                    "enabled": false,
                    "roles": [
                        "ACTUATOR"
                    ],
                    "sessions": "STATELESS"
                },
                "address": null,
                "port": null,
                "addApplicationContextHeader": true,
                "contextPath": "",
                "ssl": null
            }
        },
        "requestMappingEndpoint": {
            "prefix": "endpoints.mappings",
            "properties": {
                "id": "mappings",
                "sensitive": true,
                "enabled": true
            }
        },
        "endpoints.health-org.springframework.boot.actuate.autoconfigure.HealthMvcEndpointProperties": {
            "prefix": "endpoints.health",
            "properties": {
                "mapping": {}
            }
        },
        "spring.mvc-org.springframework.boot.autoconfigure.web.WebMvcProperties": {
            "prefix": "spring.mvc",
            "properties": {
                "dateFormat": null,
                "servlet": {
                    "loadOnStartup": -1
                },
                "staticPathPattern": "/**",
                "dispatchOptionsRequest": true,
                "dispatchTraceRequest": false,
                "locale": null,
                "ignoreDefaultModelOnRedirect": true,
                "logResolvedException": false,
                "async": {
                    "requestTimeout": null
                },
                "messageCodesResolverFormat": null,
                "mediaTypes": {},
                "view": {
                    "prefix": null,
                    "suffix": null
                },
                "localeResolver": "ACCEPT_HEADER",
                "throwExceptionIfNoHandlerFound": false
            }
        },
        "diskSpaceHealthIndicatorProperties": {
            "prefix": "management.health.diskspace",
            "properties": {
                "path": "/Users/FlySheep/FlySheep/Code/ServerCode/SpringBoot_Demo/demo/.",
                "threshold": 10485760
            }
        }
    }
    
    1.5 生成接口道控制器的映射

    在应用程序相对较小的时候,很容易搞清楚控制器都映射到了哪些接口上。如果Web界面的控制器和请求处理方法数量多,那最好能有一个列表,罗列出应用程序发布的全部接口。/mappings 接口就提供了这么一个列表。

    {
        "/webjars/**": {
            "bean": "resourceHandlerMapping"
        },
        "/**": {
            "bean": "resourceHandlerMapping"
        },
        "/**/favicon.ico": {
            "bean": "faviconHandlerMapping"
        },
        "{[/error]}": {
            "bean": "requestMappingHandlerMapping",
            "method": "public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)"
        },
        "{[/error],produces=[text/html]}": {
            "bean": "requestMappingHandlerMapping",
            "method": "public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)"
        },
        "{[/env/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)"
        },
        "{[/env || /env.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/beans || /beans.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/auditevents || /auditevents.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public org.springframework.http.ResponseEntity<?> org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint.findByPrincipalAndAfterAndType(java.lang.String,java.util.Date,java.lang.String)"
        },
        "{[/autoconfig || /autoconfig.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/loggers/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint.get(java.lang.String)"
        },
        "{[/loggers/{name:.*}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v1+json || application/json],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint.set(java.lang.String,java.util.Map<java.lang.String, java.lang.String>)"
        },
        "{[/loggers || /loggers.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/heapdump || /heapdump.json],methods=[GET],produces=[application/octet-stream]}": {
            "bean": "endpointHandlerMapping",
            "method": "public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException"
        },
        "{[/mappings || /mappings.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/trace || /trace.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/configprops || /configprops.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/dump || /dump.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/metrics/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)"
        },
        "{[/metrics || /metrics.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        },
        "{[/health || /health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)"
        },
        "{[/info || /info.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}": {
            "bean": "endpointHandlerMapping",
            "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
        }
    }
    

    这里我们可以看到不少接口的映射。每个映射的键都是一个字符串,其内容就是 Spring MVC 的 @RequestMapping 注解上设置的属性。实际上,这个字符串能让你清晰地了解控制器是如何映射的,哪怕不看源代码。每个映射的值都有两个属性:bean 和 method。bean 属性标识了 Spring Bean 的名字,映射源自这个Bean。method属性是映射对应方法的全限定方法签名。

    2. 运行时指标

    对运行时指标情况做一个快照,这对评估应用程序的健康情况很有帮助。Actuator 提供了一系列接口,让你能在运行时快速检查应用程序。

    2.1 查看应用程序的指标值

    关于运行中的应用程序,有很多有趣而且有用的信息。举个例子,了解应用程序的内存情况 (可用或空闲)有助于决定给JVM分配多少内存。对Web应用程序而言,不用查看Web服务器日志,如果请求失败或者是耗时太长,就可以大概知道内存的情况了。运行中的应用程序有诸多计数器和度量器,/metrics 接口提供了这些东西的快照。

    {
        "mem": 365004,
        "mem.free": 153938,
        "processors": 8,
        "instance.uptime": 852279,
        "uptime": 855002,
        "systemload.average": 3.509765625,
        "heap.committed": 316928,
        "heap.init": 262144,
        "heap.used": 162989,
        "heap": 3728384,
        "nonheap.committed": 50816,
        "nonheap.init": 2496,
        "nonheap.used": 48077,
        "nonheap": 0,
        "threads.peak": 18,
        "threads.daemon": 16,
        "threads.totalStarted": 23,
        "threads": 18,
        "classes": 5974,
        "classes.loaded": 5974,
        "classes.unloaded": 0,
        "gc.ps_scavenge.count": 4,
        "gc.ps_scavenge.time": 35,
        "gc.ps_marksweep.count": 1,
        "gc.ps_marksweep.time": 27,
        "httpsessions.max": -1,
        "httpsessions.active": 0,
        "gauge.response.mappings": 4,
        "gauge.response.configprops": 155,
        "counter.status.200.mappings": 1,
        "counter.status.200.configprops": 1
    }
    

    对 /metrics 接口提供的信息进行简单分类如下表:

    分类前缀报告内容
    垃圾收集器 gc.* 已经发生过的垃圾收集次数,以及垃圾收集所耗费的时间,适用于标记-清理垃圾收集器和并行垃圾收集器(数据源自java.lang.management. GarbageCollectorMXBean)
    内存 mem.* 分配给应用程序的内存数量和空闲的内存数量(数据源自java.lang. Runtime)
    heap.* 当前内存用量(数据源自java.lang.management.MemoryUsage)
    类加载器 classes.* JVM类加载器加载与卸载的类的数量(数据源自java.lang. management.ClassLoadingMXBean)
    系统 processors、instance.uptime、uptime、systemload.average 系统信息,例如处理器数量(数据源自java.lang.Runtime)、运行时间(数据源自java.lang.management.RuntimeMXBean)、平均负载(数据源自java.lang.management.OperatingSystemMXBean)
    线程池 thread.* 线程、守护线程的数量,以及JVM启动后的线程数量峰值(数据源自 java.lang .management.ThreadMXBean)
    数据源 datasource.* 数据源连接的数量(源自数据源的元数据,仅当Spring应用程序上下文里存在 DataSource Bean 的时候才会有这个信息)
    Tomcat 会话 httpsessions.* Tomcat的活跃会话数和最大会话数(数据源自嵌入式Tomcat的Bean,仅在使用嵌入式Tomcat服务器运行应用程序时才有这个信息)
    HTTP counter.status.、gauge.response. 多种应用程序服务HTTP请求的度量值与计数器

    请注意,这里的一些度量值,比如数据源和Tomcat会话,仅在应用程序中运行特定组件时才有数据。你还可以注册自己的度量信息。
      HTTP的计数器和度量值需要做一点说明。counter.status 后的值是HTTP状态码,随后是所请求的路径。举个例子,counter.status.200.metrics 表明/metrics端点返回 200(OK) 状态码的次数。
      HTTP的度量信息在结构上也差不多,却在报告另一类信息。它们全部以gauge.response 开头,,表明这是HTTP响应的度量信息。前缀后是对应的路径。度量值是以毫秒为单位的时间,反映了最近处理该路径请求的耗时。
      这里还有几个特殊的值需要注意。root路径指向的是根路径或/。star-star代表了那些Spring 认为是静态资源的路径,包括图片、JavaScript和样式表,其中还包含了那些找不到的资源。这就是为什么你经常会看到 counter.status.404.star-star,这是返回了HTTP 404 (NOT FOUND) 状态的请求数。  
      /metrics 接口会返回所有的可用度量值,但你也可能只对某个值感兴趣。要获取单个值,请求时可以在URL后加上对应的键名。例如,要查看空闲内存大小,可以向/metrics/mem.free发一 个GET请求。

    2.2 追踪 Web 请求

    /trace 接口能报告所有Web请求的详细信息,包括请求方法、路径、时间戳以及请求和响应的头信息。

    [
        {
            "timestamp": 1491279254447,
            "info": {
                "method": "GET",
                "path": "/metrics",
                "headers": {
                    "request": {
                        "host": "localhost:8080",
                        "connection": "keep-alive",
                        "upgrade-insecure-requests": "1",
                        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
                        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
                        "accept-encoding": "gzip, deflate, sdch, br",
                        "accept-language": "zh-CN,zh;q=0.8,en;q=0.6",
                        "cookie": "JSESSIONID=24CCB83195B2A35F5193C97D2CD51D69"
                    },
                    "response": {
                        "X-Application-Context": "application",
                        "Content-Type": "application/vnd.spring-boot.actuator.v1+json;charset=UTF-8",
                        "Transfer-Encoding": "chunked",
                        "Date": "Tue, 04 Apr 2017 04:14:14 GMT",
                        "status": "200"
                    }
                }
            }
        }
    ]
    
    2.3 导出线程活动

    在确认应用程序运行情况时,除了跟踪请求,了解线程活动也会很有帮助。/dump 接口会生成当前线程活动的快照。

    2.4 监控应用程序健康状况

    如果你想知道自己的应用程序是否在运行,可以直接访问/health 接口。在最简单的情况下,该端点会显示一个简单的JSON,内容如下:

    {
        "status": "UP",
        "diskSpace": {
            "status": "UP",
            "total": 48978722816,
            "free": 8812167168,
            "threshold": 10485760
        }
    }
    

    二、定制 Actuator

    虽然Actuator提供了很多运行中Spring Boot应用程序的内部工作细节,但难免和你的需求有所偏差。也许你并不需要它提供的所有功能,想要关闭一些也说不定。或者,你需要对Actuator 稍作扩展,增加一些自定义的度量信息,以满足你对应用程序的需求。

    1. 修改接口 ID

    每个Actuator 接口都有一个ID用来决定接口的路径,比方说,/beans接口的默认ID就是beans。比如要修改 /beans 为 /instances,则设置如下:

    endpoints.beans.id = instances
    
    2. 启用和禁用接口

    虽然Actuator的接口都很有用,但你不一定需要全部这些接口。默认情况下,所有接口(除 了/shutdown)都启用。比如要禁用 /metrics 接口,则可以设置如下:

    endpoints.metrics.enabled = false
    

    如果你只想打开一两个接口,那就先禁用全部接口,然后启用那几个你要的,这样更方便。

    endpoints.enabled = false
    endpoints.metrics.enabled = true
    

    3. 添加自定义度量信息

    Actuator 自动配置有两个实例 CounterService 和 GaugeService 可以用来计数使用,我们所要做的就是把它们的实例注入所需的 bean 然后调用相应的方法。除此之外,我们还可以实现 PublicMetrics 接口,提供自己需要的度量信息。

    4. 创建自定义跟踪仓库

    默认情况下,/trace 接口报告的跟踪信息都存储在内存仓库里,100个条目封顶。一旦仓库满了,就开始移除老的条目,给新的条目腾出空间。在开发阶段这没什么问题,但在生产环境中,大流量会造成跟踪信息还没来得及看就被丢弃。我们可以将那些跟踪条目存储在其他地方——既不消耗内存,又能长久保存的地方。只需实现Spring Boot的TraceRepository接口即可。

    5. 插入自定义的健康指示器

    实现 HealthIndicator 接口则可以实现自定义的健康指示器。

    6. 保护 Actuator 接口

    很多Actuator端点发布的信息都可能涉及敏感数据,还有一些端点,(比如/shutdown)非常危险,可以用来关闭应用程序。因此,保护这些端点尤为重要,能访问它们的只能是那些经过授权的客户端。

  • 相关阅读:
    智器SmartQ T7实体店试用体验
    BI笔记之SSAS库Process的几种方案
    PowerTip of the Day from powershell.com上周汇总(八)
    PowerTip of the Day2010071420100716 summary
    PowerTip of the Day from powershell.com上周汇总(十)
    PowerTip of the Day from powershell.com上周汇总(六)
    重新整理Cellset转Datatable
    自动加密web.config配置节批处理
    与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable
    在VS2003中以ClassLibrary工程的方式管理Web工程.
  • 原文地址:https://www.cnblogs.com/zp-uestc/p/10360959.html
Copyright © 2011-2022 走看看