Spring Boot Actuator监控端点小结

在Spring Boot的众多Starter POMs中有一个特殊的模块,它不同于其他模块那样大多用于开发业务功能或是连接一些其他外部资源。它完全是一个用于暴露自身信息的模块,所以很明显,它的主要作用是用于监控与管理,它就是:spring-boot-starter-actuator

spring-boot-starter-actuator模块的实现对于实施微服务的中小团队来说,可以有效地减少监控系统在采集应用指标时的开发量。当然,它也并不是万能的,有时候我们也需要对其做一些简单的扩展来帮助我们实现自身系统个性化的监控需求。下面,在本文中,我们将详解的介绍一些关于spring-boot-starter-actuator模块的内容,包括它的原生提供的端点以及一些常用的扩展和配置方式。

初识Actuator

下面,我们可以通过对快速入门中实现的Spring Boot应用增加spring-boot-starter-actuator模块功能,来对它有一个直观的认识。

在现有的Spring Boot应用中引入该模块非常简单,只需要在pom.xmldependencies节点中,新增spring-boot-starter-actuator的依赖即可,具体如下:

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

通过增加该依赖之后,重新启动应用。此时,我们可以在控制台中看到如下图所示的输出:

上图显示了一批端点定义,这些端点并非我们自己在程序中创建,而是由spring-boot-starter-actuator模块根据应用依赖和配置自动创建出来的监控和管理端点。通过这些端点,我们可以实时的获取应用的各项监控指标,比如:访问/health端点,我们可以获得如下返回的应用健康信息:

{
"status": "UP",
"diskSpace": {
"status": "UP",
"total": 491270434816,
"free": 383870214144,
"threshold": 10485760
}
}

原生端点

通过在快速入门示例中添加spring-boot-starter-actuator模块,我们已经对它有了一个初步的认识。接下来,我们详细介绍一下spring-boot-starter-actuator模块中已经实现的一些原生端点。如果根据端点的作用来说,我们可以原生端点分为三大类:

  • 应用配置类:获取应用程序中加载的应用配置、环境变量、自动化配置报告等与Spring Boot应用密切相关的配置类信息。
  • 度量指标类:获取应用程序运行过程中用于监控的度量指标,比如:内存信息、线程池信息、HTTP请求统计等。
  • 操作控制类:提供了对应用的关闭等操作类功能。

下面我们来详细了解一下这三类端点都分别可以为我们提供怎么样的有用信息和强大功能,以及我们如何去扩展和配置它们。

应用配置类

由于Spring Boot为了改善传统Spring应用繁杂的配置内容,采用了包扫描和自动化配置的机制来加载原本集中于xml文件中的各项内容。虽然这样的做法,让我们的代码变得非常简洁,但是整个应用的实例创建和依赖关系等信息都被离散到了各个配置类的注解上,这使得我们分析整个应用中资源和实例的各种关系变得非常的困难。而这类端点就可以帮助我们轻松的获取一系列关于Spring 应用配置内容的详细报告,比如:自动化配置的报告、Bean创建的报告、环境属性的报告等。

  • /autoconfig:该端点用来获取应用的自动化配置报告,其中包括所有自动化配置的候选项。同时还列出了每个候选项自动化配置的各个先决条件是否满足。所以,该端点可以帮助我们方便的找到一些自动化配置为什么没有生效的具体原因。该报告内容将自动化配置内容分为两部分:

    • positiveMatches中返回的是条件匹配成功的自动化配置
    • negativeMatches中返回的是条件匹配不成功的自动化配置
    {
    "positiveMatches": { // 条件匹配成功的
    "EndpointWebMvcAutoConfiguration": [
    {
    "condition": "OnClassCondition",
    "message": "@ConditionalOnClass classes found: javax.servlet.Servlet,org.springframework.web.servlet.DispatcherServlet"
    },
    {
    "condition": "OnWebApplicationCondition",
    "message": "found web application StandardServletEnvironment"
    }
    ],
    ...
    },
    "negativeMatches": { // 条件不匹配成功的
    "HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration": [
    {
    "condition": "OnClassCondition",
    "message": "required @ConditionalOnClass classes not found: org.springframework.jdbc.core.JdbcTemplate"
    }
    ],
    ...
    }
    }

