第11章 Spring Boot应用监控

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介: 第11章 Spring Boot应用监控在实际的生产系统中,我们怎样知道我们的应用运行良好呢?我们往往需要对系统实际运行的情况(各种cpu,io,disk,db,业务功能等指标)进行监控运维。

第11章 Spring Boot应用监控

在实际的生产系统中,我们怎样知道我们的应用运行良好呢?我们往往需要对系统实际运行的情况(各种cpu,io,disk,db,业务功能等指标)进行监控运维。这需要耗费我们不少精力来搞这些工作。在SpringBoot中,我们完全不需要面对这样的难题。

本章主要介绍使用Actuator对Spring Boot应用指标进行监控,以及通过远程shell监控与管理我们的应用。

11.0 Actuator简介

Actuator是spring boot提供的对应用系统的自省和监控功能,Actuator对应用系统本身的自省功能,可以让我们方便快捷的实现线上运维监控的工作。这个有点DevOps的味道。

通过Actuator,我们可以使用数据化的指标去度量我们的应用的运行情况。比如查看系统运行了多少线程,gc的情况,运行的基本参数等等

spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等拉管理和监控应用。

随着devops的兴起,以及docker技术的普及,微服务在一定场合会越来越受欢迎。即使不说微服务,springboot这种可以直接内嵌web服务器打成一个jar包的方式,也更符合devops的趋势:打成个jar包,往服务器上一扔,十分方便,自带Actuator,把监控也给省了一大半,真正做到了可以把精力花在刀刃上。

11.1 使用Spring Boot Actuator监控应用

1.使用actuator

添加starter依赖

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

重启应用。Spring Boot Actuator 的自动配置功能,会把Actuator的审计(Auditing)信息、健康(health)信息、各种度量数据采集(metrics gathering)会自动加到应用里面。

Actuator主要暴露的功能如下:

HTTP方法 路径 描述 是否敏感信息
GET /autoconfig 查看自动配置的使用情况, 显示一个auto-configuration的报告,该报告展示所有auto-configuration候选者及它们被应用或未被应用的原因 true
GET /configprops 查看配置属性,包括默认配置, 显示一个所有@ConfigurationProperties的整理列表 true
GET /beans bean及其关系列表, 显示一个应用中所有Spring Beans的完整列表 true
GET /dump 打印线程栈 true
GET /env 查看所有环境变量 true
GET /env/{name} 查看具体变量值 true
GET /health 查看应用健康指标, 当使用一个未认证连接访问时显示一个简单的’status’,使用认证连接访问则显示全部信息详情 false
GET /info 查看应用信息 false
GET /mappings 查看所有url映射, 即所有@RequestMapping路径的整理列表 true
GET /metrics 查看应用基本指标 true
GET /metrics/{name} 查看具体指标 true
POST /shutdown 关闭应用,允许应用以优雅的方式关闭(默认情况下不启用) true
GET /trace 查看基本追踪信息,默认为最新的一些HTTP请求 true

这些HTTP端点(Endpoint),默认是系统根路径访问的。如果我们想自定义context-path, 按照如下配置即可:

server.port=8888

#actuator
management.port=58888
management.context-path=/actuator

重启应用,我们将会看到如下日志:

01:23:38.033 [localhost-startStop-1] INFO  o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'springSecurityFilterChain' to: [/*] 
01:23:38.283 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/info || /actuator/info.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.284 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/trace || /actuator/trace.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.285 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/beans || /actuator/beans.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.286 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/configprops || /actuator/configprops.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.343 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/mappings || /actuator/mappings.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.348 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/health || /actuator/health.json],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal) 
01:23:38.349 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/autoconfig || /actuator/autoconfig.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.352 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/heapdump || /actuator/heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto 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 
01:23:38.353 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/dump || /actuator/dump.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.362 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String) 
01:23:38.362 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/metrics || /actuator/metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.363 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/env/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String) 
01:23:38.363 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/env || /actuator/env.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.364 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/server || /actuator/server.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 


我们可以清楚的看到Actuator提供应用运行信息监控等相关的HTTP Rest API(Endpoint)。

例如,我们访问 http://localhost:58888/actuator/env , 返回了系统的环境参数信息

// 20170504001108
// http://localhost:58888/actuator/env

{
  "profiles": [
    
  ],
  "server.ports": {
    "local.management.port": 58888,
    "local.server.port": 8888
  },
  "servletContextInitParams": {
    
  },
  "systemProperties": {
    "java.runtime.name": "Java(TM) SE Runtime Environment",
    "sun.boot.library.path": "/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/jre/lib",
    "java.vm.version": "25.40-b25",
    "user.country.format": "CN",
   ......

    "server.port": "8888",
    "spring.jpa.hibernate.naming-strategy": "org.hibernate.cfg.ImprovedNamingStrategy",
    "spring.jpa.hibernate.ddl-auto": "update",
    "info.build.version": "1.0-SNAPSHOT",
    "management.context-path": "/actuator",
    "spring.datasource.url": "jdbc:mysql://localhost:3306/lightsword?useUnicode=true&characterEncoding=UTF8",
    "endpoints.metrics.enabled": "true",
    "endpoints.info.id": "info",
    "management.port": "58888",
    "spring.velocity.resourceLoaderPath": "classpath:/templates/",
    "spring.mvc.static-path-pattern": "/**",
    "spring.jpa.database": "MYSQL",
    "spring.datasource.min-idle": "0",
    "info.app.name": "ecs",
    "spring.datasource.max-active": "0",
    "spring.datasource.max-wait": "10000",
    "management.security.sessions": "stateless",
    "endpoints.metrics.id": "metrics",
    "management.security.roles": "ADMIN",
    "spring.application.name": "lightsword",
    "spring.datasource.max-idle": "0",
    "spring.datasource.password": "******",
    "endpoints.actuator.enabled": "true",
    "spring.datasource.username": "root",
    "spring.velocity.properties.input.encoding": "UTF-8",
    "logging.config": "classpath:logback-dev.groovy",
    "endpoints.info.enabled": "true",
    "spring.jpa.show-sql": "true",
    "spring.velocity.toolbox-config-location": "/WEB-INF/toolbox.xml",
    "info.build.artifactId": "lightsword",
    "spring.velocity.properties.output.encoding": "UTF-8",
    "spring.velocity.suffix": ".html",
    "spring.datasource.driverClassName": "com.mysql.jdbc.Driver",
    "spring.resources.static-locations": "classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/",
    "spring.velocity.charset": "UTF-8",
    "info.app.version": "1.0.0"
  }
}

其他的一些端点,都带有丰富的系统运行数据,感兴趣的可以运行本章节的工程源码,查看端点的数据结构信息。

同时,Actuator支持与security集成,按照如下配置即可启用:

# Enable security.
management.security.enabled=true
# Comma-separated list of roles that can access the management endpoint.
management.security.roles=ADMIN

如果我们使用基于数据库的user,role集成Security的权限认证,经过测试,发现这里的management.security.roles=ADMIN将会不起作用。

如果我们想配置去掉某项的检查,比如不监控health.mail:

server:  
  port: 8888  
management:  
  port: 58888  
  health:  
    mail:  
      enabled: false  

我们可以看出这个58888端口映射的路径也是当前应用的服务器资源。例如http://localhost:58888/js/jsoneditor.js 也能访问到。跟访问 http://localhost:8888/js/jsoneditor.js 是一样的结果。

关于Actuator自动配置的源码在org.springframework.boot.actuate.autoconfigure中。想要详细深入的了解其中的原理,可以阅读这里的源码。

在application.properties中关于 ACTUATOR的配置如下

# ----------------------------------------
# ACTUATOR PROPERTIES
# ----------------------------------------

# ENDPOINTS (AbstractEndpoint subclasses)
endpoints.enabled=true # Enable endpoints.
endpoints.sensitive= # Default endpoint sensitive setting.
endpoints.actuator.enabled=true # Enable the endpoint.
endpoints.actuator.path= # Endpoint URL path.
endpoints.actuator.sensitive=false # Enable security on the endpoint.
endpoints.auditevents.enabled= # Enable the endpoint.
endpoints.auditevents.path= # Endpoint path.
endpoints.auditevents.sensitive=false # Enable security on the endpoint.
endpoints.autoconfig.enabled= # Enable the endpoint.
endpoints.autoconfig.id= # Endpoint identifier.
endpoints.autoconfig.path= # Endpoint path.
endpoints.autoconfig.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.beans.enabled= # Enable the endpoint.
endpoints.beans.id= # Endpoint identifier.
endpoints.beans.path= # Endpoint path.
endpoints.beans.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.configprops.enabled= # Enable the endpoint.
endpoints.configprops.id= # Endpoint identifier.
endpoints.configprops.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions.
endpoints.configprops.path= # Endpoint path.
endpoints.configprops.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.docs.curies.enabled=false # Enable the curie generation.
endpoints.docs.enabled=true # Enable actuator docs endpoint.
endpoints.docs.path=/docs #
endpoints.docs.sensitive=false #
endpoints.dump.enabled= # Enable the endpoint.
endpoints.dump.id= # Endpoint identifier.
endpoints.dump.path= # Endpoint path.
endpoints.dump.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.env.enabled= # Enable the endpoint.
endpoints.env.id= # Endpoint identifier.
endpoints.env.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions.
endpoints.env.path= # Endpoint path.
endpoints.env.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.flyway.enabled= # Enable the endpoint.
endpoints.flyway.id= # Endpoint identifier.
endpoints.flyway.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.health.enabled= # Enable the endpoint.
endpoints.health.id= # Endpoint identifier.
endpoints.health.mapping.*= # Mapping of health statuses to HttpStatus codes. By default, registered health statuses map to sensible defaults (i.e. UP maps to 200).
endpoints.health.path= # Endpoint path.
endpoints.health.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.health.time-to-live=1000 # Time to live for cached result, in milliseconds.
endpoints.heapdump.enabled= # Enable the endpoint.
endpoints.heapdump.path= # Endpoint path.
endpoints.heapdump.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.hypermedia.enabled=false # Enable hypermedia support for endpoints.
endpoints.info.enabled= # Enable the endpoint.
endpoints.info.id= # Endpoint identifier.
endpoints.info.path= # Endpoint path.
endpoints.info.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.jolokia.enabled=true # Enable Jolokia endpoint.
endpoints.jolokia.path=/jolokia # Endpoint URL path.
endpoints.jolokia.sensitive=true # Enable security on the endpoint.
endpoints.liquibase.enabled= # Enable the endpoint.
endpoints.liquibase.id= # Endpoint identifier.
endpoints.liquibase.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.logfile.enabled=true # Enable the endpoint.
endpoints.logfile.external-file= # External Logfile to be accessed.
endpoints.logfile.path=/logfile # Endpoint URL path.
endpoints.logfile.sensitive=true # Enable security on the endpoint.
endpoints.loggers.enabled=true # Enable the endpoint.
endpoints.loggers.id= # Endpoint identifier.
endpoints.loggers.path=/logfile # Endpoint path.
endpoints.loggers.sensitive=true # Mark if the endpoint exposes sensitive information.
endpoints.mappings.enabled= # Enable the endpoint.
endpoints.mappings.id= # Endpoint identifier.
endpoints.mappings.path= # Endpoint path.
endpoints.mappings.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.metrics.enabled= # Enable the endpoint.
endpoints.metrics.filter.enabled=true # Enable the metrics servlet filter.
endpoints.metrics.filter.gauge-submissions=merged # Http filter gauge submissions (merged, per-http-method)
endpoints.metrics.filter.counter-submissions=merged # Http filter counter submissions (merged, per-http-method)
endpoints.metrics.id= # Endpoint identifier.
endpoints.metrics.path= # Endpoint path.
endpoints.metrics.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.shutdown.enabled= # Enable the endpoint.
endpoints.shutdown.id= # Endpoint identifier.
endpoints.shutdown.path= # Endpoint path.
endpoints.shutdown.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.trace.enabled= # Enable the endpoint.
endpoints.trace.filter.enabled=true # Enable the trace servlet filter.
endpoints.trace.id= # Endpoint identifier.
endpoints.trace.path= # Endpoint path.
endpoints.trace.sensitive= # Mark if the endpoint exposes sensitive information.

# ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
endpoints.cors.allow-credentials= # Set whether credentials are supported. When not set, credentials are not supported.
endpoints.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
endpoints.cors.allowed-methods=GET # Comma-separated list of methods to allow. '*' allows all methods.
endpoints.cors.allowed-origins= # Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
endpoints.cors.exposed-headers= # Comma-separated list of headers to include in a response.
endpoints.cors.max-age=1800 # How long, in seconds, the response from a pre-flight request can be cached by clients.

# JMX ENDPOINT (EndpointMBeanExportProperties)
endpoints.jmx.domain= # JMX domain name. Initialized with the value of 'spring.jmx.default-domain' if set.
endpoints.jmx.enabled=true # Enable JMX export of all endpoints.
endpoints.jmx.static-names= # Additional static properties to append to all ObjectNames of MBeans representing Endpoints.
endpoints.jmx.unique-names=false # Ensure that ObjectNames are modified in case of conflict.

# JOLOKIA (JolokiaProperties)
jolokia.config.*= # See Jolokia manual

# MANAGEMENT HTTP SERVER (ManagementServerProperties)
management.add-application-context-header=false # Add the "X-Application-Context" HTTP header in each response.
management.address= # Network address that the management endpoints should bind to.
management.context-path= # Management endpoint context-path. For instance `/actuator`
management.cloudfoundry.enabled= # Enable extended Cloud Foundry actuator endpoints
management.cloudfoundry.skip-ssl-validation= # Skip SSL verification for Cloud Foundry actuator endpoint security calls
management.port= # Management endpoint HTTP port. Uses the same port as the application by default. Configure a different port to use management-specific SSL.
management.security.enabled=true # Enable security.
management.security.roles=ACTUATOR # Comma-separated list of roles that can access the management endpoint.
management.security.sessions=stateless # Session creating policy to use (always, never, if_required, stateless).
management.ssl.ciphers= # Supported SSL ciphers. Requires a custom management.port.
management.ssl.client-auth= # Whether client authentication is wanted ("want") or needed ("need"). Requires a trust store. Requires a custom management.port.
management.ssl.enabled= # Enable SSL support. Requires a custom management.port.
management.ssl.enabled-protocols= # Enabled SSL protocols. Requires a custom management.port.
management.ssl.key-alias= # Alias that identifies the key in the key store. Requires a custom management.port.
management.ssl.key-password= # Password used to access the key in the key store. Requires a custom management.port.
management.ssl.key-store= # Path to the key store that holds the SSL certificate (typically a jks file). Requires a custom management.port.
management.ssl.key-store-password= # Password used to access the key store. Requires a custom management.port.
management.ssl.key-store-provider= # Provider for the key store. Requires a custom management.port.
management.ssl.key-store-type= # Type of the key store. Requires a custom management.port.
management.ssl.protocol=TLS # SSL protocol to use. Requires a custom management.port.
management.ssl.trust-store= # Trust store that holds SSL certificates. Requires a custom management.port.
management.ssl.trust-store-password= # Password used to access the trust store. Requires a custom management.port.
management.ssl.trust-store-provider= # Provider for the trust store. Requires a custom management.port.
management.ssl.trust-store-type= # Type of the trust store. Requires a custom management.port.

# HEALTH INDICATORS
management.health.db.enabled=true # Enable database health check.
management.health.cassandra.enabled=true # Enable cassandra health check.
management.health.couchbase.enabled=true # Enable couchbase health check.
management.health.defaults.enabled=true # Enable default health indicators.
management.health.diskspace.enabled=true # Enable disk space health check.
management.health.diskspace.path= # Path used to compute the available disk space.
management.health.diskspace.threshold=0 # Minimum disk space that should be available, in bytes.
management.health.elasticsearch.enabled=true # Enable elasticsearch health check.
management.health.elasticsearch.indices= # Comma-separated index names.
management.health.elasticsearch.response-timeout=100 # The time, in milliseconds, to wait for a response from the cluster.
management.health.jms.enabled=true # Enable JMS health check.
management.health.ldap.enabled=true # Enable LDAP health check.
management.health.mail.enabled=true # Enable Mail health check.
management.health.mongo.enabled=true # Enable MongoDB health check.
management.health.rabbit.enabled=true # Enable RabbitMQ health check.
management.health.redis.enabled=true # Enable Redis health check.
management.health.solr.enabled=true # Enable Solr health check.
management.health.status.order=DOWN, OUT_OF_SERVICE, UP, UNKNOWN # Comma-separated list of health statuses in order of severity.

# INFO CONTRIBUTORS (InfoContributorProperties)
management.info.build.enabled=true # Enable build info.
management.info.defaults.enabled=true # Enable default info contributors.
management.info.env.enabled=true # Enable environment info.
management.info.git.enabled=true # Enable git info.
management.info.git.mode=simple # Mode to use to expose git information.

# TRACING (TraceProperties)
management.trace.include=request-headers,response-headers,cookies,errors # Items to be included in the trace.

# METRICS EXPORT (MetricExportProperties)
spring.metrics.export.aggregate.key-pattern= # Pattern that tells the aggregator what to do with the keys from the source repository.
spring.metrics.export.aggregate.prefix= # Prefix for global repository if active.
spring.metrics.export.delay-millis=5000 # Delay in milliseconds between export ticks. Metrics are exported to external sources on a schedule with this delay.
spring.metrics.export.enabled=true # Flag to enable metric export (assuming a MetricWriter is available).
spring.metrics.export.excludes= # List of patterns for metric names to exclude. Applied after the includes.
spring.metrics.export.includes= # List of patterns for metric names to include.
spring.metrics.export.redis.key=keys.spring.metrics # Key for redis repository export (if active).
spring.metrics.export.redis.prefix=spring.metrics # Prefix for redis repository if active.
spring.metrics.export.send-latest= # Flag to switch off any available optimizations based on not exporting unchanged metric values.
spring.metrics.export.statsd.host= # Host of a statsd server to receive exported metrics.
spring.metrics.export.statsd.port=8125 # Port of a statsd server to receive exported metrics.
spring.metrics.export.statsd.prefix= # Prefix for statsd exported metrics.
spring.metrics.export.triggers.*= # Specific trigger properties per MetricWriter bean name.

自动配置的 HealthIndicators

在目录org.springframework.boot.actuate.health下面,Spring Boot 默认自动配了如下的HealthIndicators

检查 Cassandra database is up.

检查 low disk space.

检查数据库连接是否正常

检查Elasticsearch cluster is up.

检查JMS broker is up.

检查mail server is up.

检查Mongo database is up.

检查Rabbit server is up.

检查Redis server is up.

检查Solr server is up.

举例说明,比如DataSourceHealthIndicator,其健康检查代码如下

        private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
        String product = getProduct();
        builder.up().withDetail("database", product);
        String validationQuery = getValidationQuery(product);
        if (StringUtils.hasText(validationQuery)) {
            try {
                // Avoid calling getObject as it breaks MySQL on Java 7
                List<Object> results = this.jdbcTemplate.query(validationQuery,
                        new SingleColumnRowMapper());
                Object result = DataAccessUtils.requiredSingleResult(results);
                builder.withDetail("hello", result);
            }
            catch (Exception ex) {
                builder.down(ex);
            }
        }
    }

实现逻辑很简单,就是执行一次query,看返回是否正常。

自定义 HealthIndicators

我们要自定义一个HealthIndicators,只需要注册一个Spring bean,实现HealthIndicator接口,实现其health()方法,返回一个 Health 对象即可。

我们可以直接参考Spring Boot 默认自动配置的那些HealthIndicators,仿照着写即可。

一个简单的示例代码如下:

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class MyHealthIndicator implements HealthIndicator {

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

}


不过有一点需要说明的是,Actuator 的这些HTTP Endpoints是基于 Spring MVC的应用的。

写一个自己的Endpoint

只需要实现Endpoint<T> 接口即可。这个接口的定义如下:


package org.springframework.boot.actuate.endpoint;

public interface Endpoint<T> {
    String getId();

    boolean isEnabled();

    boolean isSensitive();

    T invoke();
}

其中,getId()方法返回的就是url的path。

我们来实现一个获取当前运行服务器的基本信息的Endpoint,代码如下:

package com.springboot.in.action.actuator

import java.net.InetAddress
import java.util

import org.springframework.boot.actuate.endpoint.Endpoint
import org.springframework.stereotype.Component

/**
  * Created by jack on 2017/5/3.
  */
@Component
class ServerEndpoint extends Endpoint[java.util.List[String]] {
  override def invoke(): java.util.List[String] = {
    val serverDetails = new util.ArrayList[String]
    try {
      serverDetails.add("Server IP Address : " + InetAddress.getLocalHost.getHostAddress)
      serverDetails.add("Server OS : " + System.getProperty("os.name").toLowerCase)
    } catch {
      case e: Exception =>
        e.printStackTrace()
    }
    serverDetails
  }

  override def getId: String = "server"
  override def isSensitive: Boolean = false
  override def isEnabled: Boolean = true
}


重新部署运行,访问 http://localhost:58888/actuator/server ,我们看到输出如下:

// 20170503235224
// http://localhost:58888/actuator/server

[
  "Server IP Address : 192.168.1.104",
  "Server OS : mac os x"
]

11.2 Spring Boot远程Shell

Spring Boot通过集成Java shell框架CRaSH,让我们可以使用ssh或telnet命令连接到运行的应用。

添加以下依赖即可启用远程shell支持:

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

如果想使用telnet访问,需要另外添加org.crsh:crsh.shell.telnet的依赖。

配置完毕,重启应用。我们会看到启动日志

01:00:42.611 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property auth.spring.roles=ADMIN from properties 
01:00:42.619 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=SSHPlugin,interface=SSHPlugin] 
01:00:42.621 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=SSHInlinePlugin,interface=CommandPlugin] 
01:00:42.623 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=KeyAuthenticationPlugin,interface=KeyAuthenticationPlugin] 
01:00:42.648 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=CronPlugin,interface=CronPlugin] 
01:00:42.657 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=MailPlugin,interface=MailPlugin] 
01:00:42.661 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=CRaSHShellFactory,interface=ShellFactory] 
01:00:42.663 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=GroovyLanguageProxy,interface=Language] 
01:00:42.680 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=JavaLanguage,interface=Language] 
01:00:42.687 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=ScriptLanguage,interface=Language] 
01:00:42.700 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=JaasAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.730 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=SimpleAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.739 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.port=2000 from properties 
01:00:42.739 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.auth_timeout=600000 from properties 
01:00:42.740 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.idle_timeout=600000 from properties 
01:00:42.741 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.default_encoding=UTF-8 from properties 
01:00:42.742 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property auth=spring from properties 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=KeyAuthenticationPlugin,interface=KeyAuthenticationPlugin] 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=JaasAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=SimpleAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=AuthenticationManagerAdapter,interface=AuthenticationPlugin] 
01:00:42.767 [main] INFO  org.crsh.ssh.SSHPlugin - Booting SSHD 
01:00:42.793 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=GroovyLanguageProxy,interface=Language] 
01:00:42.861 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=JavaLanguage,interface=Language] 
01:00:42.861 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=ScriptLanguage,interface=Language] 
01:00:42.871 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=CRaSHShellFactory,interface=ShellFactory] 
01:00:44.185 [main] INFO  o.a.sshd.common.util.SecurityUtils - Trying to register BouncyCastle as a JCE provider 
01:00:45.739 [main] INFO  o.a.sshd.common.util.SecurityUtils - Registration succeeded 
01:00:45.978 [main] INFO  org.crsh.ssh.term.SSHLifeCycle - About to start CRaSSHD 
01:00:46.070 [main] INFO  org.crsh.ssh.term.SSHLifeCycle - CRaSSHD started on port 2000 
01:00:46.070 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=SSHPlugin,interface=SSHPlugin] 
01:00:46.070 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=SSHInlinePlugin,interface=CommandPlugin] 
01:00:46.071 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=CronPlugin,interface=CronPlugin] 
01:00:46.071 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=MailPlugin,interface=MailPlugin] 