从如上示例中我们可以看到,每个自动化配置候选项中都有一系列的条件,比如上面没有成功匹配的HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration配置,它的先决条件就是需要在工程中包含org.springframework.jdbc.core.JdbcTemplate类,由于我们没有引入相关的依赖,它就不会执行自动化配置内容。所以,当我们发现有一些期望的配置没有生效时,就可以通过该端点来查看没有生效的具体原因。

  • /beans:该端点用来获取应用上下文中创建的所有Bean。

    [
    {
    "context": "hello:dev:8881",
    "parent": null,
    "beans": [
    {
    "bean": "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration",
    "scope": "singleton",
    "type": "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration$$EnhancerBySpringCGLIB$$3440282b",
    "resource": "null",
    "dependencies": [
    "serverProperties",
    "spring.mvc.CONFIGURATION_PROPERTIES",
    "multipartConfigElement"
    ]
    },
    {
    "bean": "dispatcherServlet",
    "scope": "singleton",
    "type": "org.springframework.web.servlet.DispatcherServlet",
    "resource": "class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletConfiguration.class]",
    "dependencies": []
    }
    ]
    }
    ]

    如上示例中,我们可以看到在每个bean中都包含了下面这几个信息:

    • bean:Bean的名称
    • scope:Bean的作用域
    • type:Bean的Java类型
    • reource:class文件的具体路径
    • dependencies:依赖的Bean名称
  • /configprops:该端点用来获取应用中配置的属性信息报告。从下面该端点返回示例的片段中,我们看到返回了关于该短信的配置信息,prefix属性代表了属性的配置前缀,properties代表了各个属性的名称和值。所以,我们可以通过该报告来看到各个属性的配置路径,比如我们要关闭该端点,就可以通过使用endpoints.configprops.enabled=false来完成设置。

    {
    "configurationPropertiesReportEndpoint": {
    "prefix": "endpoints.configprops",
    "properties": {
    "id": "configprops",
    "sensitive": true,
    "enabled": true
    }
    },
    ...
    }
  • /env:该端点与/configprops不同,它用来获取应用所有可用的环境属性报告。包括:环境变量、JVM属性、应用的配置配置、命令行中的参数。从下面该端点返回的示例片段中,我们可以看到它不仅返回了应用的配置属性,还返回了系统属性、环境变量等丰富的配置信息,其中也包括了应用还没有没有使用的配置。所以它可以帮助我们方便地看到当前应用可以加载的配置信息,并配合@ConfigurationProperties注解将它们引入到我们的应用程序中来进行使用。另外,为了配置属性的安全,对于一些类似密码等敏感信息,该端点都会进行隐私保护,但是我们需要让属性名中包含:password、secret、key这些关键词,这样该端点在返回它们的时候会使用*来替代实际的属性值。

    {
    "profiles": [
    "dev"
    ],
    "server.ports": {
    "local.server.port": 8881
    },
    "servletContextInitParams": {

    },
    "systemProperties": {
    "idea.version": "2016.1.3",
    "java.runtime.name": "Java(TM) SE Runtime Environment",
    "sun.boot.library.path": "C:\\Program Files\\Java\\jdk1.8.0_91\\jre\\bin",
    "java.vm.version": "25.91-b15",
    "java.vm.vendor": "Oracle Corporation",
    ...
    },
    "systemEnvironment": {
    "configsetroot": "C:\\WINDOWS\\ConfigSetRoot",
    "RABBITMQ_BASE": "E:\\tools\\rabbitmq",
    ...
    },
    "applicationConfig: [classpath:/application-dev.properties]": {
    "server.port": "8881"
    },
    "applicationConfig: [classpath:/application.properties]": {
    "server.port": "8885",
    "spring.profiles.active": "dev",
    "info.app.name": "spring-boot-hello",
    "info.app.version": "v1.0.0",
    "spring.application.name": "hello"
    }
    }
  • /mappings:该端点用来返回所有Spring MVC的控制器映射关系报告。从下面的示例片段中,我们可以看该报告的信息与我们在启用Spring MVC的Web应用时输出的日志信息类似,其中bean属性标识了该映射关系的请求处理器,method属性标识了该映射关系的具体处理类和处理函数。

    {
    "/webjars/**": {
    "bean": "resourceHandlerMapping"
    },
    "/**": {
    "bean": "resourceHandlerMapping"
    },
    "/**/favicon.ico": {
    "bean": "faviconHandlerMapping"
    },
    "{[/hello]}": {
    "bean": "requestMappingHandlerMapping",
    "method": "public java.lang.String com.didispace.web.HelloController.index()"
    },
    "{[/mappings || /mappings.json],methods=[GET],produces=[application/json]}": {
    "bean": "endpointHandlerMapping",
    "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
    },
    ...
    }
  • /info:该端点用来返回一些应用自定义的信息。默认情况下,该端点只会返回一个空的json内容。我们可以在application.properties配置文件中通过info前缀来设置一些属性,比如下面这样:

    info.app.name=spring-boot-hello
    info.app.version=v1.0.0

    再访问/info端点,我们可以得到下面的返回报告,其中就包含了上面我们在应用自定义的两个参数。

    {
    "app": {
    "name": "spring-boot-hello",
    "version": "v1.0.0"
    }
    }

度量指标类

上面我们所介绍的应用配置类端点所提供的信息报告在应用启动的时候都已经基本确定了其返回内容,可以说是一个静态报告。而度量指标类端点提供的报告内容则是动态变化的,这些端点提供了应用程序在运行过程中的一些快照信息,比如:内存使用情况、HTTP请求统计、外部资源指标等。这些端点对于我们构建微服务架构中的监控系统非常有帮助,由于Spring Boot应用自身实现了这些端点,所以我们可以很方便地利用它们来收集我们想要的信息,以制定出各种自动化策略。下面,我们就来分别看看这些强大的端点功能。

  • /metrics:该端点用来返回当前应用的各类重要度量指标,比如:内存信息、线程信息、垃圾回收信息等。

    {
    "mem": 541305,
    "mem.free": 317864,
    "processors": 8,
    "instance.uptime": 33376471,
    "uptime": 33385352,
    "systemload.average": -1,
    "heap.committed": 476672,
    "heap.init": 262144,
    "heap.used": 158807,
    "heap": 3701248,
    "nonheap.committed": 65856,
    "nonheap.init": 2496,
    "nonheap.used": 64633,
    "nonheap": 0,
    "threads.peak": 22,
    "threads.daemon": 20,
    "threads.totalStarted": 26,
    "threads": 22,
    "classes": 7669,
    "classes.loaded": 7669,
    "classes.unloaded": 0,
    "gc.ps_scavenge.count": 7,
    "gc.ps_scavenge.time": 118,
    "gc.ps_marksweep.count": 2,
    "gc.ps_marksweep.time": 234,
    "httpsessions.max": -1,
    "httpsessions.active": 0,
    "gauge.response.beans": 55,
    "gauge.response.env": 10,
    "gauge.response.hello": 5,
    "gauge.response.metrics": 4,
    "gauge.response.configprops": 153,
    "gauge.response.star-star": 5,
    "counter.status.200.beans": 1,
    "counter.status.200.metrics": 3,
    "counter.status.200.configprops": 1,
    "counter.status.404.star-star": 2,
    "counter.status.200.hello": 11,
    "counter.status.200.env": 1
    }

    从上面的示例中,我们看到有这些重要的度量值:

    • 系统信息:包括处理器数量processors、运行时间uptimeinstance.uptime、系统平均负载systemload.average
    • mem.*:内存概要信息,包括分配给应用的总内存数量以及当前空闲的内存数量。这些信息来自java.lang.Runtime
    • heap.*:堆内存使用情况。这些信息来自java.lang.management.MemoryMXBean接口中getHeapMemoryUsage方法获取的java.lang.management.MemoryUsage
    • nonheap.*:非堆内存使用情况。这些信息来自java.lang.management.MemoryMXBean接口中getNonHeapMemoryUsage方法获取的java.lang.management.MemoryUsage
    • threads.*:线程使用情况,包括线程数、守护线程数(daemon)、线程峰值(peak)等,这些数据均来自java.lang.management.ThreadMXBean
    • classes.*:应用加载和卸载的类统计。这些数据均来自java.lang.management.ClassLoadingMXBean
    • gc.*:垃圾收集器的详细信息,包括垃圾回收次数gc.ps_scavenge.count、垃圾回收消耗时间gc.ps_scavenge.time、标记-清除算法的次数gc.ps_marksweep.count、标记-清除算法的消耗时间gc.ps_marksweep.time。这些数据均来自java.lang.management.GarbageCollectorMXBean
    • httpsessions.*:Tomcat容器的会话使用情况。包括最大会话数httpsessions.max和活跃会话数httpsessions.active。该度量指标信息仅在引入了嵌入式Tomcat作为应用容器的时候才会提供。
    • gauge.*:HTTP请求的性能指标之一,它主要用来反映一个绝对数值。比如上面示例中的gauge.response.hello: 5,它表示上一次hello请求的延迟时间为5毫秒。
    • counter.*:HTTP请求的性能指标之一,它主要作为计数器来使用,记录了增加量和减少量。如上示例中counter.status.200.hello: 11,它代表了hello请求返回200状态的次数为11。

    对于gauge.*counter.*的统计,这里有一个特殊的内容请求star-star,它代表了对静态资源的访问。这两类度量指标非常有用,我们不仅可以使用它默认的统计指标,还可以在程序中轻松的增加自定义统计值。只需要通过注入org.springframework.boot.actuate.metrics.CounterServiceorg.springframework.boot.actuate.metrics.GaugeService来实现自定义的统计指标信息。比如:我们可以像下面这样自定义实现对hello接口的访问次数统计。

    @RestController
    public class HelloController {

    @Autowired
    private CounterService counterService;

    @RequestMapping("/hello")
    public String greet() {
    counterService.increment("didispace.hello.count");
    return "";
    }

    }

    /metrics端点可以提供应用运行状态的完整度量指标报告,这项功能非常的实用,但是对于监控系统中的各项监控功能,它们的监控内容、数据收集频率都有所不同,如果我们每次都通过全量获取报告的方式来收集,略显粗暴。所以,我们还可以通过/metrics/{name}接口来更细粒度的获取度量信息,比如我们可以通过访问/metrics/mem.free来获取当前可用内存数量。

  • /health:该端点在一开始的示例中我们已经使用过了,它用来获取应用的各类健康指标信息。在spring-boot-starter-actuator模块中自带实现了一些常用资源的健康指标检测器。这些检测器都通过HealthIndicator接口实现,并且会根据依赖关系的引入实现自动化装配,比如用于检测磁盘的DiskSpaceHealthIndicator、检测DataSource连接是否可用的DataSourceHealthIndicator等。有时候,我们可能还会用到一些Spring Boot的Starter POMs中还没有封装的产品来进行开发,比如:当使用RocketMQ作为消息代理时,由于没有自动化配置的检测器,所以我们需要自己来实现一个用来采集健康信息的检测器。比如,我们可以在Spring Boot的应用中,为org.springframework.boot.actuate.health.HealthIndicator接口实现一个对RocketMQ的检测器类:

    @Component
    public class RocketMQHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
    int errorCode = check();
    if (errorCode != 0) {
    return Health.down().withDetail("Error Code", errorCode).build();
    }
    return Health.up().build();
    }

    private int check() {
    // 对监控对象的检测操作
    }
    }

    通过重写health()函数来实现健康检查,返回的Heath对象中,共有两项内容,一个是状态信息,除了该示例中的UPDOWN之外,还有UNKNOWNOUT_OF_SERVICE,可以根据需要来实现返回;还有一个详细信息,采用Map的方式存储,在这里通过withDetail函数,注入了一个Error Code信息,我们也可以填入一下其他信息,比如,检测对象的IP地址、端口等。重新启动应用,并访问/health接口,我们在返回的JSON字符串中,将会包含了如下信息:

    "rocketMQ": {
    "status": "UP"
    }
  • /dump:该端点用来暴露程序运行中的线程信息。它使用java.lang.management.ThreadMXBeandumpAllThreads方法来返回所有含有同步信息的活动线程详情。

  • /trace:该端点用来返回基本的HTTP跟踪信息。默认情况下,跟踪信息的存储采用org.springframework.boot.actuate.trace.InMemoryTraceRepository实现的内存方式,始终保留最近的100条请求记录。它记录的内容格式如下:

    [
    {
    "timestamp": 1482570022463,
    "info": {
    "method": "GET",
    "path": "/metrics/mem",
    "headers": {
    "request": {
    "host": "localhost:8881",
    "connection": "keep-alive",
    "cache-control": "no-cache",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
    "postman-token": "9817ea4d-ad9d-b2fc-7685-9dff1a1bc193",
    "accept": "*/*",
    "accept-encoding": "gzip, deflate, sdch",
    "accept-language": "zh-CN,zh;q=0.8"
    },
    "response": {
    "X-Application-Context": "hello:dev:8881",
    "Content-Type": "application/json;charset=UTF-8",
    "Transfer-Encoding": "chunked",
    "Date": "Sat, 24 Dec 2016 09:00:22 GMT",
    "status": "200"
    }
    }
    }
    },
    ...
    ]