从CRaSSHD started on port 2000这句看出,ssh默认监听的端口号为2000。SpringBoot的关于remote shell的属性配置,在org.springframework.boot.actuate.autoconfigure.ShellProperties类里面。

我们也可以在application.properties里面自行配置端口号:

management.shell.ssh.port=2001

执行如下命令

$ ssh -p 2000 user@localhost

我们就可以在shell终端连接我们的应用了。

如果我们什么都不配置,使用默认的配置,远程shell默认监听端口为2000,默认用户名为user,密码为随机生成的,并且在输出日志中会显示。

如果我们应用集成了Spring Security,remote shell使用默认系统的配置。

management.shell.auth.spring.roles=ADMIN,USER
#spring, Integrated with spring security
management.shell.auth.type=spring

这样配置将使用Spring Security的AuthenticationManager处理登录职责,相关代码如下:

private static class AuthenticationManagerAdapter extends CRaSHPlugin<AuthenticationPlugin> implements AuthenticationPlugin<String> {
        private static final PropertyDescriptor<String> ROLES = PropertyDescriptor.create("auth.spring.roles", "ADMIN", "Comma separated list of roles required to access the shell");
        @Autowired
        private AuthenticationManager authenticationManager;
        @Autowired(
            required = false
        )
        @Qualifier("shellAccessDecisionManager")
        private AccessDecisionManager accessDecisionManager;
        private String[] roles;