操作控制类

仔细的读者可能会发现,我们在“初识Actuator”时运行示例的控制台中输出的所有监控端点,已经在介绍应用配置类端点和度量指标类端点时都讲解完了。那么还有哪些是操作控制类端点呢?实际上,由于之前介绍的所有端点都是用来反映应用自身的属性或是运行中的状态,相对于操作控制类端点没有那么敏感,所以他们默认都是启用的。而操作控制类端点拥有更强大的控制能力,如果要使用它们的话,需要通过属性来配置开启。

在原生端点中,只提供了一个用来关闭应用的端点:/shutdown。我们可以通过如下配置开启它:

endpoints.shutdown.enabled=true

在配置了上述属性之后,只需要访问该应用的/shutdown端点就能实现关闭该应用的远程操作。由于开放关闭应用的操作本身是一件非常危险的事,所以真正在线上使用的时候,我们需要对其加入一定的保护机制,比如:定制Actuator的端点路径、整合Spring Security进行安全校验等。


money.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/477264.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

剑指Offer - 面试题60. n个骰子的点数(动态规划)

1. 题目 把n个骰子扔在地上&#xff0c;所有骰子朝上一面的点数之和为s。输入n&#xff0c;打印出s的所有可能的值出现的概率。 你需要用一个浮点数数组返回答案&#xff0c;其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。 示例 1: 输入: 1 输出…

经典著作《动手学深度学习》中文版2.0beta版发布!开源下载!

2020年疫情刚开始的时候&#xff0c;《动手学深度学习》的英文版相较中文版已经多出不少内容了。我们书第一版的不少老读者表示&#xff0c;疫情在家虽然想学习&#xff0c;但第一版早就刷完&#xff0c;于是只好刷阿信和小抖。沐神和我的第一反应是&#xff1a;这样对眼睛不好…

使用Spring StateMachine框架实现状态机

Spring StateMachine框架可能对于大部分使用Spring的开发者来说还比较生僻&#xff0c;该框架目前差不多也才刚满一岁多。它的主要功能是帮助开发者简化状态机的开发过程&#xff0c;让状态机结构更加层次化。前几天刚刚发布了它的第三个Release版本1.2.0&#xff0c;其中增加了…

滴滴退市了

文 | 彭小伟, 编 | 刘芳源 | 网约车焦点美东时间6月10日&#xff0c;滴滴正式在纽交所退市。根据官方通告&#xff0c;滴滴在完成退市后&#xff0c;其股份会转移到OTC&#xff08;Over-the-Counter&#xff0c;场外交易市场&#xff09;进行交易&#xff0c;交易代码为“DIDIY…

剑指Offer - 面试题62. 圆圈中最后剩下的数字(约瑟夫环 递推公式)

1. 题目 0,1,…,n-1这n个数字排成一个圆圈&#xff0c;从数字0开始&#xff0c;每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。 例如&#xff0c;0、1、2、3、4这5个数字组成一个圆圈&#xff0c;从数字0开始每次删除第3个数字&#xff0c;则删除的前4个…

Spring Boot中使用MyBatis注解配置详解

之前在Spring Boot中整合MyBatis时&#xff0c;采用了注解的配置方式&#xff0c;相信很多人还是比较喜欢这种优雅的方式的&#xff0c;也收到不少读者朋友的反馈和问题&#xff0c;主要集中于针对各种场景下注解如何使用&#xff0c;下面就对几种常见的情况举例说明用法。 在…

何恺明团队的“视频版本MAE”,高效视频预训练!Mask Ratio高达90%时效果也很好!...

文 | 小马源 | 我爱计算机视觉本篇文章分享论文『Masked Autoencoders As Spatiotemporal Learners』&#xff0c;由何恺明团队提出视频版本的 MAE&#xff0c;进行高效视频预训练&#xff01;Mask Ratio 高达 90% 时效果很好&#xff01;详细信息如下&#xff1a;论文链接&…

剑指Offer - 面试题45. 把数组排成最小的数(字符串排序)

1. 题目 输入一个正整数数组&#xff0c;把数组里所有数字拼接起来排成一个数&#xff0c;打印能拼接出的所有数字中最小的一个。 示例 1: 输入: [10,2] 输出: "102"示例 2: 输入: [3,30,34,5,9] 输出: "3033459"提示: 0 < nums.length < 100 说明…

Spring Boot整合MyBatis

最近项目原因可能会继续开始使用MyBatis&#xff0c;已经习惯于spring-data的风格&#xff0c;再回头看xml的映射配置总觉得不是特别舒服&#xff0c;接口定义与映射离散在不同文件中&#xff0c;使得阅读起来并不是特别方便。 Spring中整合MyBatis就不多说了&#xff0c;最近…

谷歌放弃Tensorflow,全面拥抱JAX