        private AuthenticationManagerAdapter() {
            this.roles = new String[]{"ADMIN"};
        }

        public boolean authenticate(String username, String password) throws Exception {
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);

            Authentication token;
            try {
                token = this.authenticationManager.authenticate(token);
            } catch (AuthenticationException var6) {
                return false;
            }

            if(this.accessDecisionManager != null && token.isAuthenticated() && this.roles != null) {
                try {
                    this.accessDecisionManager.decide(token, this, SecurityConfig.createList(this.roles));
                } catch (AccessDeniedException var5) {
                    return false;
                }
            }

            return token.isAuthenticated();
        }

具体参考CrshAutoConfiguration和ShellProperties的Javadoc。

如果不是,将使用一个简单的认证策略,你可能会看到类似这样的信息:

Using default password for shell access: ec03e16c-4cf4-49ee-b745-7c8255c1dd7e

如果想在简单的认证策略里指定用户名密码,按照如下配置即可

management.shell.auth.type=simple
management.shell.auth.simple.user.name=user
management.shell.auth.simple.user.password=123456

这个安全机制就是用的Spring security里面的功能。

Linux和OSX用户可以直接使用ssh连接远程shell,Windows用户可以下载并安装PuTTY,SecureCRT等客户端来实现ssh连接。

输入help可以获取命令列表,Spring Boot提供metrics,beans,autoconfig和endpoint命令。如下所示

jack@jacks-MacBook-Air:~$ ssh -p 2000 user@localhost
Password authentication
Password: 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.6.RELEASE)

> help
Try one of these commands with the -h or --help switch:                       
                                                                              
NAME       DESCRIPTION                                                        
autoconfig Display auto configuration report from ApplicationContext          
beans      Display beans in ApplicationContext                                
cron       manages the cron plugin                                            
dashboard  a monitoring dashboard                                             
egrep      search file(s) for lines that match a pattern                      
endpoint   Invoke actuator endpoints                                          
env        display the term env                                               
filter     a filter for a stream of map                                       
java       various java language commands                                     
jmx        Java Management Extensions                                         
jul        java.util.logging commands                                         
jvm        JVM informations                                                   
less       opposite of more                                                   
mail       interact with emails                                               
man        format and display the on-line manual pages                        
metrics    Display metrics provided by Spring Boot                            
shell      shell related command                                              
sleep      sleep for some time                                                
sort       sort a map                                                         
system     vm system properties commands                                      
thread     JVM thread commands                                                
help       provides basic help                                                
repl       list the repl or change the current repl    

比如,我们想看一下系统有那些Endpoint,直接命令行操作如下

> endpoint
usage: endpoint [-h | --help] COMMAND [ARGS]

The most commonly used endpoint commands are:
   invoke           Invoke provided actuator endpoint
   list             List all available and enabled actuator endpoints