文 | Matthew Lynley源 | 机器之心编辑部TensorFlow 大概已经成为了谷歌的一枚「弃子」。2015 年&#xff0c;谷歌大脑开放了一个名为「TensorFlow」的研究项目&#xff0c;这款产品迅速流行起来&#xff0c;成为人工智能业界的主流深度学习框架&#xff0c;塑造了现代机器学习…

LeetCode 第 20 场双周赛(294 / 1541,前19.07%,第1次全部通过)

文章目录1. 比赛结果2. 题目LeetCode 5323. 根据数字二进制下 1 的数目排序 easyLeetCode 5324. 每隔 n 个顾客打折 mediumLeetCode 5325. 包含所有三种字符的子字符串数目 mediumLeetCode 5326. 有效的快递序列数目 hard1. 比赛结果 第一次全部做出来了&#xff0c;提前6分钟…

Spring Boot中的缓存支持(二)使用Redis做集中式缓存

上一篇介绍了在Spring Boot中如何引入缓存、缓存注解的使用、以及EhCache的整合。 虽然EhCache已经能够适用很多应用场景&#xff0c;但是由于EhCache是进程内的缓存框架&#xff0c;在集群模式下时&#xff0c;各应用服务器之间的缓存都是独立的&#xff0c;因此在不同服务器…

NLP开源数据集汇总

源 | 极市平台本文汇总了几个NLP相关的开源数据集&#xff0c;均附有下载链接。CASIA手写数据集数据集地址&#xff1a;http://m6z.cn/6pFPtCCASIA-HWDB-T&#xff1a;一个从中文手写数据库CASIA-HWDB收集的触摸字符数据库。所有接触的字符&#xff08;或字符串&#xff09;都用…

LeetCode 1360. 日期之间隔几天(闰年判断)

1. 题目 请你编写一个程序来计算两个日期之间隔了多少天。 日期以字符串形式给出&#xff0c;格式为 YYYY-MM-DD&#xff0c;如示例所示。 示例 1&#xff1a; 输入&#xff1a;date1 "2019-06-29", date2 "2019-06-30" 输出&#xff1a;1示例 2&…

“我要做小小瑶大人的狗!”

小轶&#xff1a;这真的是白鹡鸰写的作为21世纪新时代人格健全&#xff0c;精神独立&#xff0c;心理健康的有志青年&#xff0c;总有那么几个时刻&#xff0c;会让我们情不自禁&#xff0c;眼泪从嘴角流下地呐喊着&#xff1a;“我是XXX的狗&#xff01;”啊&#xff01;这诚恳…

Spring Boot中的缓存支持(一)注解配置与EhCache使用

随着时间的积累&#xff0c;应用的使用用户不断增加&#xff0c;数据规模也越来越大&#xff0c;往往数据库查询操作会成为影响用户使用体验的瓶颈&#xff0c;此时使用缓存往往是解决这一问题非常好的手段之一。Spring 3开始提供了强大的基于注解的缓存支持&#xff0c;可以通…

LeetCode 1361. 验证二叉树(图的出入度)

1. 题目 二叉树上有 n 个节点&#xff0c;按从 0 到 n-1 编号&#xff0c;其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]。 只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时&#xff0c;返回 true&#xff1b;否则返回 false。 如果节点 i 没有左子节…

微软:我已把显存优化做到了极致,还有谁?

文 | 王思若大家好&#xff0c;我是王思若。17年6月Google提出了Transformer架构&#xff0c;这篇目前Citation 4.3万的文章开启了大规模预训练模型时代。或者&#xff0c;更精确的从18年OpenAI和Google分别基于其中的Decoder和Encoder发布的大规模预训练模型GPT1和BERT开始&am…

Spring Boot中使用JavaMailSender发送邮件

相信使用过Spring的众多开发者都知道Spring提供了非常好用的JavaMailSender接口实现邮件发送。在Spring Boot的Starter模块中也为此提供了自动化配置。下面通过实例看看如何在Spring Boot中使用JavaMailSender发送邮件。 快速入门 在Spring Boot的工程中的pom.xml中引入sprin…

LeetCode 1362. 最接近的因数

1. 题目 给你一个整数 num&#xff0c;请你找出同时满足下面全部要求的两个整数&#xff1a; 两数乘积等于 num 1 或 num 2以绝对差进行度量&#xff0c;两数大小最接近 你可以按任意顺序返回这两个整数。 示例 1&#xff1a; 输入&#xff1a;num 8 输出&#xff1a;[3…