> endpoint list
serverEndpoint
requestMappingEndpoint
environmentEndpoint
healthEndpoint
beansEndpoint
infoEndpoint
metricsEndpoint
traceEndpoint
dumpEndpoint
autoConfigurationReportEndpoint
configurationPropertiesReportEndpoint


连上ssh终端,我们看应用端的后台打印的日志

02:06:04.657 [main] INFO  o.s.b.c.e.t.TomcatEmbeddedServletContainer - Tomcat started on port(s): 8888 (http) 
02:06:04.673 [main] INFO  scala.App - Started App in 52.422 seconds (JVM running for 56.978) 
02:06:13.105 [pool-6-thread-1] INFO  o.a.s.server.session.ServerSession - Server session created from /127.0.0.1:50538 
02:06:13.260 [pool-6-thread-1] INFO  o.a.s.server.session.ServerSession - Kex: server->client aes128-ctr hmac-sha2-256 none 
02:06:13.260 [pool-6-thread-1] INFO  o.a.s.server.session.ServerSession - Kex: client->server aes128-ctr hmac-sha2-256 none 
02:06:16.370 [pool-6-thread-1] INFO  o.a.s.s.s.ServerUserAuthService - Session user@/127.0.0.1:50538 authenticated 
      

可以看出,ServerUserAuthService负责认证当前登录用户,ServerSession负责维护当前登录session。

你可以使用Groovy或Java编写其他的shell命令(具体参考CRaSH文档),Spring Boot默认会搜索以下路径的命令:

classpath*:/commands/**
classpath*:/crash/commands/**

如果我们想改变搜索路径,设置shell.command-path-patterns属性即可。

下面是一个从src/main/resources/commands/hello.java加载的'hello'命令:

/**
 * Created by jack on 2017/5/4.
 */

package commands;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.crsh.cli.Command;
import org.crsh.cli.Usage;
import org.crsh.command.BaseCommand;
import org.crsh.command.InvocationContext;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;


@Usage("Test Command : hello say")
public class hello extends BaseCommand{
    @Usage("hello say")
    @Command
    public String say(InvocationContext context){
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) context.getAttributes().get("spring.beanfactory");

        for (String name : defaultListableBeanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
            context.getWriter().write(name);
            context.getWriter().write("\n");
        }

        return "Hello, Now Is " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }
}




在远程ssh中执行命令,结果如下

jack@jacks-MacBook-Air:~$ ssh -p 2000 user@localhost
Password authentication
Password: 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.6.RELEASE)

> help
Try one of these commands with the -h or --help switch:                                                                               
                                                                                                                                      
NAME       DESCRIPTION                                                                                                                
autoconfig Display auto configuration report from ApplicationContext                                                                  
beans      Display beans in ApplicationContext                                                                                        
cron       manages the cron plugin                                                                                                    
dashboard  a monitoring dashboard                                                                                                     
egrep      search file(s) for lines that match a pattern                                                                              
endpoint   Invoke actuator endpoints                                                                                                  
env        display the term env                                                                                                       
filter     a filter for a stream of map                                                                                               
hello      Test Command : hello say                                                                                                   
java       various java language commands                                                                                             
jmx        Java Management Extensions                                                                                                 
jul        java.util.logging commands                                                                                                 
jvm        JVM informations                                                                                                           
less       opposite of more                                                                                                           
mail       interact with emails                                                                                                       
man        format and display the on-line manual pages                                                                                
metrics    Display metrics provided by Spring Boot                                                                                    
shell      shell related command                                                                                                      
sleep      sleep for some time                                                                                                        
sort       sort a map                                                                                                                 
system     vm system properties commands                                                                                              
thread     JVM thread commands                                                                                                        
help       provides basic help                                                                                                        
repl       list the repl or change the current repl                                                                                   

> hello
usage: hello [-h | --help] COMMAND [ARGS]

The most commonly used hello commands are:
   say              hello say



> hello say
......

lightSwordHealthIndicator
serverEndpoint
globalExceptionHandlerAdvice
angularController
helloController
httpApiController
httpReportController
httpSuiteController
rootController
webMvcConfig
webSecurityConfig
dataInit
lightSwordUserDetailService
org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
authenticationManagerBuilder
enableGlobalAuthenticationAutowiredConfigurer
initializeUserDetailsBeanManagerConfigurer
initializeAuthenticationProviderBeanManagerConfigurer
org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration
delegatingApplicationListener
webSecurityExpressionHandler
springSecurityFilterChain
........

org.springframework.boot.autoconfigure.web.MultipartProperties
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$RestTemplateConfiguration
restTemplateBuilder
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration
org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration$DatabaseShutdownExecutorJpaDependencyConfiguration
org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration
inMemoryDatabaseShutdownExecutor
loginFilter
org.springframework.orm.jpa.SharedEntityManagerCreator#0
Hello, Now Is 2017-05-04 02:29:38


除了创建新命令,你也可以扩展CRaSH shell的其他特性,所有继承org.crsh.plugin.CRaSHPlugin的Spring Beans将自动注册到shell,具体可以查看CRaSH参考文档[4]。

小结

本章示例工程源代码:

https://github.com/EasySpringBoot/lightsword/tree/spring_boot_actuator_and_remote_shell_2017.5.4

参考资料:
1.http://javabeat.net/spring-boot-actuator/
2.http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-remote-shell.html
3.https://my.oschina.net/zj0303/blog/708366
4.http://www.crashub.org/

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
26天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
132 1
|
10天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
90 62
|
8天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
8天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
23 2
|
28天前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
48 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
22天前
|
人工智能 开发框架 Java
总计 30 万奖金,Spring AI Alibaba 应用框架挑战赛开赛
Spring AI Alibaba 应用框架挑战赛邀请广大开发者参与开源项目的共建,助力项目快速发展,掌握 AI 应用开发模式。大赛分为《支持 Spring AI Alibaba 应用可视化调试与追踪本地工具》和《基于 Flow 的 AI 编排机制设计与实现》两个赛道,总计 30 万奖金。
|
27天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第8天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建并配置 Spring Boot 项目,实现后端 API 和安全配置。接着,使用 Ant Design Pro Vue 脚手架创建前端项目,配置动态路由和菜单,并创建相应的页面组件。最后,通过具体实践心得,分享了版本兼容性、安全性、性能调优等注意事项,帮助读者快速搭建高效且易维护的应用框架。
38 3
|
28天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第7天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建 Spring Boot 项目并配置 Spring Security。接着,实现后端 API 以提供菜单数据。在前端部分,使用 Ant Design Pro Vue 脚手架创建项目,并配置动态路由和菜单。最后,启动前后端服务,实现高效、美观且功能强大的应用框架。
34 2
|
1月前
|
人工智能 缓存 Java
深入解析Spring AI框架:在Java应用中实现智能化交互的关键
【10月更文挑战第12天】Spring AI 是 Spring 框架家族的新成员,旨在满足 Java 应用程序对人工智能集成的需求。它支持自然语言处理、图像识别等多种 AI 技术,并提供与云服务(如 OpenAI、Azure Cognitive Services)及本地模型的无缝集成。通过简单的配置和编码,开发者可轻松实现 AI 功能,同时应对模型切换、数据安全及性能优化等挑战。
|
16天前
|
存储 Java 数据管理
强大!用 @Audited 注解增强 Spring Boot 应用,打造健壮的数据审计功能
本文深入介绍了如何在Spring Boot应用中使用`@Audited`注解和`spring-data-envers`实现数据审计功能,涵盖从添加依赖、配置实体类到查询审计数据的具体步骤,助力开发人员构建更加透明、合规的应用系统。