Spring Boot 3.0.0-M1 Reference Documentation(Spring Boot中文参考文档) 9-16

9. 数据

Spring Boot与多个数据技术集成,包括SQL和NoSQL。

9.1. SQL数据库

Spring Framework提供扩展支持用于与SQL数据工作,从使用JdbcTemplate直接JDBC访问到完全的“对象关系映射”技术比如Hibernate。Spring Data提供一个额外的功能级别:直接从接口创建Repository实现并使用约定从方法名称生成查询。

9.1.1. 配置数据源

Java的javax.sql.DataSource接口提供标准的与数据库链接工作的方法。传统上,'DataSource’使用URL连同证书一起建立数据库链接。

查看"How-to"部分了解更多高级示例,通常是为了完全控制数据源的配置。

内嵌的数据库支持

通常非常方便使用一个基于内存的内嵌数据库开发应用程序。显然,内存数据库不提供持久化存储。你需要在应用程序启动时填充数据,在应用程序结束时丢弃数据。

"How-to"章节包括一部分关于如何初始化数据库。

Spring Boot可以自动配置内嵌的H2,HSQL和Derby数据库。你不需要提供任何连接URL。你只需要包含你想要使用的内嵌数据库的构建依赖。如果在类路径有多个内嵌数据库,设置spring.datasource.embedded-database-connection配置属性控制你使用的那一个。设置属性值为none则禁用内嵌数据的自动配置。

如果在你的测试中,你正在使用这个特性,你可能注意到无论你使用的多少应用程序上线文,你的全部测试套件重用了相同的数据库。如果你想确保每一个上下文有单独的内嵌数据库,你应该设置spring;datasource.generate-unique-nametrue

例如,典型的POM依赖如下:

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
    <groupId>org.hsqldbgroupId>
    <artifactId>hsqldbartifactId>
    <scope>runtimescope>
dependency>

你需要在spring-jdbc上的一个依赖项用于自动配置内嵌数据库。在这个示例中,它通过spring-boot-starter-data-jpa传递拉入的。

如果,无论什么原因,你所做的配置链接URL用于内嵌数据库,注意确保数据库的自动停机是禁用的。如果你使用H2,为此你应该使用DB_CLOSE_ON_EXIST=FALSE。如果你使用HSQLDB,你应该确保不使用shutdown=true。当关闭数据库时,禁用数据库自动停机可以让Spring Boot控制,从而确保不在需要访问数据库进行自动关闭。

连接生产数据库

生产数据库链接也可以使用DataSource连接池自动配置。

DataSource配置

spring.datasource.*中的外部配置属性控制DataSource配置。例如,你可以在application.properties中声明以下部分:

spring:
  datasource:
    url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"

你应该至少通过设置spring.datasource.url属性指定URL。否则,Spring Boot尝试自动配置一个内嵌数据库。

Spring Boot可以从URL中推断大多数数据库的JDBC驱动。如果你需要指定一个特定的类,你可以使用spring.datasource.driver-class-name属性。

为创建DataSource池,我们需要可以校验一个有效的Driver类是可用的,所以在做任何事情之前我们会对其进行检查。换句话说,如果你设置spring.datasource.driver-class-name=com.mysql.jdbc.Driver,然后该类必须是可加载的。

请查看DataSourceProperties了解更多的支持的选项。不管真正的实现这些都是标准的选项。也可以通过使用他们的各自的前缀微调特定的实现设置(spring.datasource.hikari.*,spring.datasource.tomcat.*,spring.datasource.dbcp2.*spring.datasource.oracleucp.*)。请查看你正使用的连接池实现文档了解更多详情。

例如,如果你使用Tomcat 连接池,你可以定制许多额外的设置,如下示例所示:

spring:
  datasource:
    tomcat:
      max-wait: 10000
      max-active: 50
      test-on-borrow: true

如果没有链接可用,这个将设置抛出异常之前链接池等待10000ms,限制最大的链接数是50并且在池中借出它之前校验链接。

支持的链接池

Spring Boot使用以下算法用于选择特定实现:

  1. 我们更喜欢HikariCP它的性能和并发性。如果HikariCP可用,我们总是选择它。
  2. 否则,如果Tomcat DataSource池可用,我们使用它。
  3. 否则,如果通用的DBCP2可用,我们使用它。
  4. 如果没有HikariCP,Tomcat和DBCP2可用,如果Oracle UCP可用,我们使用它。

如果你使用spring-boot-starter-jdbc或者spring-boot-starter-data-jap启动器,你自动得到HikariCP依赖项。

你可以完全绕过该算法并通过设置spring.datasource.type属性指定链接池来使用。如果在tomcat容器运行应用程序这点非常重要,因为默认提供tomcat-jdbc

使用DataSourceBuilder可以手工配置额外的链接池。如果你定义你自己的DataSourcebean,自动配置不会发生。下面的链接池通过DataSourceBuilder支持。

  • HikariCP
  • Tomcat DataSource
  • 通用的DBCP2
  • Oracel UCP&OracelDataSource
  • Spring Framework的SimpleDriverDataSource
  • H2 JdbcDataSource
  • PostgreSQL PGSimpleDataSource
链接到JNDI数据源

如果你部署你的Spring Boot应用程序到Application Server,你可能想要通过使用你的Application Server内建特性配置和管理你的DataSource并通过使用JNDI访问它。

spring.datasource.jndi-name属性可以用来当做spring.datasource.url的替代方案,spring.datasource.usernamespring.datasource.password属性可以从特定的JNDI位置访问DataSource。例如,下面的application.properties中部分展示根据定义的DataSource如何访问JBoss:

spring:
  datasource:
    jndi-name: "java:jboss/datasources/customers"

9.1.2. 使用JdbcTemplate

Spring的JdbcTempalteNamedParameterJdbcTemplate类是自动配置的,你可以直接@Autowire他们到自己的bean,如下示例所示:

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final JdbcTemplate jdbcTemplate;

    public MyBean(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void doSomething() {
        this.jdbcTemplate ...
    }

}

你可以通过使用spring.jdbc.template.*属性定制一些模板的属性,如下示例所示:

spring:
  jdbc:
    template:
      max-rows: 500

NamedParameterJdbcTemplate在底层重用相同的JdbcTemplate实例。如果超过一个JdbcTemplate被定义并没有主要的候选者存在,NamedParameterJdbcTempalte不会自动配置。

9.1.3. JPA和Spring Data JPA

Java Persistence API(Java持久化API)是标准的技术,让你“映射”对象到相关的数据库。spring-boot-starter-data-jpaPOM提供一个快速的方式开始。它提供以下关键依赖:

  • Hibernate:最受欢迎之一的JPA实现。
  • Spring Data JPA:帮助你实现基于JAP仓库。
  • Spring ORM:来自Spring Framework核心ORM支持。

这里我们不深入了解JPA和Spring Data的更多细节。你可以遵循来自spring.io的“使用JPA访问数据”指南并阅读Spring Data JPA和Hibernate参考文档。

实体类

传统上,在persistence.xml文件中指定JPA“实体”类。使用Spring Boot,这个文件不必须的并使用“Entity Scanning”代替。默认情况下,在你的主配置类(使用@EnableAutoConfiguration或者@SpringBootApplication注解的一个)下的所有包都会被搜索。

使用@Entity@Embeddable或者@MappedSuperclass注解的所有类都会考虑。一个典型的实体类类似于下面的示例:

import java.io.Serializable;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class City implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String state;

    // ... additional members, often include @OneToMany mappings

    protected City() {
        // no-args constructor required by JPA spec
        // this one is protected since it should not be used directly
    }

    public City(String name, String state) {
        this.name = name;
        this.state = state;
    }

    public String getName() {
        return this.name;
    }

    public String getState() {
        return this.state;
    }

    // ... etc

}

通过使用@EntityScan注解你可以定制实体扫描位置。请查看“将@Entity 定义与Spring Configuration分隔”如果做。

Spring Data JPA仓库

Spring Data JPA仓库是接口,你可以定义以访问数据。JPA查询根据你的方法名称自动创建。例如,CityRepository接口可能声明findAllByState(String state)方法来查找给定状态的所有城市。

对于更复杂的查询,你可以使用Spring Data的Query注解来注解你的方法。

Spring Data仓库通常集成自Repository或者CrudRepository接口。如果你使用自动配置,将从你的主配置类(使用@EnableAutoConfiguration或者@SpringBootApplication注解的一个)搜索仓库。

下面的示例展示了一个典型的Spring Data仓库接口定义:

import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;

public interface CityRepository extends Repository<City, Long> {

    Page<City> findAll(Pageable pageable);

    City findByNameAndStateAllIgnoringCase(String name, String state);

}

Spring Data JPA仓库支持不同的引导指令模式:defalut,defered和lazy。为启用延迟的或者懒惰的引导指令,分别设置spring.data.jpa.repositories.bootstrap-mode属性为deferred或者lazy。当使用defered或者lazy引导指令,自动配置EntityManagerFactoryBuilder将使用上下文的AsyncTaskExecutor,若有的话,作为引导执行器。如果存在多余一个,名称为applicationTaskExecutor的那个将被使用。

当使用deferred或者lazy引导指令,确保在应用程序上下文引导阶段之后延迟对JPA基础设施的任何访问。你可以使用SmartInitializingSingleton以调用任何需要JPA基础设施的初始化。对于JPA组件(例如converters)被创建为Spring bean,如果有依赖项,请使用ObjectProvider来延迟解析。

我们只触碰到Spring Data JPA的皮毛。要了解完整的详情,请查阅Spring Data JPA参考文档。

Spring Data Envers仓库

如果Sprig Data Enver可用,JPA仓库自动配置以支持典型的Enver需求。

为使用Spring Data Enver,确保你的仓库继承于RevisionRepository如下示例所示:

import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.history.RevisionRepository;

public interface CountryRepository extends RevisionRepository<Country, Long, Integer>, Repository<Country, Long> {

    Page<Country> findAll(Pageable pageable);

}

为了解更多详情,请查看Spring Data Enver参考文档。

创建和移除JPA数据库

默认情况下,只有使用内嵌数据库(H2,HSQL或者Derby)时JPA数据库是自动创建。你可以通过使用spring.jpa.*属性明确的配置JPA设置。例如,为创建和移除表,你可以添加以下行到你的application.properties

spring:
  jpa:
    hibernate.ddl-auto: "create-drop"

Hibernate自己对此的内部属性名称是hibernate.hbm2ddl.auto。你可以通过使用spring.jpa.properties.*(将他们添加到实体管理之前剔除前缀)设置它和其他Hibernate本身属性一起。以下行展示对Hibernate设置JPA属性的示例:

spring:
  jpa:
    properties:
      hibernate:
        "globally_quoted_identifiers": "true"

在前面的示例中的行传入hibernate.globally_quoted_identifiers属性true值到Hibernate实体管理。

默认情况下,DDL执行器(或者校验器)是延迟的直到ApplicationContext已经开始。也存在spring.jpa.generate-ddl标志,但是如果Hibernate自动配置是活跃的,它不会被使用,因为ddl-auto设置是更细粒度的。

视图中打开EntityManager

如果你正在运行一个web应用程序,默认情况下,Spring Boot注册OpenEntityManagerInViewInterceptor以应用“Open EntityManager In View”格式,允许在web视图中用于懒加载。如果你不希望这样的行为,你应该在application.properties中的spring.jpa.open-in-view设置为false

9.1.4. Spring Data JDBC

Spring Boot包含对JDBC支持的仓库并将对在CrudRepository上的方法自动生成SQL。对于更高级的查询,提供@Query注解。

当必须的依赖在类路径中时,Spring Boot将自动配置Spring Data的JDBC仓库。使用在spring-boot-starter-data-jdbc上的单个依赖将他们加入的项目。如果必须,你可以通过添加@EnableJdbcRepositories注解或者JdbcConfiguration子类到你的应用程序以控制Spring Data JDBC的配置。

为了解Spring Data JDBC完整详情,请查看参考文档。

9.1.5.使用H2web 控制台

H2数据库提供基于浏览器的控制台,Spring Boot可以自动配置给你。当以下条件满足时自动配置控制台:

  • 你正在开发一个基于Servlet的web应用程序。
  • com.h2database:h2在类路径中。
  • 你正在使用Spring Boot开发者工具。

如果你没有使用开发者工具但是仍想使用H2控制台, 你可以使用true值配置spring.h2.console.enabled属性。

H2控制台只打算用于开发期间使用,所以你应该小心,以确保生产环境spring.h2.console.enabled没有设置为true

更改H2控制台路径

默认情况下,控制台是使用在/h2-console。你可以通过使用spring.h2.console.path属性定制控制台路径。

在保障安全的应用程序中访问H2控制台

H2控制台使用框架并只打算用于开发环境,不支持CSRF保护措施。如果你的应用程序使用Spring Security,你需要配置它为:

  • 针对控制台请求禁用CSRF保护。
  • 在来自控制台的响应上设置头X-Frame-OptionsSAMEORIGIN
    在CSRF和头X-Frame-Options更多信息可以在Spring Security参考指南中发现。

在简单的设置中,像以下的SecurityFilterChain可以使用:

import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Profile("dev")
@Configuration(proxyBeanMethods = false)
public class DevProfileSecurityConfiguration {

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    SecurityFilterChain h2ConsoleSecurityFilterChain(HttpSecurity http) throws Exception {
        http.requestMatcher(PathRequest.toH2Console());
        http.authorizeRequests(yourCustomAuthorization());
        http.csrf((csrf) -> csrf.disable());
        http.headers((headers) -> headers.frameOptions().sameOrigin());
        return http.build();
    }


}

H2控制台只打算在开发期间使用。在生产环境,对站点禁用CSRF保护或者允许框架可能创建严重安全风险。

当控制台路径已经被定制,PathRequest.toH2Console()也可以返回正确的请求匹配器。

9.1.6. 使用jOOQ

jOOQ Object Oriented Querying(jOOQ)是来自Data Geekery非常受欢迎的产品,它根据你的数据库生成Java代码并允许你通过它的流式API构建类型安全的SQL查询。商业和开源版本都可以被Spring Boot使用。

代码生成

为了使用jOOQ类型安全查询,你需要从你的数据库模式生成Java类。你可以遵循jOOQ用户手册说明。如果你使用jooq-codegen-maven插件并且你也可以spring-boot-start-parent父POM,你可以安全地省去插件的标签。你也可以使用预定义的Spring Boot版本变量(比如h2.version)以声明插件的数据库依赖。以下列表展示了一个示例:

<plugin>
    <groupId>org.jooqgroupId>
    <artifactId>jooq-codegen-mavenartifactId>
    <executions>
        ...
    executions>
    <dependencies>
        <dependency>
            <groupId>com.h2databasegroupId>
            <artifactId>h2artifactId>
            <version>${h2.version}version>
        dependency>
    dependencies>
    <configuration>
        <jdbc>
            <driver>org.h2.Driverdriver>
            <url>jdbc:h2:~/yourdatabaseurl>
        jdbc>
        <generator>
            ...
        generator>
    configuration>
plugin>
使用DSLContext

jOOQ提供的流式API通过org.jooq.DSLContext接口发起的。Spring Boot自动配置DSLContext作为Spring bean并将它与应用程序DataSource连接。为使用DSLContext,你可以注入它,如下示例所示:

import java.util.GregorianCalendar;
import java.util.List;

import org.jooq.DSLContext;

import org.springframework.stereotype.Component;

import static org.springframework.boot.docs.data.sql.jooq.dslcontext.Tables.AUTHOR;

@Component
public class MyBean {

    private final DSLContext create;

    public MyBean(DSLContext dslContext) {
        this.create = dslContext;
    }


}

jOOQ手册倾向于使用名为create变量名称来保存DSLContext

你仍可以使用DSLContext来构造你的查询,如下示例所示:

public List<GregorianCalendar> authorsBornAfter1980() {
    return this.create.selectFrom(AUTHOR)
            .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
            .fetch(AUTHOR.DATE_OF_BIRTH);

jOOQ SQL Dialect

除了spring.jooq.sql-dialect属性已经配置,Spring Boot决定SQL方言来用于数据源的使用。如果Spring Boot无法检测方言,他使用DEFAULT

Spring Boot只能通过开源的jOOQ版本自动配置支持的方言。

定制jOOQ

通过定义自己的DefaultConfigurationCustomizerbean可以实现更高级的定制,该bean将在创建org.jooq.Configuration``@Bean之前被调用。

9.1.7. 使用R2DBC

Reactive Relational Database Connectivity(R2DBC)项目采用响应式程序API关系型数据库。R2DBC的io.r2dbc.spi.Connection提供标准的工作于非阻塞数据库链接的方法。通过使用ConnectionFactory提供链接,类似于使用jdbc的DataSource

通过在spring.r2dbc.*外部配置属性控制ConnectionFactory配置。例如,你可以在application.properties中声明以下部分:

spring:
  r2dbc:
    url: "r2dbc:postgresql://localhost/test"
    username: "dbuser"
    password: "dbpass"

你不需要指定驱动类名称,因为Spring Boot从R2DBC的链接工厂发现获得。

至少应该提供url,URL中特定的信息优先级高于个别属性,那是name,username,password和池化选项。

“如何做”章节包含在如何初始化数据库部分。

为了通过ConnectionFactory定制创建的链接,就是说,在主要的数据库配置中设置你不想(或者不能)配置特定的参数,你可以使用ConnectionFactoryOptionsBuilderCustomizer``@Bean。下面的示例展示了如何手工重写数据库端口,而其余的选项从应用程序配置中获取:

import io.r2dbc.spi.ConnectionFactoryOptions;

import org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryOptionsBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyR2dbcConfiguration {

    @Bean
    public ConnectionFactoryOptionsBuilderCustomizer connectionFactoryPortCustomizer() {
        return (builder) -> builder.option(ConnectionFactoryOptions.PORT, 5432);
    }

}

下面的示例展示如何设置一些PostgreSQL连接选项:

import java.util.HashMap;
import java.util.Map;

import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider;

import org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryOptionsBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyPostgresR2dbcConfiguration {

    @Bean
    public ConnectionFactoryOptionsBuilderCustomizer postgresCustomizer() {
        Map<String, String> options = new HashMap<>();
        options.put("lock_timeout", "30s");
        options.put("statement_timeout", "60s");
        return (builder) -> builder.option(PostgresqlConnectionFactoryProvider.OPTIONS, options);
    }

}

ConnectionFactorybean可用时,常规的JDBCDataSource自动配置就会消失。如果你想保留JDBCDataSource自动配置并能够承担在响应式应用程序中使用阻塞JDBC API的风险,在@Configuration类上添加@Import@DataSourceAutoConfiguration.class)以重新启用它。

内嵌数据库支持

类似于JDBC的支持,Spring Boot可以自动配置一个内嵌的数据库用于响应式用法。你无需提供任何连接URL.你只需要包括构建你想使用的内嵌数据库的依赖,如下示例所示:

<dependency>
    <groupId>io.r2dbcgroupId>
    <artifactId>r2dbc-h2artifactId>
    <scope>runtimescope>
dependency>

如果你正在你的测试中使用这个特定,你可能要注意无论你所使用的应用程序上下文的数据,你的所有测试用例都会重用相同的数据库。如果你想确保每一个上下文有隔离的内嵌数据库,你应该设置spring.r2dbc.generate-unique-nametrue

使用DatabaseClient

DatabaseClientbean是自动配置,你可以直接@Autowire它到你自己的bean,如下示例所示:

import java.util.Map;

import reactor.core.publisher.Flux;

import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final DatabaseClient databaseClient;

    public MyBean(DatabaseClient databaseClient) {
        this.databaseClient = databaseClient;
    }

    public Flux<Map<String, Object>> someMethod() {
        return this.databaseClient.sql("select * from user").fetch().all();
    }

}
Spring Data R2DBC 仓库

Spring Data R2DBC仓库是接口,你可以定义以访问数据。根据你的方法名自动创建查询。例如,CityRepository接口可能声明findAllByState(String state)方法来根据给定的状态查找所有的城市。

对于更复杂的查询,你可以使用Spring Data的Query注解来注解你的方法。

Spring Data通常实现Repository或者CrudRepository接口。如果你使用自动配置,从包含你的主配置类(使用@EnableAutoConfiguration或者@SpringBootApplication)的包搜索仓库。

下面的示例展示了典型的Spring Data 仓库接口定义:

import reactor.core.publisher.Mono;

import org.springframework.data.repository.Repository;

public interface CityRepository extends Repository<City, Long> {

    Mono<City> findByNameAndStateAllIgnoringCase(String name, String state);

}

我们只是触及了Spring Data R2DBC皮毛。为了解完整细节,请查阅Spring Data R2DBC参考文档。

9.2. 使用NoSQL技术

Spring Data提供额外的项目帮助你访问访问多个NoSQL技术,包括:

  • MongoDB
  • Neo4J
  • Elasticsearch
  • Redis
  • GemFire 或者Geode
  • Cassandra
  • Couchbase
  • LDAP
    Spring Boot提供对Redis,MongoDB,Neo4J,Elasticsearch,Cassandra,Couchbase,LDAP和InfluxDB自动配置。此外,针对Apache Geode的Spring Boot为Apache Geode提供自动配置。你可以利用其他项目,但是你必须自己配置他们。请查阅合适的参考文档在spring.io/projects/spring-data。

9.2.1. Redis

Redis是缓存,消息broker和特性丰富 key-value存储。Spring Boot为Lettuce和Jedis客户端类库以及Spring Data Redis提供的基于他们的抽象提供了基础的自动配置。

spring-boot-starter-data-redis启动器用于以方便的方式汇总依赖。默认情况下,它使用Letture。此启动器处理传统的和响应式的应用程序。

我们也提供spring-boot-starter-data-redis-reactive启动器为了与支持响应式的其他存储保持一致。

连接Redis

你可以注入自动配置的RedisConnectionFactory,StringRedisTemplate或原版的RedisTemplate实例作为你任何其他的Spring Bean。默认情况下,此实例尝试在localhost:6379连接Redis。下方的列表展示这样bean的一个示例:

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final StringRedisTemplate template;

    public MyBean(StringRedisTemplate template) {
        this.template = template;
    }

    public Boolean someMethod() {
        return this.template.hasKey("spring");
    }

}

你也可以注册一个随意数量实现LettuceClientConfigurationBuildrCustomizer的bean用于更高级的定制。也可以使用ClientResourcesBuilderCustomizer定制ClientResources。如果你使用Jedis,JedisClientConfigurationBuilderCustomizer是可用的。或者,你可以注册RedisStandaloneConfiguration,RedisSentineConfiguration或者RedisClusterConfiguration型的bean以完全控制配置。

如果你添加自己的任何自动配置类型的@Bean,他会替换默认值(除了RedisTempplate情况,当排除基于bean名称redisTemplate而不是类型时)。

默认情况下,如果commons-pooks在类路径中,连接池工厂自动配置。

9.2.2. MongoDB

MongoDB是开源的NoSQL文档数据库,它使用类似于JSON模式替代传统的基于表的相关的数据。Spring Boot为与MongoDB工作提供许多方便,包括spring-boot-starter-data-mongdbspring-boot-starter-data-mongodb-reactive启动器。

连接MongoDB数据库

为访问MongoDB数据库,你可以注入自动配置的org.springframework.data.mongodb.MongoDatabaseFactory。默认情况下,该实例尝试连接到在mongodb://localhost/test的MongoDB服务器。以下示例展示了如何连接到MongoDB数据库:

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final MongoDatabaseFactory mongo;

    public MyBean(MongoDatabaseFactory mongo) {
        this.mongo = mongo;
    }

    public MongoCollection<Document> someMethod() {
        MongoDatabase db = this.mongo.getMongoDatabase();
        return db.getCollection("users");
    }

}

如果你已经定义了自己的MongoClinet,它将被用来自动配置适宜的MongoDatabaseFactory

使用MongoClientSettingsbean创建自动配置的MongoClient。如果你已经定义了自己的MongoClientSetting,无需修改使用它并且spring.data.mongodb属性将被忽略。否则MongoClientSetting将自动配置并应该spring.data.mongodb属性。不论发生何种情况,你可以声明一个或者更多MongoClientSettingsBuilderCustomizerbean来微调MongoClientSettings配置。MongClientSettings.Builder顺序地调用每一个,用来构建MongoClientSettings

你可以设置spring.data.mongodb.uri属性来改变URL并配置额外的设置例如replica set,如下示例所示:

spring:
  data:
    mongodb:
      uri: "mongodb://user:[email protected]:12345,mongo2.example.com:23456/test"

或者,你可以使用离散的属性指定链接明细。例如,你可以在application.properties中声明以下设置:

spring:
  data:
    mongodb:
      host: "mongoserver.example.com"
      port: 27017
      database: "test"
      username: "user"
      password: "secret"

如果spring.data.mongodb.port没有指定,将使用默认的27017。你可以从前面展示的示例中删除这行。

如果你不使用Spring Data MongoDB,你可以注入MongoClientbean代替使用MongoDatabaseFactory。如果你想完成控制建立MongoDB连接,你还可以声明自己的MongoDatabaseFactory或者MongoClientbean。

如果你正在使用响应式驱动,Netty需要用于SSL。自动配置自动配置该工厂如果Netty可用并且要使用工厂还没有定制好。

MongoTemplate

Spring Data MongoDB提供MongoTemplate类,它的设计非常类似于Spring的JdbcTemplate。正如JdbcTemplate一样,Spring Boot为你自动配置一个bean来注入这个模板,如下:

import com.mongodb.client.MongoCollection;
import org.bson.Document;

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final MongoTemplate mongoTemplate;

    public MyBean(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public MongoCollection<Document> someMethod() {
        return this.mongoTemplate.getCollection("users");
    }

}

请查阅MongoOperations Javadoc了解全部细节。

Spring Data MongoDB Repositories

Spring Data 包含支持MongoDB的仓库。正如前面讨论的JPA仓库,基本的原理是基于方法名称自动构造查询。

事实上,Spring Data JPA和Spring Data MongoDB共享相同的通用基础设施。你可以从前面了解JPA示例并且假定现在City是MongoDB的数据类而不是JPA@Entity,他以相同的方式工作,如下示例所示:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;

public interface CityRepository extends Repository<City, Long> {

    Page<City> findAll(Pageable pageable);

    City findByNameAndStateAllIgnoringCase(String name, String state);

}

你可以通过使用@EntityScan注解定制文档的扫描位置。

为了解Spring Data MongoDB的全部细节,包括他的丰富的对象映射技术,请查阅他的参考文档。

9.2.3. Neo4j

Neo4j是开源的NoSQL图数据库,其使用丰富的连接节点的数据模型,通过一级关系连接,它比传统的RDBMS方法更适合用于连接大数据。Spring Boot为Neo4j的使用提供了一些方便,包括spring-boot-starter-data-neo4j启动器。

连接Neo4j数据库

为访问Neo4j服务器,你可以注入一个自动配置的org.neo4j.driver.Driver。默认情况下,这个实例在localhost:7687使用Bolt协议尝试连接Neo4j服务器。下方的示例展示了如何注入Neo4jDriver用于给你访问一个Session:

import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.Values;

import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final Driver driver;

    public MyBean(Driver driver) {
        this.driver = driver;
    }

    public String someMethod(String message) {
        try (Session session = this.driver.session()) {
            return session.writeTransaction((transaction) -> transaction
                    .run("CREATE (a:Greeting) SET a.message = $message RETURN a.message + ', from node ' + id(a)",
                            Values.parameters("message", message))
                    .single().get(0).asString());
        }
    }

}

你可以使用spring.neo4j.*属性配置驱动程序的各个方面。下面的示例展示了如何配置uri和凭证的使用:

spring:
  neo4j:
    uri: "bolt://my-server:7687"
    authentication:
      username: "neo4j"
      password: "secret"

使用ConfigBuilder创建自动配置的Driver。为微调他的配置,声明一个或者多个ConfigBuilderCustomizerbean。使用ConfigBuilder按顺序调用每一个用来构建Driver

Spring Data Neo4j Repositories

Spring Data包含支持Neo4j的仓库。为了解Spring Data Neo4j的全部细节,请查阅参考文档。

Spring Data Neo4j和Spring Data JPA共享常用的基础设施正如许多其他Spring Data模块所做的。你可以使用前面的JPA示例并定义City为Spring Data Neo4j @Node而不是JPA@Entity,仓库的方式以相同的方式工作,如下示例所示:

import java.util.Optional;

import org.springframework.data.neo4j.repository.Neo4jRepository;

public interface CityRepository extends Neo4jRepository<City, Long> {

    Optional<City> findOneByNameAndState(String name, String state);

}

spring-boot-starter-data-neo4j启动器启用仓库支持以及事务管理。Spring Boot使用Neo4jTemplate或者ReactiveNeo4jTemplatebean支持经典和响应式Neo4j仓库。当Project Reactor在类路径上可用,响应式风格也自动配置。

你可以通过在@Configuraitonbean上分别使用@EnableNeo4jRepositories@EntityScan定制位置来查找仓库和实体。

在应用程序中使用响应式风格,ReactiveTransactionManager不会自动配置。为启用事务管理,以下bean必须在你的配置中定义:

import org.neo4j.driver.Driver;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;

@Configuration(proxyBeanMethods = false)
public class MyNeo4jConfiguration {

   @Bean
   public ReactiveNeo4jTransactionManager reactiveTransactionManager(Driver driver,
           ReactiveDatabaseSelectionProvider databaseNameProvider) {
       return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);
   }

}

9.2.4. Elasticsearch

Elasticsearch是开源的,分布式的,RESTful查询和解析引擎。Spring Boot为Elasticsearch客户端提供基本的自动配置。

Spring Boot支持几个客户端:

  • 官方Java"低等级"和"高等级"的REST客户端。
  • 通过Spring Data Elasticsearch提供的ReactiveElasticsearchClient

Spring Boot提供一个相关的“启动器”,spring-boot-starter-data-elasticsearch

使用REST client连接Elasticsearch

Elasticsearch提供了两个不同的REST客户端可以用来查询集群:来自org.elasticsearch.client:elasticsearch-rest-client模块的低级别客户端和来自org.elasticsearch.client:elasticsearch-high-level-client模块高级别客户端。此外,Spring Boot对响应式客户端提供支持,基于来自org.springframework.data:spring-data-elasticsearch模块的Spring Framework的WebClient。默认情况下,客户端将指向localhost:9200。你可以使用spring.elasticsearch.*属性更进一步调整如何配置客户端,如下示例所示:

spring:
  elasticsearch:
    uris: "https://search.example.com:9200"
    socket-timeout: "10s"
    username: "user"
    password: "secret"
使用RestClient连接Elasticsearch

如果在类路径中有elasticsearch-rest-client,Spring Boot将自动配置并注册RestClientbean。如果在类路径存在elasticsearch-rest-high-level-client,RestHighLevelClientbean也将自动配置。在Elasticsearch弃用RestHighLevelClient之后,它的自动配置是弃用的并将在未来发布移除。除了前面所描述的属性,为微调RestClientRetHighLevelClient,你可以注册一个随意数量为更高级定制而实现RestClientBuilderCustomizer的bean。为完全控制客户端的配置,定义RestClientBuilderbean。

此外,如果elasticsearch-rest-client-sniffer在类路径中,Sniffer自动配置以发现来自正在运行的Elasticsearch集群的节点并在RestClientbean设置他们。你可以进一步微调Sniffer如何配置,如下示例所示:

spring:
  elasticsearch:
    restclient:
      sniffer:
        interval: "10m"
        delay-after-failure: "30s"
使用ReactiveElasticsearchClient连接Elasticsearch

Spring Data Elasticsearch提供ReactiveElasticsearch,以响应式的方式查询Elasticsearch实例。它建立在WebFlux的WebClient之上,所以spring-boot-starter-elasticsearchspring-boot-starter-webflux依赖项启用这个支持是非常有用的。

默认情况下,Spring Boot将自动配置并注册ReactiveElasticsearchClient。除了前面所描述的属性,spring.elasticsearch.webclient.*属性可以用来配置特性的响应式设置,如下示例所示:

spring:
  elasticsearch:
    webclient:
      max-in-memory-size: "1MB"

如果spring.elasticsearch.spring.elasticsearch.webclient.配置属性是不满足的,你想完全控制客户端配置,你可以注册一个自定义的ClientConfigurationbean。

使用Spring Data连接Elasticsearch

为连接Elasticsearch,必须定义RestHighLevelClientbean,通过Spring Boot自动配置或者通过应用程序(请查看前面的部分)手工提供。有了这个配置,可以像其他Springbean一样注入ElasticsearchRestTempalte,如下示例所示:

import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final ElasticsearchRestTemplate template;

    public MyBean(ElasticsearchRestTemplate template) {
        this.template = template;
    }

    public boolean someMethod(String id) {
        return this.template.exists(id, User.class);
    }

}

在存在spring-data-elasticsearch和所需依赖用于使用WebClient(典型的spring-boot-starter-webflux),Spring Boot也可以自动配置ReactiveElasticsearchClientReactiveElasticsearchTemplate作为bean。他们等价于其他REST客户端。

Spring Data Elasticsearch 仓库

Spring Data包括对Elasticsearch仓库的支持。正如前面讨论的JPA仓库,基本原理是根据方法名自动构造查询。

事实上,Spring Data JPA和Spring Data Elasticsearch共享相同的通用基础设施。你可以使用前面的JPA示例,假设现在CityElasticsearch@Document而不是JPA@Entity,它以相同的方式工作。

为了解Spring Data Elasticsearch的全部细节,请查看参考文档。

Spring Boot支持典型的和响应式的Elasticsearch仓库,使用ElasticsearchRestTemplate或者ReactiveElasticsearchbean。给定所需要的依赖是存在的,很可能大部分这些bean通过Spring Boot自动配置。

如果你希望使用你自己的模板来支持Elasticsearch仓库,你可以添加自己的ElasticsearchRestTemplate或者ElasticesearchOperations的bean,只要它命名为elasticsearchTemplate。使用bean名称reactiveElasticsearchTemplate,同样会应用到ReactiveElasticsearchTemplateReactiveElasticsearchOperations

你可以使用以下属性选择禁用仓库支持:

spring:
  data:
    elasticsearch:
      repositories:
        enabled: false
9.2.5. Cassandra

Cassandra是开源的,分布式数据管理系统被设计为处理跨许多商品服务器的大量数据。Spring Boot为Cassandra提供自动配置和Spring Data Cassandra基于Cassandra提供的实现。spring-boot-starter-data-cassandra启动器用于以非常方便的方式收集依赖项。

连接到Cassandra

你可以注入一个自动配置的CassandraTempalte或者Cassandra的CqlSession实例正如你将使用的任何其他Spring bean。spring.data.cassandra.*属性可以用来定制这个链接。通常,你提供keyspace-namecontact-points以及数据中心的名称,如下示例所示:

spring:
  data:
    cassandra:
      keyspace-name: "mykeyspace"
      contact-points: "cassandrahost1:9042,cassandrahost2:9042"
      local-datacenter: "datacenter1"

如果对于所有的链接端的端口是相同的,你可以使用快捷方式并只指定主机名称,如下示例所示:

spring:
  data:
    cassandra:
      keyspace-name: "mykeyspace"
      contact-points: "cassandrahost1,cassandrahost2"
      local-datacenter: "datacenter1"

这两个示例是完全相同的,因为端口默认为9042。如果你需要配置这个端口,使用spring.data.cassandra.port

Cassandra驱动有它自己的配置基础设施,其在根类路径加载application.conf

默认情况下,Spring Boot不会查找这样的文件但是会使用spring.data.cassandra.config加载一个。如果一个属性同时在spring.data.cassandra.*和配置文件同时存在,在spring.data.cassandra.*的值优先。

对于更高级的驱动自定义,你可以注册随意数量实现DriverConfigLoaderBuilderCustomizer的bean。CqlSession可以使用类型为CqlSessionBuilderCustomizer类型的bean定义。

如果你使用CqlSessionBuilder来创建多个CqlSessionbean,记住构造器是可变的,所以请确保为每一个session注入一个新的副本。

下面的代码列表展示如何注入一个Cassandra bean:

import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final CassandraTemplate template;

    public MyBean(CassandraTemplate template) {
        this.template = template;
    }

    public long someMethod() {
        return this.template.count(User.class);
    }

}

如果你添加你自己CassandraTemplate类型的bean,他将替换默认的。

Spring Data Cassandra 仓库

Spring Data包含对Cassandra基础仓库支持。目前,比前面所讨论的JPA仓库有更多的限制,需要使用@Query注解发现者方法。

为了解Spring Data Cassandra的全部细节,请查阅参考文档。

9.2.6. Couchbase

Couchbase是开源的,分布式的,多模型NoSQL面向文档数据库,它针对交互式应用程序进行了优化。Spring Boot为Couchbase提供了自动配置和通过Spring Data Couchbase提供基于他的实现。有spring-boot-starter-data-couchbasespring-boot-starter-data-couchbase-reactive启动器用于以方便的方式收集依赖项。

连接Couchbase

通过添加Couchbase SDK和一些配置,你可以得到Clusterspring.couchbase.*属性可以用来定制连接。通常,你提供链接字符串,用户名和密码,如下示例所示:

spring:
  couchbase:
    connection-string: "couchbase://192.168.1.123"
    username: "user"
    password: "secret"

它也可以定制一些ClusterEnvironment设置。例如,以下配置改变超时来使用打开一个新的Bucket并启用SSL支持:

spring:
  couchbase:
    env:
      timeouts:
        connect: "3s"
      ssl:
        key-store: "/location/of/keystore.jks"
        key-store-password: "secret"

检查spring.couchbase.env.*属性了解更多细节。为获取更多控制,可以使用一个或者更多ClusterEnvironmentBuilderCustomizerbean。

Spring Data Couchbase 仓库

Spring Data包含为Couchbas提供仓库支持。为了解Spring Data Couchbase的全部细节,请查阅参考文档。

你可以像使用任何其他Spring Bean一样注入一个自动配置CouchbaseTemplate实例,提供的CouchbaseClientFactorybean是可用的。当Cluster是可用的时,如上所述,并bucket名称已经被指定:

spring:
  data:
    couchbase:
      bucket-name: "my-bucket"

以下示例展示了如何注意CouchbaseTemplatebean:

import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final CouchbaseTemplate template;

    public MyBean(CouchbaseTemplate template) {
        this.template = template;
    }

    public String someMethod() {
        return this.template.getBucketName();
    }

}

你可以在你的自己的配置定义一些bean来重写自动配置提供的那些bean:

  • 使用couchbaseMappingContext名称的CouchbaseMappingCoutext@Bean
  • 使用couchbaseCustomConversions名称的CustomConversions@Bean
  • 使用couchbaseTemplate名称的CouchbaseTemplate@Bean

为避免在你自己的配置中硬编码这些名字,你可以重用Spring Data Couchbase提供的BeanName。例如,你可以定制转换器来使用,如下:

import org.assertj.core.util.Arrays;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.BeanNames;
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;

@Configuration(proxyBeanMethods = false)
public class MyCouchbaseConfiguration {

    @Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
    public CouchbaseCustomConversions myCustomConversions() {
        return new CouchbaseCustomConversions(Arrays.asList(new MyConverter()));
    }

}

9.2.7. LDAP

LDAP(Lightweight Directory Access Protocol)是开源的,厂商中立,工业标准的应用程序协议用于通过IP访问和维护分布式目录信息服务。Spring Boot为任意兼容的LDAP服务器提供自动配置以及对来自UnboundID内嵌内存的LDAP服务器提供支持。

通过Spring Data LDAP提供LDAP抽象。spring-boot-starter-data-ldap启动器用于方便的方式收集依赖项。

连接LDAP服务器

为连接LDAP服务器,确保你在spring-boot-starter-data-ldpa启动器上声明依赖项或者spring-ldap-core并且在你的application.properties中声明你服务器的URL,如下示例所示:

spring:
  ldap:
    urls: "ldap://myserver:1235"
    username: "admin"
    password: "secret"

如果你需要定制连接设置,你可以使用spring.ladp.basespring.ldap.base-environment属性。

LdapContextSource是基于这些设置自动配置的,如果DirContextAuthenticationStrategybean可用,它会自动配置的LdapContextSource相关联。如果你需要定制它,例如使用PooledContextSource,你可以注入自动配置LadpContextSource。确保将定制的ContextSource标记为@Primary以便自动配置的LdapTemplate使用它。

Spring Data LDAP仓库

Spring Data包括对LDAP仓库支持。要了解Spring Data LDAP完整详情,请查阅参考文档。

你也可以注入一个自动配置的LdapTemplate实例,就像使用其他Spring Bean一样,如下示例所示:

import java.util.List;

import org.springframework.ldap.core.LdapTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final LdapTemplate template;

    public MyBean(LdapTemplate template) {
        this.template = template;
    }

    public List<User> someMethod() {
        return this.template.findAll(User.class);
    }

}
内嵌的内存LDAP服务器

出于测试目的,Spring Boot支持来自UnboundID的内存服务器的自动配置。为配置服务器,添加一个依赖到com.unboudid:unboundid-ldapsdk和声明spring.ldap.embedded.base-dn属性,如下:

spring:
  ldap:
    embedded:
      base-dn: "dc=spring,dc=io"

它可以定义多个基于db的值,然而,因为标志名称通常包含逗号,他们必须使用正确的表示法来定义。

在yaml文件,你可以使用yaml列表符号。在properties文件,你必须包含索引作为属性名的一部分
Properties

spring.ldap.embedded.base-dn[0]=dc=spring,dc=io
spring.ldap.embedded.base-dn[1]=dc=pivotal,dc=io

Yaml

spring.ldap.embedded.base-dn:
 - "dc=spring,dc=io"
 - "dc=pivotal,dc=io"

默认情况下,使用随机端口服务器启动并触发常规的LDAP支持。不需要指定spring.ldap.urls属性。

如果在类路径中存在schemo.ldif文件,它用来初始化服务器。如果你想从不同的资源加载初始化脚本,你也可以使用spring.ldap.embedded.ldif属性。

默认情况下,标准的模式用来校验LDIF文件。你可以设置spring.ldap.embedded.validataion.enabled属性来完全关闭验证。如果你有自定义属性,你可以使用spring.ldap.embedded.validation.schema来定义你自定义的属性类型或者类对象。

9.2.8. InfluxDB

InfluxDB是开源的,时间序列的数据库,针对操作监控,应用程序指标,物联网传感器数据和实时分析等领域的时间序列数据进行了快速、高可用存储的优化。

连接InfluxDB

Spring Boot自动配置一个InfluxDB实例,提供influxdb-java客户端在类路径并且设置数据库URL,如下示例所示:

spring:
  influx:
    url: "https://172.0.0.1:8086"

如果连接到InfluxDB需要用户和密码,你可以直接设置spring.influx.userspring.influx.password属性。

InfluxDB依赖OkHttp。如果你需要底层调整http客户端InfluxDB使用,你可以注册InfluxDbOkHttpClientBuilderProviderbean。

如果你需要控制配置,考虑注册InfluxDbCustomizerbean。

9.3. 下一步读什么

现在你应该熟悉如何使用Spring Boot与多种data技术。至此,你可以阅读关于Spring Boot对多种消息技术的支持并如何在你的应用程序中启用他们。

10. 消息

Spring Framework与消息系统集成提供了广泛的支持,从使用JmsTempalte简化JMS API到完整基础设施来异步接收消息。Spring AMQP提供一个用于高级消息队列协议(Advanced Message Queuing Protocol)类似的特性集合。Spring Boot为RabbitTemplate和RabbitMQ也提供自动配置选项。Spring WebSocket本身就包含对STOMP消息的支持,并且Spring Boot通过启动器和小数量的自动配置提供对STOMP的支持。Spring Boot也对Apache Kafka提供支持。

10.1 JMS

javax.jms.ConnnectionFactory接口提供了一个创建与JMS borker交互的javax.jms.Connnection的标准方法。尽管Spring需要ConnectionFactory以便与JMS工作,你通常不需要你自己直接使用它并且可以改为依赖更高级别的消息抽象。(请查阅Spring Framework参考文档相关的章节了解细节)。Spring Boot也自动配置必须的基础设施以发送和接收消息。

10.1.1. ActiveMQ Artemis支持

当ActiveMQ Artemis在类路径中可用时,Spring Boot可以自动配置ConnectionFactory。如果broker存在,内嵌的broker自动启动并配置(除非这模式属性已经明确设置)。支持的模式是embedded(为明确内嵌的broker是必须的,如果在类路径中broker不可用将发生一个错误。)和native(使用netty传输协议连接broker)。当配置后者时,Spring Boot配置一个ConnectionFactory用于使用默认的设置链接运行在本地机器的broker。

如果你使用spring-boot-starter-artemis,提供连接到现有的ActiveMQ Artemis实例的必须的依赖项 ,以及与JMS集成的Spring基础设施。添加org.apache.activemq:artemis-jms-server到你的应用程序允许你使用内嵌的模式。

通过在spring.artemis.*外部配置属性控制ActiveMQ Artemis配置。例如,你可以在application.properties声明以下部分:

spring:
  artemis:
    mode: native
    broker-url: "tcp://192.168.1.210:9876"
    user: "admin"
    password: "secret"

当内嵌broker时,你可以选择是否启用持久化,并列出应该可用的目的地。这些可以被指定为一个逗号分隔的列表来使用默认的选项创建他们,或者你可以为高级的队列和主题配置依次定义org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration或者org.apache.activemq.artemis.jms.server.config.TopicConfiguration类型的bean(s)。

默认情况下,CachingConnectionFactory使用合理的设置封装本地ConnectionFactory,你可以通过外部配置属性spring.jms.*合理的配置:

spring:
  jms:
    cache:
      session-cache-size: 5

如果你更愿意使用本地池,你可以直接通过添加org.messaginghub:pooled-jms依赖和配置JmsPoolConnectionFactory,如下示例所示:

spring:
  artemis:
    pool:
      enabled: true
      max-connections: 50

请查阅ArtemisProperties了解更多支持的选项。

不涉及JNDI查找,通过他们的名称解析目的地,使用Artemis配置中的name属性或者通过配置提供的名称。

10.1.2 使用JNDI ConnectionFactory

如果你正在应用程序服务器内运行你的应用程序,Spring Boot尝试通过使用JNDI定义一个JMSConnectionFactory。默认情况下,检查java:/JmsXAjava:/XAConnectionFactory位置。如果你需要指定一个可代替的位置,你可以使用spring.jms.jndi-name属性,如下示例所示:

spring:
  jms:
    jndi-name: "java:/MyConnectionFactory"

10.1.3. 发送消息

Spring的JmsTemplate是自动配置的,你可以直接自动装配它到你自己的bean,如下示例所示:

import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final JmsTemplate jmsTemplate;

    public MyBean(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void someMethod() {
        this.jmsTemplate.convertAndSend("hello");
    }

}

JmsMessagingTemplate可以以类似的方式注入。如果DestinationResolver或者MessageConverterbean已经定义,它自动与自动配置的JmsTempalte相关联。

10.1.4. 接收消息

当JMS基础设施存在时,任何使用JmsListener注解的bean来创建监听器端。如果没有JmsListenerContainerFactory定义,默认的一个自动配置。如果DestinationResolverMessageConverter或者javax.jms.ExceptionListenerbean被定义,他们自动与默认的工厂关联。

默认情况下,默认的工厂是事务的。如果在JtaTransactionManager存在的基础设施中运行,默认情况下,他关联到监听者容器。如果不存在,启用sessionTransacted标志。在后者的场景,你可以通过添加@Transactional在你的监听器方法(或其委托)上将本地数据存储事务与传入消息的处理关联起来。一旦本地事务已经完成,这样确保传入的消息是证实的。这也包含在相同的JMS会话中已经执行发送响应消息。

下方的组件在someQueue目的地创建一个监听器端点:

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @JmsListener(destination = "someQueue")
    public void processMessage(String content) {
        // ...
    }

}

请查阅@Enable的Javadoc了解更多详情。

如果你需要创建更多的JmsListenerContainerFactory实例或者你想重写默认的,Spring Boot提供DefaultJmsListenerContainerFactoryConfigurer,你可以使用和自动配置相同的设置来初始化DefaultJmsListenerContainerFactory

例如,下面的示例公开使用特定的MessageConverter的另外一个工厂:

import jakarta.jms.ConnectionFactory;

import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;

@Configuration(proxyBeanMethods = false)
public class MyJmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory myFactory(DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        ConnectionFactory connectionFactory = getCustomConnectionFactory();
        configurer.configure(factory, connectionFactory);
        factory.setMessageConverter(new MyMessageConverter());
        return factory;
    }

    private ConnectionFactory getCustomConnectionFactory() {
        return ...
    }

}

然后你可以在任何带有@JmsListener方法中使用工厂,如下:

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @JmsListener(destination = "someQueue", containerFactory = "myFactory")
    public void processMessage(String content) {
        // ...
    }

}

10.2. AMQP

高级消息队列协议(Advanced Message Queuing Protocol:AMQP)是跨平台,底层协议的面向消息的中间件。Spring AMQP项目应用核心的Spring概念来进行基于AMQP消息开发的解决方案。Spring Boot 通过RabbitMQ使用AMQP提供了一些便利,包括spring-boot-starter-amqp启动器。

10.2.1. RabbitMQ支持

RabbitMQ是轻量级,可靠的,基于AMQP协议可移植消息的broker。Spring使用RabbitMQ通过AMQP协议来传递信息。

通过使用spring.rabbitmq.*外部配置属性提供RabbitMQ配置。例如,你可以在application.properties中声明以下部分:

spring:
  rabbitmq:
    host: "localhost"
    port: 5672
    username: "admin"
    password: "secret"

或者,你可以使用addresses属性配置相同的链接:

spring:
  rabbitmq:
    addresses: "amqp://admin:secret@localhost"

当指定这个方式的地址,hostport属性是忽略的。如果这个地址使用amqps协议,SSL支持自动启用。

请查阅RabbitProperties了解更多的支持的基于属性的配置选项。为配置SpringAMAP使用的RabbitMQConnectionFactory的低级别明细,定义一个ConnnectionFactoryCustomizerbean。

如果在上下文中ConnectionNameStrategybean存在,它将自动用于命名由自动配置CachingConnnectionFactory创建的链接。

请查阅理解AMQP,RabbitMQ使用的协议了解更多详情。

10.2.2. 发送消息

Spring的AmqpTemplateAmqpAdmin是自动配置的,并且你可以直接自动装配他们到你自己的bean,如下示例所示:

import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final AmqpAdmin amqpAdmin;

    private final AmqpTemplate amqpTemplate;

    public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
        this.amqpAdmin = amqpAdmin;
        this.amqpTemplate = amqpTemplate;
    }

    public void someMethod() {
        this.amqpAdmin.getQueueInfo("someQueue");
    }

    public void someOtherMethod() {
        this.amqpTemplate.convertAndSend("hello");
    }

}

RabbitMessagingTemplate可以以类似的方式注入。如果MessageConverterbean已经定义,它将自动与自动配置的AmqpTemplate关联。

如果必须,任何已经定义为一个bean的org.springframework.amqp.core.Queue自动用来在RabbitMQ实例声明一个相对应的队列。

为重试操作,你可以在AmqpTempalte上启用重试(例如,在borker连接丢失的时间中):

spring:
  rabbitmq:
    template:
      retry:
        enabled: true
        initial-interval: "2s"

默认情况下,重试是禁用的。你也可以通过声明RabbitRetryTemplateCustomizerbean程序化定制RetryTemplate

如果你需要创建更多的RabbitTemplate实例或者如果你想重写默认的,Spring Boot提供RabbitTemplateConfigurerbean,你可以用来初始化RabbitTemplate,其使用了和使用自动配置的工厂相同的设置。

10.2.3. 发送消息到流

为发送消息到一个特定的流,指定流的名称,如下示例所示:

spring:
  rabbitmq:
    stream:
      name: "my-stream"

如果MessageConverter,StreamMessageConverter或者ProducerCustomizerbean已经定义,他将自动与自动配置的RabbitStreamTemplate关联。

如果你需要创建更多的RabbitStreamTemplate示例或者如果你想重写默认值,Spring Boot提供RabbitStreamTemplateConfigurerbean,你可以使用和与自动配置的工厂相同的配置初始化RabbitStreamTemplate

10.2.4. 接受一个消息

当Rabbit基础设施存在时,任何bean可以使用@RabbitListener注解创建监听器端。如果没有RabbitListenerContainerFactory已经定义,默认的SimpleRabbitListenerContainerFactroy自动配置并且你可以使用spring.rabbit.listener.type属性转换到一个直接的容器。如果MessageConverter或者MessageRecovererbean已经定义,它将自动与默认的工厂关联。

下方的示例组件在someQueue队列创建了一个监听器端:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @RabbitListener(queues = "someQueue")
    public void processMessage(String content) {
        // ...
    }

}

请查看@EnableRabbit的Javadoc了解更多详情。

如果你需要创建更多的RabbitListenerContainerFactory示例或者如果你想重写默认值,Spring Boot提供SimpleRabbitListenerContainerFactoryConfigurerDirectRabbitListenerContainerFactoryConfigurer,你可以使用与自动配置的工厂相同设置初始化SimpleRabbitListenerContainerFactoryDirectRabbitListenerContainerFactory

他不关注你选择的容器类型。通过自动配置公开这两个bean.

例如,下方的配置类公开另外使用特定的MessageConverter一个工厂:

import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyRabbitConfiguration {

    @Bean
    public SimpleRabbitListenerContainerFactory myFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        ConnectionFactory connectionFactory = getCustomConnectionFactory();
        configurer.configure(factory, connectionFactory);
        factory.setMessageConverter(new MyMessageConverter());
        return factory;
    }

    private ConnectionFactory getCustomConnectionFactory() {
        return ...
    }

}

然后你可以在任何带有注解@RabbitListener的方法上使用这个工厂,如下:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @RabbitListener(queues = "someQueue", containerFactory = "myFactory")
    public void processMessage(String content) {
        // ...
    }

}

你可以启动重试来处理你的监听器抛出一个异常的解决方案。默认情况下,使用RejectAndDontRequestRecoverer,但是你可以定义你自己的MessageRevoverer。如果broker被配置这样做,当重试耗尽时,拒绝消息并且丢弃或者路由到死信交换器。默认情况下,重试是禁用的。你也可以通过声明RabbitRetryTemplateCustomizerbean程序化定制RetryTemplate

默认情况下,如果重试是禁用的并且监听器抛出一个异常,交付则无限期重试。你可以以两种方式修改这种行为:设置defaultRequeueRejected属性为false以便尝试零重新提交或者抛出AmqpRejectAndDontRequeueException来标志消息应该被拒绝。后者是在启用重试并达到最大传递尝试次数时使用的机制。

10.3. Apache Kafka支持

Apache Kafka通过提供spring-kafka项目的自动配置提供支持。

通过使用spring.kafka.*外部化配置属性控制Kafka配置。例如,你可以在application.properties声明以下章节:

spring:
  kafka:
    bootstrap-servers: "localhost:9092"
    consumer:
      group-id: "myGroup"

为在启动时创建主体,添加了类型为NewTopic的bean。如果这个主题已经存在,忽略这个bean。

请查看KafkaProperties了解更多支持的选项。

10.3.1. 发送消息

Spring的KafkaTemplate是自动配置的,并且你可以直接自动装载它到你自己的bean,如下示例所示:

import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final KafkaTemplate<String, String> kafkaTemplate;

    public MyBean(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void someMethod() {
        this.kafkaTemplate.send("someTopic", "Hello");
    }

}

如果属性spring.kafka.producer.transaction-id-prefix被定义,KafkaTransactionManager是自动配置。同时,如果RecordMessageConverterbean已经定义,它会自动与自动配置的KafkaTemplate关联。

10.3.2. 接受消息

当Apache Kafka基础设施存在,任何使用@KafkaListener注解的bean创建了一个监听器端。如果没有KafkaListenerContainerFactory已经定义,将使用在spring.kafka.listener.*中定义的key自动配置默认的一个。

以下组件在someTopic主题,创建一个监听器端:

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @KafkaListener(topics = "someTopic")
    public void processMessage(String content) {
        // ...
    }

}

如果定义一个KafkaTransactionManagerbean,它将自动与容器工厂关联。类似地,如果定义了RecordFilterStrategy,CommonErrorHandler,AfterRollbackProcessor或者ConsumerAwareRebalanceListenerbean,它将自动与默认的工厂关联。

依据监听器类型,RecordMessageConverter或者BatchMessageConverterbean与默认的工厂关联。如果只有一个用于批量监听器RecordMessageConverterbean存在,将使用BatchMessageConveter封装它。

自定义的ChaindKafkaTransactionManager必须被标记为@Primary,因为它通常引用自动配置的KafkaTransactionManagerbean。

10.3.3. Kafka流

用于Apache Kafka的Spring提供工厂bean创建StreamBuilder对象并管理它的流的生命周期。只要kafka-streams在类路径中,Spring Boot自动配置所需要的KafkaStreamsConfigurationbean并且Kafka Stream通过@EnableKafkaStreams注解启用。

启用Kafka流意味着必须设置应用程序id和引导服务器。前者使用spring.kafka.streams.application-id配置,如果没有设置默认使用spring.application.name。后者可以全局设置或者专门为流覆盖。

使用专用的属性可以获得几个额外的属性;其他任意Kafka属性可以使用spring.kafka.streams.properties命名空间设置。请查阅额外的Kafka属性了解更多信息。

为使用工厂bean,将StreamsBuilder连接到@Bean,如下示例所示:

import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KeyValue;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.Produced;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafkaStreams;
import org.springframework.kafka.support.serializer.JsonSerde;

@Configuration(proxyBeanMethods = false)
@EnableKafkaStreams
public class MyKafkaStreamsConfiguration {

    @Bean
    public KStream<Integer, String> kStream(StreamsBuilder streamsBuilder) {
        KStream<Integer, String> stream = streamsBuilder.stream("ks1In");
        stream.map(this::uppercaseValue).to("ks1Out", Produced.with(Serdes.Integer(), new JsonSerde<>()));
        return stream;
    }

    private KeyValue<Integer, String> uppercaseValue(Integer key, String value) {
        return new KeyValue<>(key, value.toUpperCase());
    }

}

默认情况下,由它创建的StreamBuilder对象管理的流是自动启动的。你可以使用spring.kafka.streams.auto-startup属性定制这种行为。

10.3.4. 额外的Kafka属性

自动配置支持的属性是展示在附录中的“集成属性”章节中的。注意,对于大多数部分,这些属性(带有连字符或者驼峰)直接映射到Apache Kafka带有逗号的属性。请查阅Apache Kafka文档了解详情。

最开始这些属性的几个适用所有组件(生产者,消费者,管理员和流)但是如果希望使用不同的值,可以在组件级别指定。Apache Kafka使用非常重要的HIGH,MEDIUM或者LOW指定属性。Spring Boot自动配置支持所有的HIGH重要属性,一些选中的MEDIUM和LOW属性,以及任何没有默认值属性。

只有Kafka支持的这些属性的子集可以通过KafkaProperties类直接获取。如果你希望使用不直接支持的额外的属性配置生产者或者消费者,使用以下属性:

spring:
  kafka:
    properties:
      "[prop.one]": "first"
    admin:
      properties:
        "[prop.two]": "second"
    consumer:
      properties:
        "[prop.three]": "third"
    producer:
      properties:
        "[prop.four]": "fourth"
    streams:
      properties:
        "[prop.five]": "fifth"

这个设置普通的prop.oneKafka属性为first(应用到生产者,消费者和管理者),prop.twoadmin属性为second,prop.three consumer属性为thirdprop.four生产者属性为fourthprop.fivestream 属性为fifth

你也可以如下配置Spring KafkaJsonDeserializer

spring:
  kafka:
    consumer:
      value-deserializer: "org.springframework.kafka.support.serializer.JsonDeserializer"
      properties:
        "[spring.json.value.default.type]": "com.example.Invoice"
        "[spring.json.trusted.packages]": "com.example.main,com.example.another"

类似地,你可以禁用JsonSerializer在数据头发送类型信息的默认行为:

spring:
  kafka:
    producer:
      value-serializer: "org.springframework.kafka.support.serializer.JsonSerializer"
      properties:
        "[spring.json.add.type.headers]": false

这种方式的属性设置覆盖Spring Boot明确支持的任何配置项。

10.3.5. 使用内嵌Kafka测试

用于Apache Kafka的Spring 提供了方便的方式测试使用内嵌的Apache Kafka broker的项目。为使用这个特性,使用来自spring-kafka-test模块@EnbeddedKafka注解一个测试类。对于更多信息,请查阅用于Apache Kafka参考手册。

为使Spring Boot自动配置与上述的内嵌Apache Kafka broker一起工作,你需要将内嵌broker地址的系统属性(由EmbeddedKafkaBorker填充)重新映射到Apache Kafka的Spring Boot配置属性。几种方式可以做到这些:

  • 提供系统属性以将内嵌的broker地址映射到测试类中的spring.kafka.bootstrap-servers:
static {
    System.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, "spring.kafka.bootstrap-servers");
}
  • @EmbeddedKafka注解上配置属性名称:
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.test.context.EmbeddedKafka;

@SpringBootTest
@EmbeddedKafka(topics = "someTopic", bootstrapServersProperty = "spring.kafka.bootstrap-servers")
class MyTest {

    // ...

}
  • 在配置文件中使用占位符
spring:
  kafka:
    bootstrap-servers: "${spring.embedded.kafka.brokers}"

10.4. RSocket

RSocket是二进制协议用在字节流传输。它通过在单个连接上传递异步消息来支持对称交互模型。

Spring Framework的spring-messaging模型在客户端和消费端对RSocket请求者和响应者提供支持。请查看Spring Framework仓考的RSocket部分了解更多详情,包括RSocket协议概览。

10.4.1. RSocket 自动配置策略

Spring Boot自动配置一个RSocketStrategiesbean,为编码和解码RSocket负载提供了所有的基础设施。默认情况下,自动配置将尝试配置以下内容(按照顺序):

  1. 使用Jackson进行CBOR编码
  2. 使用Jackson进行JSON编码

spring-boot-starter-rsocket启动器提供两者依赖。请查看Jackson支持部分了解更多关于定制可能性。

开发者通过创建实现了RSocketStrategiesCustomizer接口的bean可以定制RSocketStrategies组件。注意他们的@Order是重要的,因为它决定编码的顺序。

10.4.2. RSocket服务器自动配置

Spring Boot提供RSocket服务器自动配置。通过spring-boot-starter-rsocket提供需要的依赖项。

Spring Boot允许从WebFlux服务器通过WebSocket暴露RSocket,或者建立一个独立的RSocket服务器。这个依据应用程序的类型和它的配置。

对于WebFlux应用程序(这个是WebApplicationType.REACTIVE类型),只有以下属性匹配时,RSocket服务器将才会被插入到Web服务器:

spring:
  rsocket:
    server:
      mapping-path: "/rsocket"
      transport: "websocket"

只有使用Reactor Netty支持将RSocket插入到web服务器,因为RSocket它自己使用这个类库构建的。

或者,RSocket TCP或者websocket服务器作为独立内嵌服务器启动的。除了依赖项的需求外,仅需要的配置是定义服务器的端口:

spring:
  rsocket:
    server:
      port: 9898

10.4.3. Spring Messaging RSocket支持

Spring Boot将为RSocket自动配置Spring Messaging基础设施。

这表示Spring Boot将创建RSocketMessageHandlerbean,将处理对应用程序的RSocket请求。

10.4.4. 使用RSocketRequester调用RSocket Service

一旦RSocket频道已经在服务器和客户端确定,任意一方可以发送或者接受到另一方的请求。

作为服务器,你可以在任意RSocket的@Controller的处理方法上注入RScoketRequester实例。作为客户端,首先你需要配置和简历RSocket连接。Spring Boot使用期望的编解码器为这种情况自动配置一个RSocketRequest.Builder并应用任何RSocketConnectorConfigurerbean。

RSocketRequester.Builder实例是原型bean,表示每个注入点都将提供一个新的实例。这样做是有目的的,是因为这个构造器是有状态的,你不应该使用相同的实例创建具有不同的设置的requester。

下方的代码展示了典型的示例:

import reactor.core.publisher.Mono;

import org.springframework.messaging.rsocket.RSocketRequester;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private final RSocketRequester rsocketRequester;

    public MyService(RSocketRequester.Builder rsocketRequesterBuilder) {
        this.rsocketRequester = rsocketRequesterBuilder.tcp("example.org", 9898);
    }

    public Mono<User> someRSocketCall(String name) {
        return this.rsocketRequester.route("user").data(name).retrieveMono(User.class);
    }

}

10.5. Spring Integration

Spring Boot为与Spring Integration一起工作提供了多种方便,包括spring-boot-starter-integration启动器。Spring Integration提供消息和其他传输协议,比如HTTP,TCP等抽象。如果Spring Integration在类路径中可用,通过@EnableIntegration注解初始化。

Spring Integration轮询逻辑依据自动配置的TaskScheduler。默认的PollerMetadata(每秒钟轮询无数次消息)可以使用spring.integration.poller.*配置属性定制。

Spring Boot也配置一些特性,这些特性通过额外的Spring Integration模块触发。如果spring-integration-jmx也在类路径中,消息处理统计信息通过JXM发布。如果spring-integration-jdbc可用,默认的数据库模式在启动时创建,如下行所示:

spring:
  integration:
    jdbc:
      initialize-schema: "always"

如果spring-integration-rsocket是可用的,开发者可以使用spring.rsocket.server.*属性配置一个RSocket服务器并允许它使用IntegrationRSocketEndpoint或者RSocketOutboundGateway组件处理传入RSocket消息。
这个基础设施可以处理Spring Integration RSocket通道适配器和@MessageMapping处理器(给定的"spring.integration.rsocket.server.message-mapping-enable"已经配置)。

Spring Boot也可以使用配置属性自动配置ClientRSocketConnector

# Connecting to a RSocket server over TCP
spring:
  integration:
    rsocket:
      client:
        host: "example.org"
        port: 9898
# Connecting to a RSocket Server over WebSocket
spring:
  integration:
    rsocket:
      client:
        uri: "ws://example.org"

请查看IntegrationAutoConfigurationIntegrationProperties类了解更多详情。

10.6. WebSocket

Spring Boot对内嵌的tomcat,Jetty和Undertow提供WebSocket自动配置。如果你发布一个war文件到独立运行的容器,Spring Boot假设容器负责配置其WebSocket支持。

Spring Framework对MVCweb应用程序提供丰富的WebSocket支持,可以通过spring-boot-starter-websocket模块非常容易进行访问。

WebSocket支持对于响应式web应用程序也是可用的,需要包括WebSocket API与spring-boot-starter-webflux一起:

<dependency>
    <groupId>javax.websocketgroupId>
    <artifactId>javax.websocket-apiartifactId>
dependency>

10.7 下一步读什么

下一章节描述在应用程序中如何启用IO功能。你可以在这个章节中读关于caching,mail,validation,rest clients或者更多的内容。

11. IO

大多数应用程序在某些时候都需要处理输入和输出。当你需要IO功能的时候,Spring Boot提供工具和集成一系列技术来提供帮助。这个章节包含标准的IO特性比如缓存和校验以及更高级主题比如定时和分布式事务。我们也将包含调用远程REST或者SOAP服务和发送email。

11.1. 缓存

Spring Framework对显示的添加缓存到应用程序提供支持。其核心是,抽象将缓存应用到方法,从而根据缓存中可用的信息减少执行次数。缓存逻辑的应用是透明的,不会对调用者造成任何干扰。只要通过使用@EnableCaching注解启用缓存支持,Spring Boot自动配置缓存的基础设施。

查看Spring Framework的相关章节了解更多详情。

简言之,为添加缓存到服务的操作中, 请将相关的注解一个到它的方法中,如下示例所示:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

@Component
public class MyMathService {

    @Cacheable("piDecimals")
    public int computePiDecimal(int precision) {
        ...
    }

}

这个示例演示了在可能开销较大的操作上使用缓存。在调用computePiDecimal之前,这个抽象查找匹配i参数piDecimals缓存入口。如果找到入口,在缓存中的内容立即返回给调用者,并且这个方法不会被调用。否则,调用这个方法,并且在返回值之前更新缓存。

你也可以显示地使用标准的JSR-107(JCache)注解(比如@CacheResult)。然而,我们强烈建议你不要混合使用Spring Cache和JCache注解。

如果你不添加任何特定的缓存类库,Spring Boot自动配置一个简单的提供者,在存储上使用并行map。当需要一个缓存时(例如前面例子中的piDecimals),这个提供者为你创建它。这个简单的提供者不建议在生产中使用,但是他是比较好的入门并确保你理解这个特性。当你已经想好使用缓存提供者,请务必阅读它的文档,弄清楚如何配置应用程序使用的缓存。几乎所有的提供者需要你明确配置每一个在应用程序中使用的缓存。有些提供了一种方式通过spring.cache.cache-names属性来定制已定义的默认缓存。

他也可以显性地更新或者从缓存中移除数据。

11.1.1. 支持的缓存提供者

缓存抽象不是提供一个真实的存储并依赖于org.springframework.cache.Cacheorg.springframework.cache.CacheManager接口的实现抽象。

如果你没有定义CacheManager或者命名为cacheResolverCacheResolver(请看CachingConfigurer),Spring Boot尝试检测以下提供者(按照表明的顺序):

  1. Generic
  2. JCache(JSR-107)(EhCache 3,Hazelcast和其他)。
  3. Hazelcast
  4. Couchbase
  5. Redis
  6. Caffeine
  7. Cache2k
  8. Simple
    或者,用于Apache Geode的Spring Boot提供自动配置用于使用Apache Geode作为缓存提供者

它也可能通过设置spring.cache.type属性强制提供一个特别的缓存。如果你需要在某一环境(比如测试)完全禁用缓存请使用这个属性。

使用spring-boot-starter-cache启动器快速添加基本的缓存依赖项。启动器引入spring-context-support。如果你手工添加依赖,你必须包含spring-context-support为了使用JCache或者Caffeine支持。

如果CacheManager通过Spring Boot自动配置,在完全初始化之前,你可以通过公开一个实现CacheManagerCustomizer接口的bean在进一步调整他的配置。下方的示例设置了一个标志,表示null值不应该传入到底层映射:

import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCacheManagerConfiguration {

    @Bean
    public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
        return (cacheManager) -> cacheManager.setAllowNullValues(false);
    }

}

在前面的示例中,需要一个自动配置的ConcurrentMapCacheManager。如果不是这样的话(或者你提供你自己的配置或者自动配置了不同的缓存提供者),则定制器根本不会被调用。你可以拥有任意数量的定制器,你也可以使用@Order或者Ordered对他们进行排序。

Generic

如果上下文定义了至少一个org.springframework.cache.Cachebean则会使用Generic缓存。CacheManager包装所有创建该类型的bean。

JCache(JSR-107)

通过类路径中的javax.cache.spi.CachingProvider(也就是说,类路径上存在符合JSR-107缓存库)启动JCache ,并且通过spring-boot-starter-cache启动器提供JCacheCacheManager。多种符合的类库是可用的,Spring Boot为Ehcache 3和Hazelcast提供依赖管理。也可以添加任何其他的符合类库。

可能发生存在超过一个提供者的情况,这种情况提供者必须明确指定。即使JSR-107标准没有实施标准化的方式来定义配置文件的位置,Spring Boot尽最大努力通过实现细节设置一个缓存,如下示例所示:

# Only necessary if more than one provider is present
spring:
  cache:
    jcache:
      provider: "com.example.MyCachingProvider"
      config: "classpath:example.xml"

当一个缓存类库提供本身实现和JSR-107支持,Spring Boot更倾向于JSR-107支持,以便如果你改变到一个不同的JSR-107实现,相同的特性是可用的。

Spring Boot对Hazelcast提供常规支持。如果单独的HazelcastInstance是可用的,它也会被CacheManager自动重用,除非指定了spring.cache.jcache.config属性。

有两种方式定制底层的javax.cache.cacheManager

  • 通过设置spring.cache.cache-names属性,在启动时可以创建Cache。如果一个自定义的javax.cache.configuration.Configurationbean已经定义,使用它定制他们。
  • org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizerbean通过引用CacheManager来进行完全定制的。

如果一个标准的javax.cache.CacheManagerbean被定义,它自动包装在抽象所期望的org.springframework.cache.CacheManager实现中。没有对其应用任何进一步的定制。

Hazelcast

Spring Boot存在对Hazelcast的常规支持。如果一个HazelcastInstance已经自动配置,它自动封装在CacheManager

Couchbase

如果Spring Data Couchbase是可用的并且Couchbase已经配置,CouchbaseCacheManager则自动配置。可以通过设置spring.cache.cache-name属性启动时创建额外的缓存并且使用spring.cache.couchbase.*属性配置默认缓存。例如,下面的配置创建了条目过期时间为10分钟的cache1cache2缓存:

spring:
  cache:
    cache-names: "cache1,cache2"
    couchbase:
      expiration: "10m"

如果你需要更多控制配置,考虑注册CouchbaseCacheManagerBuilderCustomizerbean。以下示例展示了配置了特定的条目过期时间的cache1cache2的定制:

import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyCouchbaseCacheManagerConfiguration {

    @Bean
    public CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() {
        return (builder) -> builder
                .withCacheConfiguration("cache1", CouchbaseCacheConfiguration
                        .defaultCacheConfig().entryExpiry(Duration.ofSeconds(10)))
                .withCacheConfiguration("cache2", CouchbaseCacheConfiguration
                        .defaultCacheConfig().entryExpiry(Duration.ofMinutes(1)));

    }

}
Redis

如果Redis是可用的并且已经配置,RedisCacheManager是自动配置的。可以通过设置spring.cache.cache-name属性启动时创建额外的缓存,通过使用spring.cache.redis.*属性配置默认缓存。例如,下面的配置创建了存活时间为10分钟的cache1cache2缓存:

spring:
  cache:
    cache-names: "cache1,cache2"
    redis:
      time-to-live: "10m"

通过添加你自己的RedisCacheConfigurationbean,你可以完全控制默认的配置。如果你需要定制默认的序列化策略的话这个是非常有用的。

如果你需要更多的控制,考虑注册RedisCacheManagerBuilderCustomizerbean。下面的示例展示了配置指定存活时间的cache1cache2的定制:

import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyRedisCacheManagerConfiguration {

    @Bean
    public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
        return (builder) -> builder
                .withCacheConfiguration("cache1", RedisCacheConfiguration
                        .defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
                .withCacheConfiguration("cache2", RedisCacheConfiguration
                        .defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));

    }

}
Caffeine

Caffeine是Java 8 Guava的缓存重写的,取代了Guava支持。如果Caffeine存在,CaffeineCacheManagerspring-boot-starter-cache启动器提供)自动配置。通过设置spring.cache.chache-names属性Cache在启动时创建并通过以下其中一种方式定制(按照指定的顺序):

  1. spring.cache.caffeine.spec定义的spec缓存。
  2. 定义com.github.benmanes.caffeine.cache.CaffeineSpecbean。
  3. 定义com.github.benmanes.caffeine.cache.Caffeine
    例如,以下配置创建了500最大长度和10分钟存活的cache1cache2缓存:
spring:
  cache:
    cache-names: "cache1,cache2"
    caffeine:
      spec: "maximumSize=500,expireAfterAccess=600s"

如果com.github.benmanes.caffeine.cache.CacheLoaderbean被定义,将自动与CaffeineCacheManager关联。因为CacheLoader将通过缓存管理器与所有的管理的缓存关联,它必须被定义为CacheLoader。自动配置任何忽略泛型。

Cache2k

Cache2k是一个内存缓存。如果Cache2k spring 集成存在,SpringCache2kCacheManager是自动配置的。

通过设置spring.cache.cache-name属性在启动时创建缓存。通过使用Cache2kBuilderCustomizerbean可以定制默认的缓存。以下示例展示配置了容量为200条目的缓存并且过期时间5分钟的定制:

import java.util.concurrent.TimeUnit;

import org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCache2kDefaultsConfiguration {

    @Bean
    public Cache2kBuilderCustomizer myCache2kDefaultsCustomizer() {
        return (builder) -> builder.entryCapacity(200)
                .expireAfterWrite(5, TimeUnit.MINUTES);
    }

}
Simple

如果没有发现其他提供者,一个简单的实现使用ConcurrentHashMap作为缓存存储被配置。如果应用程序中没有缓存类库存在则使用这个默认的。默认情况下,缓存根据所需创建的,但是如果你可以通过设置cache-names属性限制可用缓存的列表。例如,如果你只想cache1cache2缓存,设置如下cache-names属性:

spring:
  cache:
    cache-names: "cache1,cache2"

如果你这样做,并且你的应用程序使用了未列出的缓存,然后当需要缓存时,运行时失败,并不是在启动的时候。如果使用未声明的缓存,这就类似于“真正”的缓存提供者的行为。

None

当你的配置中@EnableCaching存在时,也需要一个合适的缓存配置。如果你需要在某一环境中完全禁用缓存,强制缓存类型为none以使用无操作的实现,如下示例所示:

spring:
  cache:
    type: "none"

11.2. Hazelcast

如果Hazelcast在类路径中并且发现可用的配置,Spring Boot自动配置HazelcastInstance,你可以将其注入到应用程序。

Spring Boot首先通过检查以下配置选项,尝试创建一个客户端:

  • com.hazelcast.client.config.ClientConfigbean的存在。
  • spring.hazelcast.config属性定义的配置文件。
  • hazelcast.client.config系统属性的存在。
  • 在工作目录或者根类路径中的hazelcast-client.xml
  • 在工作目录或者根类路径中的hazelcast-client.yaml

如果客户端不能被创建,Spring Boot尝试配置一个内嵌的服务器。如果你定义了com.hazelcast.config.Configbean,Spring Boot使用这个。如果配置定义了一个实例的名称,Spring Boot尝试定位现有的实例而不是创建一个新的。

你也可以通过配置指定Hazelcast配置文件以使用,如下示例所示:

spring:
  hazelcast:
    config: "classpath:config/my-hazelcast.xml"

否则,Spring Boot尝试在默认的位置查找Hazelcast配置:在工作目录或者根类路径中的hazelcast.xml,或者相同位置对应的.yml。我们也检查hazelcast.config系统属性是否设置。请查阅Hazelcast文档了解更多详情。

默认情况下,在Hazelcast 组件上的@SpringAware是支持的。ManagementContext可以通过声明一个使用大于零的OrderHazelcastConfigCustomizerbean重写。

Spring Boot也对Hazelcast也明确的缓存支持。如果禁用缓存,HazelcastInstance自动封装在CacheManager实现中。

11.3. Quartz Scheduler

Spring Boot为与Quartz Scheduler工作提供多种方便,包括spring-boot-starter-quartz启动器。如果Quartz是可用的,Scheduler是自动配置(通过SchedulerFactoryBean抽象)。

以下类型的bean自动选取并关联Scheduler

  • JobDetail:定义特定的Job。JobDetail实例可以使用JobBuilderAPI构造。
  • Calendar
  • Trigger:当特定的job触发时定义。

默认情况下,使用一个内存的JobStore。然而,如果应用程序中DataSourcebean 可用并且如果相应的配置spring.quartz.job-store-type属性,可以配置基于JDBC存储,如下示例所示:

spring:
  quartz:
    job-store-type: "jdbc"

当使用JDBC存储时,在启动时初始化此模式,如下示例所示:

spring:
  quartz:
    jdbc:
      initialize-schema: "always"

默认情况下,通过使用Quartz类库提供的标准的脚本,检测和初始化数据库。在每次重启,这些脚本删除存在的表,删除所有的触发器。通过设置spring.quartz.jdbc.schema属性可以提供自定义的脚本。

要让Quartz使用应用程序的主DataSource以外的DataSource,声明一个DataSourcebean,使用@QuartzDataSource注解它的@Bean方法。这样做确保SchedulerFactoryBean和用于模式初始化使用特定的QuartzDataSource。类似地,要让Quartz使用应用程序的主要的TransactionManager,声明一个TransactionManagerbean,使用@QuartzTranscationManager注解它的@Bean方法。

默认情况下,通过配置创建的job将不会重写已经注册并且已经从持久化job存储读取的job。为启用重写现在有job定义,请设置spring.quartz.overwrite-existing-jobs属性。

Quartz Scheduler配置可以使用spring.quartz属性和SchedulerFactoryBeanCustomizerbean定制,它们允许对SchedulerFactoryBean程序化定制。高级的Quartz配置属性可以使用spring.quartz.properties.*定制。

特别是,Executorbean不会与scheduler结合因为Quartz通过spring.quartz.properties配置方式配置scheduler。如果你需要定制任务执行器,考虑实现SchedulerFactoryBeanCustomizer

Job可以定义setter注入数据映射属性。常规的bean也可以以类似的方式注入,如下示例所示:

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import org.springframework.scheduling.quartz.QuartzJobBean;

public class MySampleJob extends QuartzJobBean {

    private MyService myService;

    private String name;

    // Inject "MyService" bean
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    // Inject the "name" job data property
    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        this.myService.someMethod(context.getFireTime(), this.name);
    }

}

11.4. 发送email

Spring Framework通过使用JavaMailSender接口提供发送邮件的抽象,并且Spring Boot为它提供自动配置以及启动器模块。

请查看参考文档了解解释了如何使用JavaMailSender情况。

如果spring.mail.host和相关的类库(spring-boot-starter-mail定义的)是可用的,如果默认的JavaMailSender不存在则创建。发送器(sender)可以通过配置来自spring.mail命名空间的项进一步定制。请查看MailProperties了解更多详情。

特别是,某个默认的超时的值是无限的,你可能想改变这一点,来避免被无响应的邮件服务器线程阻塞,如下示例所示:

spring:
  mail:
    properties:
      "[mail.smtp.connectiontimeout]": 5000
      "[mail.smtp.timeout]": 3000
      "[mail.smtp.writetimeout]": 5000

也可以使用JNDI中现有的Session配置JavaMailSender

spring:
  mail:
    jndi-name: "mail/Session"

jndi-name已经设置,它的优先级在所有其他相关的Session设置之上。

11.5. 验证

支持方法验证特性通过Bean Validation 1.1自动启用只要在类路径中存在JSR-303实现(例如Hibernate验证)。这个使得bean方法可以在其参数或者他们的返回值上javax.validation约束进行注解。使用这样的带有注解方法的目标类需要在类型级别上使用@Validated注解进行注解,以便搜索他们的方法以内联约束注解。

例如,以下服务触发第一个参数的校验,确保他的长度在8和10之间:

import jakarta.validation.constraints.Size;

import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

@Service
@Validated
public class MyBean {

    public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, Author author) {
        return ...
    }

}

当解析在约束信息中的{参数}时使用应用程序的MessageSource。这个允许你使用你的应用程序的messages.properties文件用于Bean Validation信息。一旦参数已经被解析,使用Bean Validation的默认内插器完成信息内插。

为定制用于构建ValidatorFactoryConfiguration,定义ValidationConfigurationCustomizerbean。当定义了多个定制器bean,他们按照基于@Order注解或者Ordered实现的顺序调用。

11.6. 调用REST服务

如果你的应用程序调用远程的REST服务,Spring Boot使用RestTemplate或者WebClient使其非常方便。

11.6.1. RestTemplate

如果你需要在你的应用程序调用远程的REST服务,你可以使用Spring Framework的RestTemplate类。因为在使用RestTemplate实例之间通常需要被定制,Spring Boot不会提供任何单个自动配置的RestTemplatebean。但是,他会自动配置RestTemplateBuilder,当需要时它可以用来创建RestTemplate实例。自动配置的RestTemplateBuilder确保合适的HttpMessageConverters应用到RestTemplate实例中。

以下代码展示了典型的示例:

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class MyService {

    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    public Details someRestCall(String name) {
        return this.restTemplate.getForObject("/{name}/details", Details.class, name);
    }

}

RestTemplateBuilder包含多个有用处的方法,可以用来快速配置RestTemplate。例如,为添加基本的授权支持,你可以使用builder.basicAuthentication("user","password").build()

RestTemplate定制

有三种主要的方法实现RestTemplate定制,这取决于你希望自定义的应用范围。

为了使定制的范围尽可能的小,注入自动配置的RestTemplateBuilder,然后根据所需调用他的方法。每次方法调用返回一个新的RestTemplateBuilder实例,所以这个定制只影响builder的使用。

为使应用程序范围内的,递增地定制,使用RestTemplateCustomizerbean。所有这样的bean是自动注册到RestTemplateBuilder并且被应用于使用它构建的任何模板。

下方的示例展示了一个定制器,其配置了用于除了192.168.0.6以外的所有主机的代理的使用:

import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.protocol.HttpContext;

import org.springframework.boot.web.client.RestTemplateCustomizer;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class MyRestTemplateCustomizer implements RestTemplateCustomizer {

    @Override
    public void customize(RestTemplate restTemplate) {
        HttpRoutePlanner routePlanner = new CustomRoutePlanner(new HttpHost("proxy.example.com"));
        HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build();
        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    }

    static class CustomRoutePlanner extends DefaultProxyRoutePlanner {

        CustomRoutePlanner(HttpHost proxy) {
            super(proxy);
        }

        @Override
        public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
            if (target.getHostName().equals("192.168.0.5")) {
                return null;
            }
            return super.determineProxy(target, request, context);
        }

    }

}

最后,你可以定义你自己的RestTemplateBuilderbean。这样做将替换自动配置的builder。如果你希望任何RestTemplateCustomizerbean被应用到自定义builder,就像自动配置那样,使用RestTemplateBuilderConfigurer配置它。下面的示例暴露匹配Spring Boot的自动配置所做的RestTemplateBuilder,除了自定义连接以外,读超时也被指定:

import java.time.Duration;

import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyRestTemplateBuilderConfiguration {

    @Bean
    public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {
        return configurer.configure(new RestTemplateBuilder()).setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(2));
    }

}

最极端的情况(很少使用)是不使用configurer创建自己的RestTemplateBuilder。除了替换自动配置的builder,也可以防止使用任何RestTemplateCustomizer

11.6.2. WebClient

如果你有Spring WebFlux在类路径中,你也可以选择使用WebClient来调用远程的REST服务。相比于RestTemplate,这个客户端有更强的功能性,而且完全是响应式的。你可以在Spring Framework文档中相关的章节学习更多关于WebClient

Spring Boot为你创建和预配置一个WebClient.Builder。强烈建议将它注入你的组件和使用它创建WebClient实例。Spring Boot正在配置该构建器以共享HTTP资源,以与服务器相同的方式反射编解码器的设置(请查看WebFlux HTTP编解码自动配置),等等。

下面的代码展示了一个典型的示例:

import org.neo4j.cypherdsl.core.Relationship.Details;
import reactor.core.publisher.Mono;

import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
public class MyService {

    private final WebClient webClient;

    public MyService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("https://example.org").build();
    }

    public Mono<Details> someRestCall(String name) {
        return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
    }

}
运行时WebClient

Spring Boot将自动检测使用哪个ClientHttpConnector来驱动WebClient,取决于在应用程序类路径可用的类库。现在,Reactor Netty,Jetty RS客户端和Apache HttpClient是支持的。

spring-boot-starter-webflux启动器默认情况下依赖io.projectreactor.netty:reactor-netty,其带有服务器和客户端实现。如果你选择使用Jetty作为响应式服务器代替,你应该在Jetty Reactive HTTP客户端类库上添加一个依赖项,org.eclipse.jetty:jetty-reactive-httpclient。服务器和客户端使用相同的技术有它的优势,因为它将在客户端和服务器自动共享HTTP资源。

开发者可以通过提供自定义的ReactorResourceFactory或者JettyResourceFactorybean对Jetty和Reactor Netty重写资源配置,ReactorResourceFactory或者JettyResourceFactorybean将应用到客户端和服务器。

如果你希望为客户端重写该选择,你可以定义你自己的ClientHttpConnectorbean并且完全控制客户端配置。

你也可以学习更多关于在Spring Framework参考文档的WebClient配置选项。

WebClient定制

WebClient定制有三种主要的方法,取决于你想要应用的定制范围。

为是任何定制的范围尽可能的小,注入自动配置的WebClient.Builder,然后调用他的所需要的方法。WebClient.Builder实例是有状态的:任何在builder的改变都会反应到随后使用它创建的所有客户端上。如果你想使用相同的builder创建多个客户端,你也可以考虑使用WebClient.Builder other = builder.clone()克隆builder。

要对所有的WebClient.Builder实例进行应用程序范围的递增地定制,你可以声明WebClientCustomizerbean并且在注入点局部改变WebClient.Builder

最终,你可以回退到原始的API并使用WebClient.create()。在这种情况,没有自动配置或者应用WebClientCustomizer

11.7. Web服务

Spring Boot提供Web服务自动配置,因此你必须做的是定义你的Endpoints

Spring Web Service特性使用spring-boot-starter-webservices模块可以非常容易访问。

可以为WSDL和XSD分别自动创建SimpleWsdl11DefinitionSimpleXsdSchemabean。为此,配置他们的位置,如下示例所示:

spring:
  webservices:
    wsdl-locations: "classpath:/wsdl"

11.7.1. 使用WebServiceTemplate调用Web Service

如果你需要在应用程序中调用远程的web服务,你可以使用WebServiceTemplate类。因为WebServiceTemplate实例通常在使用之前需要定制它,Spring Boot不提供任何单独自动配置的WebServiceTemplatebean。但是他会自动配置WebServiceTemplateBuilder,当需要的它可以用来创建WebServiceTemplate实例。

下面的代码展示了典型的示例:

import org.springframework.boot.webservices.client.WebServiceTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.client.core.SoapActionCallback;

@Service
public class MyService {

    private final WebServiceTemplate webServiceTemplate;

    public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {
        this.webServiceTemplate = webServiceTemplateBuilder.build();
    }

    public SomeResponse someWsCall(SomeRequest detailsReq) {
        return (SomeResponse) this.webServiceTemplate.marshalSendAndReceive(detailsReq,
                new SoapActionCallback("https://ws.example.com/action"));
    }

}

默认情况下,WebServiceTemplateBuilder使用类路径中可用的HTTP客户端类库检测合适的基于HTTP的WebServiceMessageSender,你也可以定制读和连接超时,如下:

import java.time.Duration;

import org.springframework.boot.webservices.client.HttpWebServiceMessageSenderBuilder;
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;

@Configuration(proxyBeanMethods = false)
public class MyWebServiceTemplateConfiguration {

    @Bean
    public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
        WebServiceMessageSender sender = new HttpWebServiceMessageSenderBuilder()
                .setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(2))
                .build();
        return builder.messageSenders(sender).build();
    }

}

11.8. 使用JTA分布式事务

Spring Boot通过使用从JNDI检索的事务管理支持跨多个XA资源的分布式JTA事务。

当检测JTA环境时,Spring的JtaTransactionManager用来管理事务。自动配置的JMS,DataSource和JPAbean升级为支持XA事务。你可以使用标准的Spring风格,比如@Transactional,来参与分布式事务。如果你在一个JTA环境内并想使用本地事务,你可以设置spring.jta.enabled属性为false来禁用JTA自动配置。

11.8.1. 使用Jakarta EE管理事务管理器

如果你打包Spring Boot应用程序为war或者ear文件并部署它到Jakarta EE应用程序服务器,你可以使用应用程序服务器的内建的事务管理器。Spring Boot尝试通过查找常用的JNDI位置(java:comp/UserTransaction,java:comp/TransactionManager等等)自动配置一个事务管理器。当使用应用程序服务器提供的事务服务时,你通常也希望确保所有的资源通过服务器管理并且通过JNDI暴露。Spring Boot尝试通过在JNDI路径(java:/JmsXA或者java:/XAConnectionFactory)查找ConnectionFactory自动配置JMS,你可以使用spring.datasource.jndi-name属性配置你的DataSource

11.8.2. 混合XA和非XA JMS连接

当我们使用JTA,主要的JMSConnectionFactorybean是支持XA并在分布式事务中参与。你无需使用任何@Qualifier可以注入到你自己的bean。

public MyBean(ConnectionFactory connectionFactory) {
    // ...
}

在一些情况中,你可能想使用非XA的ConnectionFactory处理某一个JMS消息。例如,你的JMS处理逻辑所花费的时间可能比XA超时长。

如果你想使用一个非XAConnectionFactory,你可以使用nonXaJmsConnectionFactorybean:

public MyBean(@Qualifier("nonXaJmsConnectionFactory") ConnectionFactory connectionFactory) {
    // ...
}

为保持一致性,通过使用别名为xaJmsConnectionFactory也可以提供jmsConnectionFactorybean:

public MyBean(@Qualifier("xaJmsConnectionFactory") ConnectionFactory connectionFactory) {
    // ...
}

11.8.3. 支持内嵌的事务管理器

XAConnectionFactoryWrapperXADataSourceWrapper接口可以用来支持内嵌的事务管理器。接口是负责包装XAConnectionFactoryXADataSourcebean并且暴露他们作为常规的ConnectionFactoryDataSourcebean,他们透明地注册到分布式事务中。DataSource和JMS自动配置使用JTA变体,前提是你有一个JtaTransactionManagerbean并且合适的XA封装bean注册到ApplicationContext中。

11.9.下一步读什么

现在你应该对Spring Boot的核心特性有一个很好的理解,并且Spring Boot通过自动配置提供支持各种技术。

下几个章节带你了解关于发布应用程序到云平台的细节。你可以读关于下一个章节构建容器镜像或者跳到生产就绪特性章节。

12. 容器镜像

Spring Boot应用程序可以使用Docketfile容器化,或者使用云生打包创建优化的docker,兼容的容器镜像,可以在任何地方运行

12.1. 高效容器镜像

可以容易地将Spring Boot fat jar打包为docker镜像。然而,在docker镜像中复制和运行fat jar也有多种缺点。当运行fat jar而不解压它时,总是有大量开销。并且在容器化环境中这个是很明显的。另一个问题是将你应用程序的代码和所有他的依赖放在Docker镜像中一个层是次优的。因为你可能重新编译你的代码通常多余升级你使用Spring Boot版本,最好是将代码的内容分开一些。如果你将jar文件放在应用程序类之前的那一层,Docker通常只需要改变最底层,就可以从缓存中获取其他文件。

12.1.1. 解压fat jar

如果你正在容器中运行你的应用程序,你可以使用可执行jar,但是它也通常具有优势来引爆它并且以不同的方式运行它。某些PaaS实现可能也选择在他们运行之前解压文档。例如,Cloud Foundry这种方式操作。一种方式运行一个未解压的档案是通过启动适合的启动器,如下:

$ jar -xf myapp.jar
$ java org.springframework.boot.loader.JarLauncher

这实际上在启动时确实比运行在未爆炸的存档要快一些(依据jar的大小)。在运行时你不应该期望有任何差异。

一旦你解压了jar文件,你也可以通过使用它的“自然的”主方法代替JarLauncher来运行应用程序来获得额外的启动时间的提升。例如:

$ jar -xf myapp.jar
$ java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication

在应用程序的主方法上使用JarLauncher还有额外的好处,那就时可预测的类路径顺序。jar包含classpath.idx文件,在构造类路径时被JarLauncher使用。

12.1.2. 分层Docker镜像

为使它容易创建最优的Docker映像,Spring Boot支持添加一个分层索引文件到jar。它提供分层列表和应该包含在其中的jar部分。在索引中的分层列表是基于分层应该被添加到Docker/OCI镜像顺序排序的。以下分层是支持开箱即用的:

  • dependencies(用于常规的发布依赖)
  • spring-boot-loader(在org/springframework/boot/loader下的任何东西)
  • snapshot-dependencies(用于快照依赖)
  • application(用于应用程序和资源)
    以下展示了layers.idx文件的示例:
- "dependencies":
  - BOOT-INF/lib/library1.jar
  - BOOT-INF/lib/library2.jar
- "spring-boot-loader":
  - org/springframework/boot/loader/JarLauncher.class
  - org/springframework/boot/loader/jar/JarEntry.class
- "snapshot-dependencies":
  - BOOT-INF/lib/library3-SNAPSHOT.jar
- "application":
  - META-INF/MANIFEST.MF
  - BOOT-INF/classes/a/b/C.class

这个分层被设计用于基于不同应用程序构建之间更改的可能性来分隔代码。类库代码在不同的构建可能很少改变,所以它放在他自己的分层以允许工具从缓存中重用这个分层。应用程序代码在构建之间更可能改变所以它被隔离放一个单独的分层。

Spring Boot在layers.idx的帮助下也支持对war文件分层。

对于Maven,关于添加分层索引到存档,请查看打包分层jar或者war章节了解更多详情。对于Gradle,请查看Gradel插件文档的打包分层jar或者war章节

12.2. Dockerfiles

虽然在Dockerfile仅仅几行就可以转换Spring Boot fat jar到docker镜像,我们将使用分层特性来创建一个更优的docker镜像。当你创建包含分层索引文件的jar时,spring-boot-jarmode-layertoolsjar将作为一个依赖项添加到你的jar中。有了类路径中的这个jar,你可以以一个特殊的模式启动你的应用程序,此模式允许引导代码运行与应用程序完全不同的东西,例如,提取层的东西。

layertools模式不能与包含运行脚本完全的可执行的Spring Boot存档使用。当构建一个打算使用layertools的jar文件时,禁用启动脚本配置。

这是你如何启动使用layertoolsjar模式运行你的jar:

$ java -Djarmode=layertools -jar my-app.jar

这个将提供以下输出:

Usage:
  java -Djarmode=layertools -jar my-app.jar

Available commands:
  list     List layers from the jar that can be extracted
  extract  Extracts layers from the jar for image creation
  help     Help about any command

extract命令可以用来容易的将应用程序分隔成添加到dockerfile的分层。这是一个Dockerfile使用jarmode的示例:

FROM eclipse-temurin:11-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM eclipse-temurin:11-jre
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

假设上面的Dockerfile在当前目录,你的docker镜像可以使用docker build .构建,或者随意地指定你的应用程序 jar的路径,如下示例所示:

$ docker build --build-arg JAR_FILE=path/to/myapp.jar .

这个是一个多级dockerfile。构造器阶段提取以后需要的目录。每个COPY命令都与jarmode提取的层相关。

当然,Dockerfile可以在不使用jarmode的情况下重写。你可以使用一些unzipmv的组合来移动东西到正确的分层但是jarmode简化了这一点。

12.3. 云原生构建包

Dockerfile只是一种方式构建docker镜像。另外一种方式构建docker镜像是直接使用Maven或者Gradle插件,使用构建包。如果你曾经使用过应用程序平台,比如Cloud Foundry或者Heroku,那么你可能使用过构建包。构建包是平台的一部分,他把你的应用程序转换成平台可以实际运行的东西。例如,Cloud Foundry的Java构建包会注意到你正在推送.jar文件并自动添加一个相关的JRE。

使用云原生构建包,你可以创建可以在任何地方运行的Docker兼容镜像。Spring Boot包含构建包直接支持Maven和Gradle。这意味着你只需输入单个命令,就可以快速得到将一个合理的镜像导入到本地运行的Docker守护进程。

查看各自的插件文档关于如何在Maven和Gradle中使用构建包。

Paketo Spring Boot构建包也已经更新支持layers.idx文件,所以任何应用到它的定制,都会反应到构建包创建的镜像。

为了实现可复制的构建和容器镜像缓存,构建包可以操作应用程序资源元数据(例如文件“最后修改”信息)。你应该确保你的应用程序运行时不依赖该元数据。当提供静态资源时,Spring Boot可以使用该信息,但是可以使用spring.web.resources.cache.use-last-modified禁用这个功能。

12.4. 下一步读什么

一旦你已经学会如何构建高效的容器镜像,你可以读关于发布应用程序到云平台,例如Kubernetes。

13. 生产就绪特性

当你将应用程序推送生产时,Spring Boot包含多种额外特性帮助你监控和管理你的应用程序。你可以通过使用HTTP端或者使用JMX选择管理和监控你的应用程序。监察,健康度和指标收集也可以自动应用到应用程序。

13.1. 启用生产就绪特性

spring-boot-actuator模块提供所有的Spring Boot的生产就绪状态特性。启用特性推荐的方式是添加spring-boot-starter-actuator启动器依赖项。

Actuator定义

Actuator是一个制造术语,指的是移动和控制某物的一种机械装置。Actuator可以由一个微小的变化生成大量的运动。

为将Actuatro添加到基于Maven的项目,添加以下“启动器”依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-actuatorartifactId>
    dependency>
dependencies>

对于Gradle,使用以下声明:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

13.2. 端点

Actuator端点允许你监控应用程序并与之交互。Spring Boot包含多个内建的端点并允许你添加自己的。例如,health端点提供基本的应用程序监控信息。

你可以启用或者禁用每一个个别的端点或者在HTTP或者JMX暴露他们(使他们远程访问)。当一个端点启用并且暴露则认为是可用的。只有当他们是可用的,内建的端点是自动配置的。大多数应用程序选择在HTTP端暴露,其中端点的ID和/actuator的前缀被映射到URL。例如,默认情况下,health端点被映射到/actuator/health

为了解更多关于Actuator的端点和他们的请求响应格式,查看单独的API文档(HTML或者PDF)。

以下是可用的与技术无关的端点:

ID 描述
auditevents 暴露当前应用程序审核事件信息。需要AuditEventRepository bean
beans 显示在你的应用程序中所有的bean的完整列表
caches 暴露可用缓存
conditions 展示在配置文件和自动配置类评估的条件和为什么他们没有或者匹配的原因
configprops 展示所有的ConfigurationProperties整理列表
env 展示来自Spring的ConfigurableEnvironment的属性
flyway 展示任何已经应用的Flyway数据迁移。需要一个或者更多Flywaybean
health 展示应用程序健康信息
httptrace 展示HTTP追踪信息(默认情况下,最后100个HTTP请求响应交换).需要HttpTraceRepositorybean
info 展示任意的应用程序信息
integrationgraph 展示Spring集成图像。需要spring-integration-core依赖项
loggers 展示和修改应用程序中日志的配置
liquibase 展示任何已经应用的Liquibase数据库迁移.需要一个或者多个Liquibasebean
metrics 展示当前应用程序的指标
mappings 展示所有的@RequestMapping路径的整理列表
quartz 展示关于Quartz Scheduler工作的信息
scheduledtasks 展示你应用程序中的计划任务
sessions 允许从Spring Session-backed会话库中用户会话的找回和删除。需要使用Spring Session基于servlet的web应用程序
shutdown 使应用程序优雅停机。默认情况下展示
shutdown 使应用程序优雅停机。默认情况下禁用
startup 展示通过ApplicationStartup收集的启动步骤数据.需要使用BufferingApplicationStartup配置SpringApplication
threaddump 提供线程转存

如果你的应用程序是一个web应用程序(Spring MVC或者Spring WebFlux),你可以使用以下额外的端点:

ID 描述
heapdump 返回堆转存文件。在HotSpot JVM,返回HPROF格式文件。在OpenJ9 JVM,返回PHD格式文件
jolokia 当Jolokia在类路径上时,在HTTP上暴露JMXbean(对于WebFlux是不可用的)。需要jolokia-core依赖项
logfile 返回日志文件内容(如果logging.file.name或者logging.file.path属性已经设置)。支持HHTPRange数据头使用以回收日志文件的内容部分
prometheus 以Prometheus服务可以抓取的格式暴露指标。需要micrometer-registry-prometheus依赖项

13.2.1. 启用端点

默认情况下,所有的端点除了shutdown都是启用的。为配置一个端点的可用,使用它的management.endpoint..enabled属性。下面的示例启用shutdown端点:

management:
  endpoint:
    shutdown:
      enabled: true

如果你更喜欢端点启用为可选择的加入而不是选择性退出,设置management.endpoints.enabled-by-default属性为false和使用个别的endpoint的enable属性选择性回归加入。下面的示例启用info端点并禁用其他所有端点:

management:
  endpoints:
    enabled-by-default: false
  endpoint:
    info:
      enabled: true

禁用端点是完全的从应用程序上下文移除。如果你想只改变暴露端点这个技术,使用includeexclude属性代替。

13.2.2. 暴露端点

因为端点可能包含敏感信息,你应该小心考虑什么时候暴露他们。下面的表展示了默认内建端点的暴露:

ID JMX Web
auditevents
beans
caches
conditions
configprops
env
flyway
health
heapdump
httptrace
info
integrationgraph
jolokia N/A
logfile N/A
loggers
liquibase
metrics
mappings
prometheus N/A
quartz
scheduledtasks
sessions
shutdown
startup
threaddump

为改变哪个端点暴露,使用以下特定的技术 includeexclude属性。

属性 默认的
management.endpoints.jmx.exposure.exclude
management.endpoints.jmx.exposure.include *
management.endpoints.web.exposure.exclude
management.endpoints.web.exposure.include health

include属性列出已经暴露端点的ID。exclude属性列出不应该暴露端点列表的ID。exclude属性优先于include属性。你可以使用端点ID列表配置includeexclude属性。

例如,为停止暴露所有端点在JMX并只暴露healthinfo端点,使用以下属性:

management:
  endpoints:
    jmx:
      exposure:
        include: "health,info"

*可以用来选择所有端点。例如,为在HTTP上暴露所有,除了envbeans端点,使用以下属性:

management:
  endpoints:
    web:
      exposure:
        include: "*"
        exclude: "env,beans"

*在YAML中有一个特定的含义,如果你想包含或者(排除)所有端点,所以一定要保证添加双引号标志。

如果你的应用程序公开暴露,我们强烈建议,你要使你的端点安全。

如果你想实现你自己的策略用于什么时候暴露端点,你可以注册EndpointFilterbean。

13.2.3. 安全

处于安全目的,默认情况下,只有/health端点在HTTP上暴露。你可以使用management.endpoints.web.exposure.include属性配置要暴露的端点。

设置management.endpoints.web.exposure.include之前,确保暴露的actuator不包含敏感信息,确保通过将他们放在防火墙之后来保证安全,或者通过像Spring Security的一些东西来保证安全。

如果Spring Security在类路径中并且没有其他WebSecurityConfigurerAdapter或者SecurityFilterChainbean存在,所有的actuator不同于Spring Boot自动配置保证安全的/health。如果你定义了自定义的WebSecurityConfigureAdapter或者SecurityFilterChainbean,Spring Boot自动配置退出并让你完全控制actuator访问规则。

如果你希望对HTTP端点配置自定义的安全(例如,只允许拥有某个角色的用户访问他们),Spring Boot提供一些方便的RequestMatcher对象,你可以与Spring Security结合使用。

一个典型的Spring Security配置可能看起来像下面的示例:

import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.requestMatcher(EndpointRequest.toAnyEndpoint());
        http.authorizeRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
        http.httpBasic(withDefaults());
        return http.build();
    }

}

前面的示例使用EndpointRequest.toAnyEndpoint()匹配任意端点的请求并且确保所有具有ENDPOINT_ADMIN角色。在EndpointRequest上几个其他匹配方法也是可用的。请查看API文档(HTML或者PDF)了解细节。

如果你发布应用程序在防火墙强后面,你可能希望所有的actuator端点可以访问而无需验证身份。你可以通过改变management.endpoints.web.exposure.include属性来这么做,如下:

management:
  endpoints:
    web:
      exposure:
        include: "*"

或者,如果Spring Security存在,你可能需要添加自定义安全配置来运行无身份认证的访问端点,如下示例所示:

import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.requestMatcher(EndpointRequest.toAnyEndpoint());
        http.authorizeRequests((requests) -> requests.anyRequest().permitAll());
        return http.build();
    }

}

在前面的示例中,配置只应用到actuator端点。因为Spring Boot的安全配置在任何SecurityFilterChain bean存在时都是完全退出的,你需要规则配置额外的SecurityFilterChainbean应用到应用程序的其余部分。

跨站点请求伪造保护

因为Spring Boot依赖Spring Security的默认情况,CSRF保护是打开的。这表示当默认的安全配置在使用中时,需要POST(shutdown 和loggers端点),PUT,DELETE的actuator端点返回403(禁止)错误。

如果你在创建非浏览器使用的服务,你我们建议完全禁用CSRF保护。

你可以在Spring Security参考指南中找到关于CSRF保护额外的信息。

13.2.4. 配置端点

端点自动化缓存响应以读取不带参数的操作。为配置端点缓存响应的时间数量,使用它的cache.time-to-live属性。下面的例子设置beans端点缓存10秒的存活时间:

management:
  endpoint:
    beans:
      cache:
        time-to-live: "10s"

management.endpoint.前缀唯一标识正在配置的端点。

13.2.5. 用于Actuator web端点的超媒体

添加一个“展示页面”链接到所有的端点。默认情况下在/actuator这个“展示页面”是可用的。

为禁用“展示页面”,添加以下属性到应用程序属性:

management:
  endpoints:
    web:
      discovery:
        enabled: false

当配置了自定义管理上下文路径时,“展示页面”自动从/actuator移动到管理上下文的根路径。例如,如果管理上下文路径是/management,展示的页面在/management是可用的。当管理上下文路径设置为/,展示页面是禁用的,避免其他映射冲突的可能性。

13.2.6. CORS支持

跨源资源共享(CORS)是W3C规范,让你以灵活的方式指定哪种跨域请求是授权的。如果你使用Spring MVC或者Spring WebFlux,你可以配置Actuator的web端点来支持这种场景。

CORS支持默认情况下是禁用的,当你已经设置management.endpoints.web.cors.allowed-origins属性才会启用。以下配置允许GETPOSTexample.com域调用。

management:
  endpoints:
    web:
      cors:
        allowed-origins: "https://example.com"
        allowed-methods: "GET,POST"

请查看CorsEndpointProperties了解完整的选项列表。

13.2.7. 实现自定义端点

如果你添加带有@Endpoint注解的@Bean,任何带有@ReadOperation,@WriteOperation或者@DeleteOperation方法是自动暴露在JMX上,在web应用程序中也会在HTTP上暴露。端点可以使用Spring MVC或者Spring WebFlux在HTTP上暴露。

下面的示例暴露了返回自定义对象的读操作:

@ReadOperation
public CustomData getData() {
    return new CustomData("test", 5);
}

你也可以通过使用@JmxEndpoint或者@WebEndpoint写特定技术的端点。这些端点分别受限于他们的技术。例如,@WebEndpoint直接通过HTTP暴露而不能通过JMX。

你可以通过@EndpointWebExtension@EndpointJmxExtension写特定技术的扩展。这些注解允许你提供特定技术操作来增加现有端点。

最终,如果你需要访问特定的web框架功能,你可以实现servlet或者Spring @Controller@RestController端点,但是代价是他们不能在JMX或者使用不同的web框架时可用。

接受输入

在端点上的操作通过他们的参数接受输入。当在web上暴露时,这些参数的值取自URL的查询参数和JSON请求体。当在JXM暴露时,参数被映射到MBean的操作参数上。默认情况下需要参数。使用@javax.annotation.Nullable或者@org.springframework.lang.Nullale注解他们,可以使他们成为可选的。

你可以在JSON请求体中映射每一个根属性到端点的参数。考虑以下JSON请求体:

{
    "name": "test",
    "counter": 42
}

你可以使用这个调用一个写操作,取String nameint counter参数,如下示例所示:

@WriteOperation
public void updateData(String name, int counter) {
    // injects "test" and 42
}

因为端点是与技术无关的,只有简单类型可以在方法签名中指定。特别是,声明一个单独的参数CustomData类型并定义namecounter属性是不支持。

为让输入可以被映射到操作方法参数,实现一个端点的Java代码应该使用-parameters编译,并且实现一个端点的Kotlin代码应该使用-java-parameters编译。如果你使用Spring Boot的Gradle插件或者使用Maven和spring-boot-starter-parent这将自动发生。

输入类型转换

参数传入到端点操作方法是在必须的情况自动转换为所有的类型。调用操作方法之前,在JMX或者HTTP上接收的传入通过使用ApplicationConversionService的实例以及使用@EndpointConverter限定的任何Converter或者GenericConverterbean被转换为所需要的类型。

自定义web端点

@Endpoint,@WebEndpoint或者@EndpointWebExtension上的操作是使用Spring MVC或者Spring WebFlux自动暴露在HTTP上。

Web端点请求断言

请求断言是自动为每一个在web暴露的端点生成。

路径

断言的路径取决于端点的ID和暴露的web端点的基础路径。默认的基础路径是/actuator。例如,使用sessionsID的端点在断言中使用/actuator/sessions作为它的路径。

你可以通过使用@Selector注解操作方法的一个或者更多参数进一步定制路径。这样的一个参数被添加到路径断言作为路径参数。当端点操作被调用,这个参数值被传入到操作方法。如果你想捕获所有剩下的路径元素,你可以添加@Selector(Match=ALL_REMAINING)到最后的参数并且使其成为与String[]兼容转换的类型。

HTTP方法

断言的HTTP方法通过操作类型决定的,如下示例所示:

操作 HTTP方法
@ReadOperation GET
@WriteOperation POST
@DeleteOperation DELETE
消费

对于使用请求体的@WriteOperation(HTTPPOST),consumes的断言子句是application/vnd.spring-boot.actuator.v2+json,application/json。对于所有其他操作,consumers子句是空的。

生产

produces断言子句通过@DeleteOperation@ReadOperation@WriteOpertaion注解的produces属性决定的,这个属性是可选的。如果不使用它,produces子句自动确定。

如果操作方法返回void或者Voidproduces子句是空的。如果操作方法返回org.springframework.core.io.Resourceproduces子句是application/octet-stream。对于所有其他操作,produces子句是application/vnd.spring-boot.actuator.v2+jsonapplication/json

Web端点响应状态

对于一个端点操作的默认的响应状态取决于操作类型(read,write或者delete)以及操作返回的内容(如果有的话)。

如果@ReadOperation返回一个值,响应状态将是200(OK).如果他没有返回一个值,响应状态为404(Not Foound)。

如果@WriteOperation或者@DeleteOperation返回一个值,响应状态为200(OK).如果它没有返回一个值,响应状态为204(Not Content).

如果一个操作未使用参数或者一个参数被调用,不能转换为所需要的类型,操作方法将不会被调用,响应状态为400(Bad Request)。

Web端点范围请求

你可以使用HTTP范围请求来请求HTTP资源部分。返回org.springframework.core.io.Resource操作自动支持范围请求。

Web端点安全

在web端点的操作或者特定的web端点扩展可以接受当前的java.security.Principal或者org.springframework.boot.actuate.endpoint.SecurityContext作为方法参数。前者是通常结合@Nullable用来对身份验证和非身份验证用户提供不同的行为。后者通常用来使用它的isUserInRole(String)方法提供身份认证检查。

Servlet端点

servlet通过实现带有注解@ServletEndpoint的类或者实现Suppllier作为一个端点暴露。servlet端点提供了与servlet容器的高度集成,但是以可移植性作为代价。他们打算用来暴露现有的servlet作为一个端点。对于新的端点,应该尽可能首选@Endpoint@Webpoint注解。

Controller端点

你可以使用@ControllerEndpoint@RestControllerEndpoint只能通过Spring MVC或者spring WebFlux实现一个暴露的端点。使用Spring MVC和Spring WebFlux的标准的注解映射方法,例如@ReqestMappingGetMapping,使用端点的ID用来当做路径的前缀。Controller 端点提供与Spring的web框架的深度集成,但是以可移植性作为代价。应该尽可能首选@Endpoint@Webpoint注解。

13.2.8. 监控信息

你可以使用健康信息来检查运行中的应用程序的状态。当生产系统下降时,通常通过监控软件使用来提醒一些事情。这个信息是通过health端点暴露的,取决于management.endpoint.health.show-detailsmanagement.endpoint.health.show-components属性,可以使用以下其中一个配置他们。

名称 描述
Never 不展示明细
when-authorized 对授权用户展示。通过使用management.endpoint.health.roles配置授权角色
always 对所有用户展示

默认值是never。当用户是端点角色的一个或者更多时,用户被认为已经授权。如果端点没有配置角色(默认情况),所有已经通过认证的用户被认为已经授权。你可以通过使用management.endpoint.health.roles属性配置角色。

如果你已经对应用程序做了保护并且希望使用always,你的安全配置对已验证和未验证的用户必须许可访问health端点。

HealthContributorRegistry(默认情况下,你的ApplicationContext中定义的所有的HealthContributor实例)内容收集监控信息。Spring Boot包含多个自动配置的HealthContributors,并且你也可以写你自己的。

HealthContributor可以是HealthIndicator或者CompositeHealthContributorHealthIndicator提供真实的健康信息,包含StatusCompositeHealthContirbutor提供其他的HealthContributors的集合。总之,contributor形成一个树形结构来表示整个系统的健康状况。

默认情况下,最终系统健康是通过StatusAggregator推导的,其基于状态的顺序列表排序每一个HealthIndicator的状态。在排序列表的第一个状态用来当做全部健康状态。如果没有HealthIndication返回StatusAggregator已知的状态,使用UNKNOWN状态。

你可以在运行时使用HealthContributorRegistry注册并注销健康指标。

自动配置的监控指标

在适当的时候,Spring Boot自动配置下方表格所列的HealthIndicators。你也可以通过配置management.health.key.enabled启用或者禁用选择的指标,使用下面表格中所列出的key

key 名称 描述
cassandra CassandraDriverHealthIndicator 检查Cassandra数据库是否启动
couchbase CouchbaseHealthIndicator 检查Couchbase集群是否启动
db DataSourceHealthIndicator 检查连接到数据库是否获得
diskspace DiskSpaceHealthIndicator 检查低磁盘空间
elasticsearch ElasticsearchRestHealthIndicator 检查Elasticsearch集群是否启动
hazelcast HazelcastHealthIndicator 检查Hazelcast缓存是否启动
influxdb InfluxDbHealthIndicator 检查InfluxDB服务器是否启动
jms JmsHealthIndicator 检查JMS broker是否启动
ldap LdapHealthIndicator 检查LDAP服务器是否启动
mail MailHealthIndicator 检查mail服务器是否启动
mongo MongoHealthIndicator 检查Mongo数据库是否启动
neo4j Neo4jHealthIndicator 检查Neo4j数据库是否启动
ping PingHealthIndicator 总是使用up响应
rabbit RabbitHealthIndicator 检查Rabbit服务器是否启动
redis RedisHealthIndicator 检查Redis服务器是否启动

你可以通过设置management.health.defaults.enabled属性禁用他们所有。

额外的HealthIndicators是可用的但是默认情况下是不启用的。

key 名称 描述
livenessstate LivenessStateHealthIndicator 暴露“Liveness”(活跃的)应用程序可用性状态
readinessstate ReadinessStateHealthIndicator 暴露“readiness”(就绪)应用程序可用状态
写自定义的健康指标

为提供自定义健康指标信息,你可以注册实现HealthIndicator接口的Spring bean。你需要提供一个health()方法的实现并且返回一个Health返回。Health响应应该包含状态并且可以随意包含用来展示的额外明细。下方的代码展示了简单的HealthIndicator实现:

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();
        if (errorCode != 0) {
            return Health.down().withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }

    private int check() {
        // perform some specific health check
        return ...
    }

}

用于给定的HealthIndicator的标志符是不带HealthIndicator后缀的bean的名称,如果它存在,在上面的示例中,在命名为name入口健康信息是可用的。

健康指标通常在HTTP上调用并且需要任何连接超时之前响应。如果健康指标超过10s响应,Spring Boot将对任何健康指标记录警告信息日志。如果你想配置这个阈值,你可以使用management.endpoint.health.logging.slow-indicator-threshold属性。

除了Spring Boot的预定义的Status类型,Health可以返回自定义的表示新的系统状态Status。这样的情况下,你也需要提供一个自定义的StatusAggregator接口实现,或者你必须通过使用management.endpoint.health.status.order配置属性配置默认的实现。

例如,假设使用FATAL编码的新的Status正被用来HealthIndicator实现中的一个。为配置严重性顺序,添加以下属性到你的应用程序属性:

management:
  endpoint:
    health:
      status:
        order: "fatal,down,out-of-service,unknown,up"

在响应中的HTTP状态码反映出全部监控状态。默认情况下,OUT_OF_SERVICEDOWN映射到503。任何未映射的健康状态,包含UP,映射到200。如果在HTTP上访问健康端点,你可能也想注册自定义的状态映射。对DOWNOUT_OF_SERVICE配置一个自定义的映射禁用默认的映射。如果你想保留默认的映射你必须与任何自定义映射一起明确配置他们。例如,下面的属性映射FATAL到503(服务不可用)并且对DOWNOUT_OF_SERVICE保留默认的映射:

management:
  endpoint:
    health:
      status:
        http-mapping:
          down: 503
          fatal: 503
          out-of-service: 503

如果你需要更多的控制,你可以定义你自己的HttpCodeStatusMapperbean。

下方列表展示了对内建状态默认的状态映射:

状态 映射
DOWN SERVICE_UNAVAILABLE(503)
OUT_OF_SERVICE SERVICE_UNAVAILABLE(503)
UP 默认没有映射,所以HTTP状态为200
UNKNOWN 默认没有映射,所以HTTP状态为200
接收健康度指标

对于响应式应用程序比如这些使用Spring WebFlux,ReactiveHealthContributor提供一个非阻塞的约定来获得应用程序健状态。类似于传统的HealthContributor,从ReactiveHealthContributorRegistry的内容收集健康状态信息(默认情况下,在应用程序中定义的所有的HealthContributorReactiveHealthContributor实例)。不检查响应式API的常规的HealthContributors会在弹性调度器上执行。

在响应式应用程序,在运行时你应该使用ReactiveHealthContributorRegistry注册或者注销健康指标。如果你需要注册一个常规的HealthContributor,你应该使用ReactiveHealthContirbutor#adapt封装它。

为从响应式API中提供自定义的健康信息,你可以注册实现了ReactiveHealthIndicator接口的Sping bean。以下代码展示了一个简单的ReactiveHealthIndicator实现:

import reactor.core.publisher.Mono;

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

@Component
public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {

    @Override
    public Mono<Health> health() {
        return doHealthCheck().onErrorResume((exception) ->
            Mono.just(new Health.Builder().down(exception).build()));
    }

    private Mono<Health> doHealthCheck() {
        // perform some specific health check
        return ...
    }

}

为自动处理错误,考虑继承自AbstractReactiveHealthIndicator

自动配置的ReactiveHealthIndicators

适当的时候,Spring Boot自动配置以下ReactiveHealthIndicators:

key 名称 描述
cassandra CassandraDriverReactiveHealthIndicator 检查Cassandra数据库是否启动
couchbase CouchbaseReactiveHealthIndicator 检查Couchbase集群是否启动
elasticsearch ElasticsearchReactiveHealthIndicator 检查Elasticsearch集群是否启动
mongo MongoReactiveHealthIndicator 检查Mongo数据库是否启动
neo4j Neo4jReactiveHealthIndicator 检查Neo4j数据库是否启动
redis RedisReactiveHealthIndicator 检查Redis服务器是否启动

如果必须,响应式指标替换常规的那个。而且,任何没有显示处理的HealthIndicator自动被封装。

监控状态组

组织监控指标到一个组是非常有用的,你可以用于不同的目的。

要创建一个监控指标组,你可以使用management.endpoint.health.group.属性并指定监控指标列表ID到include或者exclude。例如,要创建一个只有数据库指标的组,你可以如下定义:

management:
  endpoint:
    health:
      group:
        custom:
          include: "db"

你仍可以通过点击localhost:8080/actuator/health/custom检查结果。

类似的,从包含所有其他指标的组中要创建一个不包含数据库指标的组,你可以如下定义:

management:
  endpoint:
    health:
      group:
        custom:
          exclude: "db"

默认情况下,组继承与系统健康相同的StatusAggregatorHttpCodeStatusMapper设置。然而,你也可以在每个组的基础上定义这些。如果需要,你也可以重写show-detailsroles属性:

management:
  endpoint:
    health:
      group:
        custom:
          show-details: "when-authorized"
          roles: "admin"
          status:
            order: "fatal,up"
            http-mapping:
              fatal: 500
              out-of-service: 500

如果你需要注册自定义的StatusAggregator或者HttpCodeStatusMapperbean用于与组一起使用,你可以使用Qualifier("grouname")

健康组也可以包含/排除CompositeHealthContributor。你也可以包含/排除某一个CompositeHealthContirbutor。可以使用组件的全限定名称做到这些,如下:

management.endpoint.health.group.custom.include="test/primary"
management.endpoint.health.group.custom.exclude="test/primary/b"

在上面的例子中,custom组将包含名称为primaryHealthContributor,它是组合test的一个组件。在这里,primary本身是一个组合并且使用名称BHealthContributor将从custom组排除。

监控组可以在主端口或者管理端口额外的路径上使用,在云平台上是比较有用的,例如Kubernetes,在这样的环境下,处于安全目的,actuator端点通常使用一个单独的管理端口。使用单独的端口可能导致不可靠的健康检查,因为主应用程序可能不能正确的工作即使健康检查是成功的。健康组可以使用如下额外的路径配置:

management.endpoint.health.group.live.additional-path="server:/healthz"

这将使live健康组在/healthz的主服务器端口可用。这个前缀是强制的而且还必须是server:(表示主要的服务器端口)或者management:(表示管理端口,如果已经配置)路径必须是单独的路径片段。

数据库健康状态

DataSource监控指标展示标准的数据源和路由数据源bean两者的健康状态。路由的数据源健康状态报货每一个它的目标数据源的健康状态。在健康端点的响应中,每一个路由数据源的目标使用它的路由键命名。如果在指标输出中,你不喜欢包括路由数据源,设置management.health.db.ignore-routing-data-sourcestrue

13.2.9. Kubernetes 探针

应用程序部署在Kubernetes可以使用Container Probes提供关于他们内部状态的信息。依据你的Kubernetes配置,kubelete调用这些探针并对结果作出响应。

默认情况下,Spring Boot管理你的Application Avalilability State。如果部署到Kubernaetes环境,actuator从ApplicationAvailability接口聚集LivenessReadiness信息并在专用的健康指标中使用该信息:LivenessStateHealthIndicatorReadinessStateHealthIndicator。在全局健康度端点展示这些指标(“/actuator/health”)。他们作为单独的HTTP探针使用健康组暴露:“/actuator/health/liveness"和”/actuator/health/readiness"。

你仍可以使用以下端点信息配置你的Kubernetes基础设施:

livenessProbe:
  httpGet:
    path: "/actuator/health/liveness"
    port: -port>
  failureThreshold: ...
  periodSeconds: ...

readinessProbe:
  httpGet:
    path: "/actuator/health/readiness"
    port: -port>
  failureThreshold: ...
  periodSeconds: ...

应该被设置为actuator端点可用的端口。它可以是主要的服务器端口或者,如果"management.server.prot"属性已经设置,也可以是单独的管理端口。

这些健康组是自动启用,只有当应用程序运行在Kubernetes环境。你可以使用management.endpoint.health.probes.enabled配置属性在任何环境启用他们。

如果应用程序的启动时间比配置的存活的时间长,Kubernetes提到"startupProbe"作为可能的解决方案。这个"startupProbe"在这里不是必须的,因为直到所有的启动任务已经完成"readinessProbe"才会失败。请查看在应用程序生命周期探针的行为是怎样的描述的章节。

如果你的Actuator端点被发布在一个单端的管理上下文,端点不使用相同的web基础设施(端口,连接池,框架组件)作为主要的应用程序。在这种情况下,即使主要的应用程序不能正确的工作,一个探针检测可以成功。(例如,他不能接收新的链接)。对于这种原因,在主要的服务器端口使livenessreadiness健康组可用是一个好主意。通过设置以下属性这些可以完成:

management.endpoint.health.probes.add-additional-paths=true

在主要的服务器端口上,在livez上将使liveness可用,在/readyz上使/readiness可用。

使用Kubernaetes 探针检查额外的状态

Actuator配置"liveness"和"readiness"探针作为Health Groups。这意味着所有的健康组特性对他们是可用的。例如,你可以配置额外的健康状态指标:

management:
  endpoint:
    health:
      group:
        readiness:
          include: "readinessState,customCheck"

默认情况下,Spring Boot 不会将其他的健康状态指标添加到这些组。

"liveness"探针不应该取决于对于外部系统的健康状态检查。如果应用程序的活性状态坏掉了,Kubernetes尝试通过重启应用程序实例解决该问题。这表示如果一个外部系统(例如数据库,Web API或者外部缓存)失败,Kubernates可能重启所有的应用程序实例并创建级联失败。

至于“准备就绪”探针,应用程序开发者必须谨慎地选择检查外部系统。对此,在准备就绪探针中,Spring Boot 不包括任何额外的健康状态检查。如果应用程序准备就绪状态实例是未就绪的,Kubernates不会路由流量到该实例。一些外部系统不会通过应用程序实例共享,这种情况下,他们可以包含在准备就绪探针。其他的外部系统可能对应用程序不是必不可少的(应用程序可以有断路器和后备方案),在这种情况下,他们绝对不应该包含在内。不幸地,一个由所有应用程序实例共享的外部系统是常见的,并且你必须见机行事:在准备就绪探针中包含它并希望当外部服务关闭时应用程序退出服务,或者应用程序退出服务时并处理堆栈上层的故障,可能在调用方中使用断路器。

如果应该程序的所有示例是未就绪的,使用type-ClusterIP或者NodePort的Kubernetes服务不会接收任何输入连接。没有HTTP响应(503等等),因为没有连接。使用type=LoadBalancer的服务可能或者可能不接受连接,取决于提供者。一个有明确入口的服务也以一种依赖于实现的方式进行响应-入口服务本身必须决定如何处理来自下游的“连接拒绝”。HTTP 503 很可能同时存在于负载均衡和入口中。

而且,如果应用程序使用Kubernetes 自动缩放,它可能会对应用程序退出负载均衡作出不同的反映,取决于它的自动伸缩的配置。

应用程序周期和探针状态

一个重要的Kubernetes探针支持的方面是他的应用程序生命周期的一致性。在AvailabilityState(它是在内存中的,应用程序的本地状态)和实际的探针(暴露该状态)是有显著的区别的。根据应用程序生命周期的各个阶段,探针可能是不可用的。

Spring Boot在应用程序启动和关闭期间推送应用程序事件,并且探针可以监听这些事件并保留AvailabilityState信息。

下表展示AvailabilityState和HTTP在不同的阶段连接的状态。

当Spring Boot应用程序启动:

启动阶段 活性状态 准备就绪状态 HTTP服务器 备注
启动中 BROKEN REFUSING_TRAFFIC 没有开始 Kubernetes检查“活跃”探针,如果时间较长,重启应用程序
已启动 CORRECT REFUSING_TRAFFIC 拒绝请求 应用程序上下文已经刷新.应用程序执行启动任务,但还不接收流量
就绪 CORRECT ACCEPTING_TRAFFIC 接收请求 启动任务已经完成,应用程序接收流量

当应用程序关停时:

关停阶段 活性状态 准备就绪状态 HTTP服务器 备注
运行中 CORRECT ACCEPTING_TRAFFIC 接收请求 停机已经请求
优雅停机 CORRECT REFUSING_TRAFFIC 拒绝新的请求 如果启用,优雅停机将处理正在处理的请求
完成停机 N/A N/A 服务器已经停机 应用程序上下文已经关闭并且应用程序已经关停

请查看Kubernetes容器生命周期章节了解关于Kubernates部署的信息。

13.2.10. 应用程序信息

应用程序信息暴露从你的ApplicationContext中定义的所有的InfoContributorbean收集的多个信息。Spring Boot包含多个自动配置的InfoContributorbean,并且你可以写你自己的。

自动配置的InfoContributor

在适当的时候,Spring自动配置以下InfoContributor:

ID 名称 描述 先决条件
build BuildInfoContributor 暴露构建信息 META-INF/build-info.properties资源
env EnvironmentInfoContributor 暴露来自Environment的名称以info.开头的任何属性 META-INF/build-info.properties资源
git GitInfoContributor 暴露git信息 git.properties资源
java JavaInfoContributor 暴露java运行时信息 没有
os OsInfoContributor 暴露操作系统信息 没有

个别的贡献者是否启用通过management.info..enabled属性控制。不同的贡献者在这个属性有不同的默认值,取决于他们的先决条件和他们所暴露的信息的性质。

由于没有先决条件的表示应该启用他们,env,javaos贡献者默认情况下是禁用的。每一个可以通过设置它的management.info..enabled属性为true启用。

buildgit信息贡献者默认情况下启用。每一个可以通过设置它的management.info..enabled属性为false禁用它。或者,要禁用每一个默认情况下通常启用的贡献者,设置management.info.defaults.enabled属性为false

自定义应用程序信息

env贡献者启用,你可以自定义通过设置info.* Spring 属性的info端点所暴露的数据。在info下的所有的Environment属性是自动暴露的。例如,你可以将以下设置添加到application.properties文件:

info:
  app:
    encoding: "UTF-8"
    java:
      source: "11"
      target: "11"

你也可以在构建时展开信息属性,不是硬编码这些值。
假设你使用Maven,你可以如下重写上面的示例:

info:
 app:
   encoding: "@project.build.sourceEncoding@"
   java:
     source: "@java.version@"
     target: "@java.version@"
Git提交信息

info端点的另一个有用的特性是他能够在项目构建时,发布关于git源码仓库状态的信息。如果GitPropertiesbean是可用的,你可以使用info端点暴露这些属性。

如果在根类路径git.properties文件可用,GitPropertiesbean是自动配置的。请查看“如果生成git信息”了解更多详情。

默认情况下,如果存在,端点暴露git.branchgit.commit.idgit.commit.time属性。如果你不想要在端点响应中的任何这些属性,他们需要从git.properties文件排除。如果你想展示全量的git信息(也就是,git.properties的全部内容),使用management.info.git.mode属性,如下:

management:
  info:
    git:
      mode: "full"

要在info端点完全禁用git提交信息,设置management.info.git.enabled属性为false,如下:

management:
  info:
    git:
      enabled: false
构建信息

如果BuildPropertiesbean可用,info端点也可以推送关于你的构建信息。如果在类路径中META-INF/build-info.properties文件可用这些将发生。

Maven和Gradle插件可以同时生成该文件。请查看"如何生成构建信息"了解更多详情。

Java信息

info端点推送关于Java运行时环境信息,请查阅JavaInfo了解更多详情。

OS信息

info端点推送关于操作系统信息,请查看QsInfo了解更多信息。

写自定义InfoContributors

为提供自定义应用程序信息,你可以注册实现InfoContributor接口的Spring bean。

下方的示例使用单个值贡献了example入口:

import java.util.Collections;

import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;

@Component
public class MyInfoContributor implements InfoContributor {

    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("example", Collections.singletonMap("key", "value"));
    }

}

如果你访问info端点,你应该看到包含以下额外条目响应:

{
    "example": {
        "key" : "value"
    }
}

13.3. 通过HTTP进行监控和管理

如果你在开发一个web应用程序,Spring Boot Actuator自动配置所有启用的端点通过HTTP暴露。默认的协议是使用端点的id/actuator的前缀作为URL路径。例如,health/actuator/health暴露的。

Actuator由Spring MVC和Spring WebFlux原生支持的。

Jackson是必须的依赖项,以便获取在API(HTML或者PDF)文档中记录正确的JSON响应 。

13.3.1. 自定义管理端点路径

有时候,自定义用于管理端点的前缀是非常有用的。例如,你的应用程序可能已经准备使用/actuator用于其他目的。你可以使用management.endpoints.web.base-path属性改变你的管理端点前缀,如下示例所示:

management:
  endpoints:
    web:
      base-path: "/manage"

前面的application.properties历史修改端点从/actuator/{id}/manage/{id}(例如,/manage/info)。

除非管理端口已经配置以使用不同的HTTP端口暴露端口,management.endpoints.web.base-pathserver.servlet.context-path(对于servlet web应用程序)或者spring.webflux.base-path(对于reactive web应用程序)有关。如果management.server.port已经配置,management.endpoints.web.base-pathmanagement.servet.base-path有关。

如果你想映射端点到不同的路径,你可以使用management.endpoints.web.path-mapping属性。

以下示例重新将/actuator/health映射到/healthcheck

management:
  endpoints:
    web:
      base-path: "/"
      path-mapping:
        health: "healthcheck"

13.3.2. 自定义管理服务器端口

对于基于云部署,通过使用默认的HTTP端口暴露管理端点是明智的选择。然而,如果你应用程序运行在你自己的数据中心,你可以更喜欢使用不同的HTTP端口暴露端点。

你可以设置management.server.prot属性以改变HTTP端口,如下示例所示:

management:
  server:
    port: 8081

在Cloud Foundry,默认情况下,对于HTTP和TCP路由,应用程序接收请求只在端口8080上。如果你想要在Cloud Foundry使用自定义的管理端口,你需要显示地设置应用程序路由,以便将流量转发到自定义端口。

13.3.3. 配置特定的管理SSL

当使用自定义端口配置,你也可以使用多种management.server.ssl属性配置它自己的SSL配置管理服务器。例如,这样做,当主应用程序使用HTTPS,让管理服务器通过HTTP是可用,正如下方属性设置所展示的:

server:
  port: 8443
  ssl:
    enabled: true
    key-store: "classpath:store.jks"
    key-password: "secret"
management:
  server:
    port: 8080
    ssl:
      enabled: false

或者,主服务器和管理服务器可以使用SSL,但是使用不同的key存储,如下:

server:
  port: 8443
  ssl:
    enabled: true
    key-store: "classpath:main.jks"
    key-password: "secret"
management:
  server:
    port: 8080
    ssl:
      enabled: true
      key-store: "classpath:management.jks"
      key-password: "secret"

13.3.4. 自定义管理服务器地址

你可以自定义地址,通过设置management.server.address属性,在地址管理端点是可用的。如果你想只监听一个外部或者面向ops的网络或者只监听来自localhost的链接,这样做是有用的。

只有当端口与主服务器端口不同时,你可以在不同的地址监听。

以下示例application.properties不允许远程管理链接:

management:
  server:
    port: 8081
    address: "127.0.0.1"

13.3.5 禁用HTTP端点

如果你不想在HTTP上暴露端点,你可以设置管理端口为-1,如下示例所示:

management:
  server:
    port: -1

你也可以通过使用management.ednpoints.web.exposure.exclude属性实现这个功能,如下示例所示:

management:
  endpoints:
    web:
      exposure:
        exclude: "*"

13.4. 通过JMX监控和管理

Java Management Extensions(JMX)提供一个标准的机制来监控和管理应用程序。默认情况下,这个特性不会启用。你可以通过设置spring.jmx.enabled配置属性为true打开它。Spring Boot使用mbeanServerID暴露最合适的MBeanServer作为bean。使用Spring JMX注解(@ManagedResource,@ManagedAttribute或者@ManagedOperation)来注解你的任何bean都将被暴露给它。

如果你的平台提供一个标准的MBeanServer,Spring Boot使用它,如果必须,默认为VMMBeanServer。如果所有的MBeanServer失败,创建一个新的MBeanServer

请查看JmxAutoConfiguration类了解更多详情。

默认情况下,Spring Boot还将管理端点暴露为org.springframework.boot域下的JMX MBean。要完全控制在JMX域注册的端点,考虑注册你自己的EndpointObjectNameFactory实现。

13.4.1. 自定义MBean名称

MBean的名称通常生成自端点的id。例如,health端点作为org.springframework.boot:type=Endpoint,name=Health暴露。

如果你的应用程序包含多余一个Spring ApplicationContext,你可能会发现名称冲突。要解决这个问题,你可以设置spring.jmx.unique-names属性为true,以便MBean名称一直唯一。

你也可以定制在其下暴露的端点的JMX域。以下设置展示在application.properties中这样做的一个示例:

spring:
  jmx:
    unique-names: true
management:
  endpoints:
    jmx:
      domain: "com.example.myapp"

13.4.2. 禁用JMX端点

如果你不想通过JMX暴露端点,你可以设置management.endpoints.jmx.exposure.exclude属性为*,如下示例所示:

management:
  endpoints:
    jmx:
      exposure:
        exclude: "*"

13.5. 日志记录器

Spring Boot Actuator包括展示的能力和配置运行时应用程序的日志级别。你可以查看整个列表或者个别的日志记录器的配置,该配置包括显示配置日志级别以及日志框架给它的有效日志记录级别。这些级别可以是以下中的一个:

  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF
  • null
    null表示没有明确的配置

13.5.1. 配置一个日志记录器

要配置一个给定的日志记录器,将一部分实体POST到资源URI,如下示例所示:

{
    "configuredLevel": "DEBUG"
}

要“重置”特定的日志记录器级别(使用默认的配置代替),你可以将null值传入作为configuredLevel

13.6. 指标

Spring Boot Actuator提供对Micrometer依赖项管理和自动配置。支持众多监控系统的应用程序指标外观,包括:

  • AppOptics
  • Atlas
  • Datadog
  • Dynatrace
  • Elastic
  • Ganglia
  • Graphite
  • Humio
  • Influx
  • JMX
  • KairosDB
  • New Relic
  • OpenTelemetry
  • Prometheus
  • SignalFx
  • Simple (in-memory)
  • Stackdriver
  • StatsD
  • Wavefront

要学习更多关于Micrometer的功能,请查看他的参考文档,特别是概念部分。

13.6.1. 开始

Spring Boot 自动配置一个组合的MeterRegistry并将注册信息添加到在类路径中发现的每一个支持的实现组合。在你运行的类路径中存在一个依赖项micrometer-registry-{system}就足以让Spring Boot配置注册表。

大多数注册表共享通用的特性。例如,你可以禁用一个常见的注册表即使Micrometer注册表是在类路径中。以下示例禁用Datadog:

management:
  datadog:
    metrics:
      export:
        enabled: false

你也可以通过特定的注册表属性禁用所有的注册表除非已经启用,如下示例所示:

management:
  defaults:
    metrics:
      export:
        enabled: false

Spring Boot也将任何自动配置的注册表到在Metrics类上的全局静态组合的注册表,除非你明确告诉他不要这样做:

management:
  metrics:
    use-global-registry: false

你可以注册任意数量的MeterRegistryCustomizerbean来进一步配置注册表,例如在使用注册表注册任意meter之前,应用通用的标签:

import io.micrometer.core.instrument.MeterRegistry;

import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return (registry) -> registry.config().commonTags("region", "us-east-1");
    }

}

你可以通过更具体的描述泛型,将自定义应用到特定的注册表实现:

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.graphite.GraphiteMeterRegistry;

import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
        return (registry) -> registry.config().namingConvention(this::name);
    }

    private String name(String name, Meter.Type type, String baseUnit) {
        return ...
    }

}

Spring Boot 也配置内建的仪表装置,通过配置或者相关的注解标记来控制它。

13.6.2. 监控系统支持

这部分简单描述每一个支持的监控系统。

AppOptics

默认情况下,AppOptics注册表定期地推送指标到api.appoptics.com/vi/measurements。要输出指标到SaaS AppOptics,你的API token必须提供:

management:
  appoptics:
    metrics:
      export:
        api-token: "YOUR_TOKEN"
Atlas

默认情况下,指标被输出到在你本地运行的机器 的Atlas。你可以提供Atlas服务器的位置:

management:
  atlas:
    metrics:
      export:
        uri: "https://atlas.example.com:7101/api/v1/publish"
Datadog

Datadog注册表周期性推送指标到datadoghq。要输出指标到Datadog,你必须提供你的API键:

management:
  datadog:
    metrics:
      export:
        api-key: "YOUR_KEY"

如果你额外的提供一个应用程序的key(可选的),然后是原数据,比如仪表描述,类型和基本单元也将输出:

management:
  datadog:
    metrics:
      export:
        api-key: "YOUR_API_KEY"
        application-key: "YOUR_APPLICATION_KEY"

默认情况下,指标将被发送到Datadog US站点(api.datadoghq.com)。如果你的Datadog项目托管在其他站点上,或者你需要通过代理发送指标,直接配置URI:

management:
  datadog:
    metrics:
      export:
        uri: "https://api.datadoghq.eu"

你也可以改变指标被发送到Datadog的间隔:

management:
  datadog:
    metrics:
      export:
        step: "30s"
Dynatrace

Dynatrace提供两项指标摄取API,这两个API都是为Micrometer实现的。你可以在这里发现关于Micrometer Dynatrace 摄取的文档。在v1命名空间的配置属性只当输出到实现序列 v1 API时应用。在v2命名空间的配置属性只当输出到指标v2 API时应用。注意在某一时间这个集成只能输出到v1或者v2的API版本,最好是v2。如果device-id(v1是必须的但是在v2中不使用)在v1命名空间设置,指标将输出到v1端点。否则,输出到v2

v2 API

你可以两种方式使用v2 API:
自动配置:
对于通过OneAgent或者对Kubernaetes通过Dynatrace OperatorDynatrace的主机自动配置是可用的。

本地 OneAgent:如果OneAgent在主机中正在运行,指标自动化输出到本地OneAgent摄取端点。摄取端点将指标转发到Dynatrace后端。

Dynatrace Kubernetes Operator:当使用安装的Dynatrace Operator运行在Kubernetes中时,注册表将自动从操作符选择你的端点URI和API token。

这个是默认的行为,除了依赖于io.micrometer:micrometer-registry-dynatrace外,不需要特殊的设置。

手工配置:
如果没有自动配置可用,Metrics v2 API的端点和API的token是必须的。API token必须有"摄取指标(metrics.ingest)权限设置。我们建议将token的作用域限制到这一权限。你必须确保这个端点URI包含这个路径(例如,/api/v2/metrics/ingest):

根据你的部署选项,Metrics API v2的URL 摄取端点是不同的:

  • SaaS:https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest
  • 管理的部署:https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest

下方的示例使用example环境id配置指标输出:

management:
  dynatrace:
    metrics:
      export:
        uri: "https://example.live.dynatrace.com/api/v2/metrics/ingest"
        api-token: "YOUR_TOKEN"

当使用Dynatrace v2 API,下方可选的特性是可用的(更多细节可以在Dynatrace文档中找到):

  • Metric key前缀:设置一个前缀,该前缀作为导出指标键的前缀。
  • 使用Dynatrace元数据丰富:如果OneAgent或者Dynatrace 操作者正在运行,使用额外的元数据丰富指标(例如,关于主机,进程或者触摸屏)
  • 默认维度:指定key-value对,可以将其添加到所有输出的指标。如果使用Micrometer指定相同key的标签,他们重写默认的维度。
  • 使用Dynatrace Summary仪器:在某些情况中,Micrometer Dynatrace注册表创建的指标被拒绝。在Micrometer 1.9.x,通过引进特定的Dynatrace 汇总一起已经修复这个。设置这个开关为false强制Micrometer 返回1.9.x之前的行为。只有当迁移Micrometer从1.8.x到1.9.x 遭遇问题时,才应该使用它。

它可以不指定一个URI和API token,如下示例所示。在这个情景中,使用自动化配置的端点:

management:
  dynatrace:
    metrics:
      export:
        # Specify uri and api-token here if not using the local OneAgent endpoint.
        v2:
          metric-key-prefix: "your.key.prefix"
          enrich-with-dynatrace-metadata: true
          default-dimensions:
            key1: "value1"
            key2: "value2"
          use-dynatrace-summary-instruments: true # (default: true)
v1 API(遗留的)

Dynatrace v1 API指标注册表通过使用TimeSeries v1 API定期推送指标到配置的URI。向后兼容现有设置,当device-id已经设置(v1所需要的,不是在v2中使用的),指标被输出到Timeseries v1端点。为输出指标到Dynatrace,你的API token,device ID和URI必须指定:

management:
  dynatrace:
    metrics:
      export:
        uri: "https://{your-environment-id}.live.dynatrace.com"
        api-token: "YOUR_TOKEN"
        v1:
          device-id: "YOUR_DEVICE_ID"

对于v1 API,你必须指定不带路径的基本的环境URI,因为v1端点路径是自动添加的。

独立于版本的设置

除了API端点和token,你也可以改变其指标被发送到Dynatrace的间隔。默认输出间隔是60s。以下示例设置输出间隔为30秒:

management:
  dynatrace:
    metrics:
      export:
        step: "30s"

你可以在Micrometer文档和Dynatrace文档中找到更多信息关于如何设置对Micrometer 的Dynatrace输出。

Elastic

默认情况下,指标被输出到在你本机上运行的Elastic。你可以通过使用以下属性提供Elastic服务器位置来使用:

management:
  elastic:
    metrics:
      export:
        host: "https://elastic.example.com:8086"
Ganglia

默认情况下,指标被输出到在你本机上运行的Ganglia。你可以提供Ganglia服务器主机和端口,如下示例所示:

management:
  ganglia:
    metrics:
      export:
        host: "ganglia.example.com"
        port: 9649
Graphite

默认情况下,指标被输出到运行在你本机的Graphite。你可以提供Graphite服务器主机和端口,如下示例所示:

management:
  graphite:
    metrics:
      export:
         host: "graphite.example.com"
         port: 9004

Micrometer提供默认的HierarchicalNameMapper,它管理维度meterID如何被映射到平面分层的名字。

要控制这个行为,定义你的GraphiteMeterRegistry和提供你自己的HierarchicalNameMapper。一个自动配置的GraphiteConfigClockbean被提供,除非你定义你自己的:

import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.HierarchicalNameMapper;
import io.micrometer.graphite.GraphiteConfig;
import io.micrometer.graphite.GraphiteMeterRegistry;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyGraphiteConfiguration {

   @Bean
   public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig config, Clock clock) {
       return new GraphiteMeterRegistry(config, clock, this::toHierarchicalName);
   }

   private String toHierarchicalName(Meter.Id id, NamingConvention convention) {
       return ...
   }

}
Humio

默认情况下,Humio注册表周期性推送指标到cloud.humio.com。为输出指标到SaaS Humio,你必须提供你的API token:

management:
  humio:
    metrics:
      export:
        api-token: "YOUR_TOKEN"

你应该也可以配置一个或者多个标签识别数据源到哪个指标被推送:

management:
  humio:
    metrics:
      export:
        tags:
          alpha: "a"
          bravo: "b"
Influx

默认情况下,指标使用默认的配置被输出到运行在本机的Influx v1实例。为输出指标到InfluxDB v2,为写入指标配置orgbucket和身份认证token。你可以使用以下命令提供要使用的Influx服务器:

management:
  influx:
    metrics:
      export:
        uri: "https://influx.example.com:8086"
JMX

Micrometer 提供将分层的映射提供到JMX,主要是一种廉价且可移植的方式来本地展示指标。默认情况下,指标被输出到metricsJMX域。你可以使用以下命令提供要使用的域:

management:
  jmx:
    metrics:
      export:
        domain: "com.example.app.metrics"

Micrometer提供默认的HierarchicalNameMapper,它管理维度meterID如何映射到平面分层的名字:

要控制这种行为,定义你自己的JmxMeterRegistry和提供你自己的HierarchicalNameMapper。自动配置的JmxConfigClock bean被提供,除非你定义你自己的:

import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.HierarchicalNameMapper;
import io.micrometer.jmx.JmxConfig;
import io.micrometer.jmx.JmxMeterRegistry;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyJmxConfiguration {

   @Bean
   public JmxMeterRegistry jmxMeterRegistry(JmxConfig config, Clock clock) {
       return new JmxMeterRegistry(config, clock, this::toHierarchicalName);
   }

   private String toHierarchicalName(Meter.Id id, NamingConvention convention) {
       return ...
   }

}
KairosDB

默认情况下,指标被输出到运行在你本地机器上的KairosDB。你可以使用以下配置提供要使用的KairosDB 服务器:

management:
  kairos:
    metrics:
      export:
        uri: "https://kairosdb.example.com:8080/api/v1/datapoints"
New Relic

New Relic注册表周期性推送指标到New Relic。要输出指标到New Relic,你必须提供你的API键和账户ID:

management:
  newrelic:
    metrics:
      export:
        api-key: "YOUR_KEY"
        account-id: "YOUR_ACCOUNT_ID"

你也可以改变在指标被发送到New Relic的间隔:

management:
  newrelic:
    metrics:
      export:
        step: "30s"

默认情况下,通过REST调用推送指标,但是你也可以使用Java Agent API,如果在类路径上存在它:

management:
  newrelic:
    metrics:
      export:
        client-provider-type: "insights-agent"

最后,你可以通过定义你自己的NewRelicClientProviderbean完全控制。

OpenTelemetry

默认情况下,指标被输出到在你本机上运行的OpenTelemetry。你可以使用以下配置提供要使用的OpenTelemtry 指标端点的位置:

management:
  otlp:
    metrics:
      export:
        url: "https://otlp.example.com:4318/v1/metrics"
Prometheus

Prometheus期望通过抓取和轮询单个实例来获取指标。Spring Boot在/actuator/prometheus提供一个actuator端点以适当的格式呈现Prometheus scrape。

默认情况下,端点是不可用的,必须公开。请查看暴露端点了解更多详情。

以下示例scrape_config添加到prometheus.yml:

scrape_configs:
  - job_name: "spring"
    metrics_path: "/actuator/prometheus"
    static_configs:
      - targets: ["HOST:PORT"]

Prometheus范例也是支持的。要启用这个特性,SpanContextSupplierbean应用存在。如果你使用Spring Cloud Sleuth,它将为你自动配置,而且你还可以创建你想要的自己的bean。
请查看Prometheus Docs,因为这个特性需要在Prometheus端显示地启用,并且它只有在使用OpenMetrics格式时支持。

对于可能存在时间不长的临时或者批量作业无法抓取,你可以使用Promethus Pushgateway向Prometheus暴露指标。要启用Prometheus Pushgateway支持,添加以下依赖到你的项目:

<dependency>
    <groupId>io.prometheusgroupId>
    <artifactId>simpleclient_pushgatewayartifactId>
dependency>

当Prometheus Pushgateway依赖在类路径中已经存在并且management.prometheus.metrics.export.pushgateway.enable属性已经设置为truePrometheusPushGatewayManagerbean是自动配置的。这个管理指标的推送到Prometheus Pushgateway。

你可以使用management.prometheus.metrics.exprot.pushgateway下的属性调整PrometheusPushGatewayManager 。对于高级配置,你也可以提供你自己的PrometheusPushGatewayManagerbean。

SignalFx

SignalFx注册表周期性推送指标到SignalFx。要输出指标到SignalFx,你必须提供你的访问token:

management:
  signalfx:
    metrics:
      export:
        access-token: "YOUR_ACCESS_TOKEN"

你也可以改变指标发送到SignalFx的间隔:

management:
  signalfx:
    metrics:
      export:
        step: "30s"
Simple

Micrometer附带一个简单的,内存的后端,如果没有其他注册表配置,该后端自动作为应急计划使用。这让你看到在指标端点那些收集的指标。

一旦你使用任何其他可用的后端,内存后端禁用它自己。你也可以显示地禁用它:

management:
  simple:
    metrics:
      export:
        enabled: false
Stackdriver

Stackdriver注册表周期性地推送指标到Stackdriver。要暴露指标到SaaS Stackdriver,你必须提供你的Google Cloud项目ID:

management:
  stackdriver:
    metrics:
      export:
        project-id: "my-project"

你也可以改变指标被发送到Stackdriver的间隔:

management:
  stackdriver:
    metrics:
      export:
        step: "30s"
StatsD

StatsD注册表通过UDP急切地推送指标到StatsD代理。默认情况下,指标被暴露到在你本机运行的StatsD代理。你可以使用以下配置提供所使用的StatsD代理主机,端口和协议:

management:
  statsd:
    metrics:
      export:
        host: "statsd.example.com"
        port: 9125
        protocol: "udp"

你也可以改变StatsD行协议使用(它默认是Datadog):

management:
  statsd:
    metrics:
      export:
        flavor: "etsy"
Wavefront

Wavefront注册表周期性推送指标到Wavefront。如果你直接暴露指标到Wavefront,你必须提供你的API token:

management:
  wavefront:
    api-token: "YOUR_API_TOKEN"

或者,你可以使用Wavefront端或者在你的环境中的内部协议来转发指标数据到Wavefront API 主机:

management:
  wavefront:
    uri: "proxy://localhost:2878"

如果你推送指标到Wavefront代理(正如在Wavefront文档中描述的),主机必须是proxy://HOST:PORT格式。

你也可以改变指标发送到Wavefront的间隔:

management:
  wavefront:
    metrics:
      export:
        step: "30s"

13.6.3. 指标和计量器支持

Spring Boot为各种各样的技术提供自动的计量器注册。在大多数情景,默认提供合理的指标,可以将其推送到任意的支持的监控系统。

JVM指标

自动配置通过使用核心的Micrometer类启用JVM指标。JVM指标在jvm.仪器名称发布的。

提供以下JVM指标:

  • 各种内存和缓冲池详情信息
  • 与垃圾收集相关的统计信息
  • 线程利用率
  • 加载和卸载类的数量
  • JVM版本信息
  • JIT编译时间
系统指标

自动配置通过使用核心的Micrometer类启用系统指标。系统指标通过system.process.dist.仪器名称发布。

提供以下系统指标:

  • CPU指标
  • 文件描述符指标
  • 正常运行时间指标(应用程序已经运行的时间和绝对开始时间的固定测量仪)
  • 可用磁盘空间
应用程序启动指标

自动配置暴露应用程序启动时间指标:

  • application-started.time:启用应用程序的时间
  • application.ready.time:应用程序就绪到服务请求的时间

指标是通过应用程序的全量限定名称标记的。

日志记录器指标

自动配置对Logback和Log4j2启用事件指标。明细在log4j2.events.或者logback.events.仪器名称被发布。

任务执行和计划指标

自动配置启用所有可用的ThreadPoolTaskExecutorThreadPoolTaskScheduler bean的仪器,只要底层ThreadPoolExecutor是可用的。指标通过执行器名称标记,执行器的名称来源bean名称。

Spring MVC指标

自动配置启用所有Spring MVC控制器和函数处理器处理的请求的测量仪器,默认情况下,指标使用名称http.server.requests生成。你可以通过management.metrics.web.server.request.metric-name属性定制这个名称。

@Timed注解支持在@Controller类和@RequestMapping方法上(请查看@Time 注解支持了解更多明细)。如果你不想记录所有Spring MVC请求的指标,你可以设置management.metrics.web.server.request.autotime.enabledfalse并且只使用@Timed注解代替。

标签 描述
exception 任何异常的普通的类名称,当处理请求时被抛出的异常
method 请求的方法(例如,get或者POST
outcome 请求的结果,基于响应的状态码。1xx是INFORMATIONAL,2xx是SUCCESS,3xx是REDIRECTION,4xx是CLIENT_ERROR ,5xx是SERVER_ERROR
status 响应的HTTP状态码(例如200500
uri 在变量替换之前的请求URI模板,如果可能的话,例如,/api/person/{id}

要增加默认标签,提供一个或者多个实现WebMvcTagsContributor@Bean。要替换默认的标签,提供实现了WebMvcTagsProvider@Bean

在这些情况中,在web控制器处理的异常不会作为请求指标标签被记录。应用程序可以通过将处理异常设置为请求属性来选择并记录异常。

默认情况下,处理所有的请求。要定制过滤器,提供实现了FilterRegistrationBean@Bean

Spring WebFlux指标

自动配置启用通过Spring WebFlux控制器和函数式处理器处理的所有请求的测量仪器。默认情况下,指标通过名称http.server.requests生成。你可以通过设置management.metrics.web.server.request.metric-name属性定制名称。

@Timed注解支持在@Controller类和@RequestMapping方法上(请查看@Timed 注解支持了解更多详情)。如果你不想为所有的Spring WebFlux请求记录指标,你可以设置management.metrics.web.server.request.autotime.enabledfalse并仅仅使用@Timed注解代替。

标签 描述
exception 任何异常的普通的类名称,当处理请求时被抛出的异常
method 请求的方法(例如,get或者POST
outcome 请求的结果,基于响应的状态码。1xx是INFORMATIONAL,2xx是SUCCESS,3xx是REDIRECTION,4xx是CLIENT_ERROR ,5xx是SERVER_ERROR
status 响应的HTTP状态码(例如200500
uri 在变量替换之前的请求URI模板,如果可能的话,例如,/api/person/{id}

要增加默认的标签,提供一个或者多个实现WebFluxTagsContributor@Bean。要替换默认的标签,提供实现WebFluxTagsProvider的bean。

在这些情况中,在控制器中处理的异常和处理器函数不会作为请求指标标签记录的。应用程序可以通过设置处理异常作为请求参数选择和记录异常。

HTTP客户端指标

Spring Boot Actuator管理RestTemplateWebClient的测量仪器。为此,你必须注入自动配置的构造器并使用它创建实例:

  • RestTemplateBuilder用于RestTemplate
  • WebClient.Builder用于WebClient

你也可以手工应用负责此检测的定制器,也就是MetricsRestTemplateCustomizerMetricsWebClientCustomizer

默认情况下,指标通过http.client.requests生成。你可以通过设置management.metrics.web.client.request.metric-name属性定制名称。

默认情况下,通过装有仪器的客户端生成的指标使用以下信息标记:

标签 描述
clientName URI的主机部分
method 请求放发(例如,GET或者POST
outcome 请求结果,基于响应的状态码。1xx是INFORMATIONAL,2xx是SUCCESS,3xx是REDIRECTION,4xx是CLIENT_ERROR ,5xx是SERVER_ERROR.其他是UNKNOWN
status 如果可用,响应的HTTP状态码(例如,200或者500)或者在IO问题情况下的IO_ERROR。其他是CLIENT_ERROR
uri 在变量替换之前的请求的URI模板,如果可能(例如,api/person/{id}

要定制标签,取决于你的客户端选择,你可以提供实现了RestTemplateExchangeTagsProvider或者WebClientExchangeTagsProvider@BeanRestTemplateExchangeTagsWebClientExchangeTags中有方便的静态函数。

Tomcat指标

自动配置只有当MBeanRegistry启用时才会启用Tomcat测量仪器。默认情况下,MBeanRegistry是禁用的,但是你可以通过设置server.tomcat.mbeanregistry.enabledtrue启用它。

Tomcat指标在tomcat.仪器名称被发布。

缓存指标

自动配置启用所有启动时可用的Cache实例的测量仪器,使用cache前缀的指标。缓存监测仪器是基本的指标集合标准标准化。而且,特定的缓存指标也是可用的。

支持以下缓存类库:

  • Cache2k
  • Caffenine
  • Hazelcast
  • 任何满足JCache(JSR-107)实现。
  • Redis
    指标通过缓存的名称和CacheManager的名称被标记,后者派生自bean的名称。

只有启动时配置的缓存才会绑定到注册表。对于在缓存配置中没有定义的缓存,例如动态创建的缓存或者启动阶段之后程序化创建的缓存,需要显示的注册。我们提供了一个CacheMetricsRegistrarbean来简化这个过程。

DataSource指标

自动配置启用所有有效的使用前缀为jdbc.connection的指标的DataSource对象的监测仪器。数据源监测会产生表示池中当前活动,空闲,允许的最大连接数,允许的最小连接数。

指标也可以通过基于bean名称计算的DataSource的名称标记。

默认情况下,Spring Boot提供所有支持的数据源的元数据。如果你最喜欢的数据源不支持,你可以添加额外的DataSourcePoolMetadataProviderbean.请查看DataSourcePoolMetadataProvidersConfiguration了解示例。

而且,特定的Hikari指标通过hikaricp前缀暴露。每一个指标通过池的名称标记(你可以使用spring.datasource.name控制)。

Spring Data Repository指标

自动配置启用所有Spring Data Repository方法调用的检测仪器。默认情况下,指标使用spring.data.repository.invocations名称生成。你可以通过设置management.metrics.data.repository.metric-name定制这个名称。

@Timed注解支持在Repository类和方法上的(请查看@Timed注解支持了解详情)。如果你不想记录所有Repository调用的指标,你可以设置management.metrics.data.repository.autotime.enbaledfalse并仅仅使用@Timed注解代替。

默认情况下,仓库调用关联的指标使用以下信息标记:

标记 描述
repository Repository简单的类名称
method 被调用的Repository方法名称
state 结果状态(SUCCESSERROR,CANCELED或者RUNNING
exception 来自调用抛出的任何异常的简单类名称

要替换默认的标签,提供实现了RepositoryTagsProvider@Bean

RabbitMQ指标

自动配置启用所有使用有效的名称为rabbitmq的指标RabbitMQ连接工厂的监测仪器。

Spring Integration指标

只要MeterRegistrybean可用,SpringIntegration自动提供Micrpmeter支持。指标通过spring.integration.仪器名称发布。

Kafka指标

自动配置注册MicrometerConsumerListenerMicrometerProducerListener分别用于自动配置的消费者工厂和生产者工厂。它也注册KafkaStreamsMicrometerListener用于StreamsBuilderFactoryBean。对于更多细节,请查看Spring Kafka文档的Micrometer Native Metrics章节。

MongoDB指标

这个章节简单的描述了MongoDB的可用指标。

MongoDB 命令指标

自动配置使用自动配置的MongoClient的注册MongoMetricsCommandListener

为向底层的MongoDB驱动程序发出的每命令创建一个名称为mongodb.driver.commands的定时器指标。默认情况下,每个指标使用以下信息标记:

标签 描述
command 发布的命令的名称
cluster.id 将命令发送到集群的标志符
server.address 将命令发送到服务器的地址
status 命令的结果(SUCCESS或者FAILED

要替换默认的指标标签,定义MongoCommandTagsProviderbean,如下示例所示:

import io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCommandTagsProviderConfiguration {

    @Bean
    public MongoCommandTagsProvider customCommandTagsProvider() {
        return new CustomCommandTagsProvider();
    }

}

要禁用自动配置的命令指标,设置以下属性:

management:
  metrics:
    mongo:
      command:
        enabled: false
MongoDB连接池指标

自动配置使用自动配置的MongoClient注册MongoMetricsConnectionPoolListener

以下标准指标为连接池创建:

  • mongodb.driver.pool.size报告链接池当前大小,包括空闲和使用中的成员。
  • mongodb.driver.pool.checkedout报告当前正在使用的链接数量。
  • mongodb.driver.pool.waitqueuesize报告来自池的连接的等待队列的当前大小。

默认情况下,每一个指标使用以下信息标记:

标签 描述
cluster.id 连接池所对应的集群标志符
server.address 连接池对应的服务器地址

要替换默认的指标标签,定义一个MongoConnectionPoolTagsProviderbean:

import io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyConnectionPoolTagsProviderConfiguration {

    @Bean
    public MongoConnectionPoolTagsProvider customConnectionPoolTagsProvider() {
        return new CustomConnectionPoolTagsProvider();
    }

}

要禁用自动配置的链接池指标,设置以下属性:

management:
  metrics:
    mongo:
      connectionpool:
        enabled: false
Jetty指标

自动配置通过使用Micrometer的JettyServerThreadPoolMetrics绑定指标用于Jetty的ThreadPool。Jetty的实例指标通过使用Micrometer的JettyConnectionMetrics绑定,当server.ssl.enabled设置为true时,也可以通过Micrometer的JettySslHandshakeMetrics

@Timed注解支持

你可以使用来自io.micrometer.core.annotation包的@Timed注解与前面描述的几个支持的技术。如果支持,你可以使用注解在类级别或者方法级别。

例如,以下代码展示你可以如何使用注解来对@RestController中的所有请求映射增加监测:

import java.util.List;

import io.micrometer.core.annotation.Timed;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Timed
public class MyController {

    @GetMapping("/api/addresses")
    public List<Address> listAddress() {
        return ...
    }

    @GetMapping("/api/people")
    public List<Person> listPeople() {
        return ...
    }

}

如果你只是想监测单个映射,你可以在方法上使用注解而不是在类上:

import java.util.List;

import io.micrometer.core.annotation.Timed;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/api/addresses")
    public List<Address> listAddress() {
        return ...
    }

    @GetMapping("/api/people")
    @Timed
    public List<Person> listPeople() {
        return ...
    }

}

如果你想要对特定的方法改变改变计时细节,你也可以组合类级别和方法级别注解:

import java.util.List;

import io.micrometer.core.annotation.Timed;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Timed
public class MyController {

    @GetMapping("/api/addresses")
    public List<Address> listAddress() {
        return ...
    }

    @GetMapping("/api/people")
    @Timed(extraTags = { "region", "us-east-1" })
    @Timed(value = "all.people", longTask = true)
    public List<Person> listPeople() {
        return ...
    }

}

使用longTask = true@Timed注解对方法启用一个长任务计时器。长任务计时器需要一个单独的指标名称,可以和短任务计时器一起使用。

Redis指标

自动配置注册MicrometerCommandLatencyRecorder用于自动配置的LettuceConnectionFactory。要了解更多细节,请查看Lettuce文档的Micrometer Metrics 部分。

13.6.4. 注册自定义指标

要注册自定义指标,将MeterRegistry注入到你的组件:

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;

import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final Dictionary dictionary;

    public MyBean(MeterRegistry registry) {
        this.dictionary = Dictionary.load();
        registry.gauge("dictionary.size", Tags.empty(), this.dictionary.getWords().size());
    }

}

如果你的指标依赖于其他bean,我们建议你使用MeterBinder来注册他们:

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.binder.MeterBinder;

import org.springframework.context.annotation.Bean;

public class MyMeterBinderConfiguration {

    @Bean
    public MeterBinder queueSize(Queue queue) {
        return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
    }

}

使用MeterBinder确保设置正确的依赖项关系并确保在检索指标的值时该bean是可用的。如果你发现你在组件或者应用程序之间重复地使用一套指标,那么MeterBinder实现也是非常有用的。

默认情况下,来自所有MeterBinderbean的指标是自动绑定到Spring管理的MeterRegistry

13.6.5. 定制个别的指标

如果你需要应用定制到特定的Meter实例,你可以使用io.micrometer.core.instrument.config.MeterFilter接口。

例如,如果你想重命名mytag.region标签为mytag.area用于所有的以com.example开头的meter ID,你可以按照以下来做:

import io.micrometer.core.instrument.config.MeterFilter;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyMetricsFilterConfiguration {

    @Bean
    public MeterFilter renameRegionTagMeterFilter() {
        return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
    }

}

默认情况下,所有的MeterFilterbean是自动绑定到Spring管理的MeterRegistry。确保通过使用Spring管理的MeterRegistry注册你的指标,而不是Metrics上的任何静态方法。这些使用全局注册表并不是Spring管理的。

常用标签

常用标签通常用于对操作环境维度维度挖掘,例如主机,实例,地区,栈和其他。常用的标签被应用到所有meter并且可以被配置,如下示例所示:

management:
  metrics:
    tags:
      region: "us-east-1"
      stack: "prod"

前面的示例添加值分别为us-east-1prodregionstack标签到所有的meter。

如果你使用Graphite,常用标签的顺序是非常重要的。因为使用这个方法不能保证常用标签的顺序,Graphite用户建议定义自定义的MeterFilter代替。

Per-meter属性

除了MeterFilterbean,你可以通过使用属性对每一个仪器基础应用一个限制的定制集合。每一个仪器定制应用到以给定名称开头的任何仪器ID。以下示例禁用以example.remote开头ID的任何仪器:

management:
  metrics:
    enable:
      example:
        remote: false

以下属性允许每一个仪器定制:
*** Table 9. Per-meter customizations***

属性 描述
management.metrics.enable 是否阻止仪器发出任何指标
management.metrics.distribution.percentiles-histogram 是否发布适合计算可聚集(跨维度)百分比近似值的柱状图
management.metrics.distribution.minimum-expected-value,
management.metrics.distribution.maximum-expected-value
通过压缩期望值的范围发布少量柱状图桶
management.metrics.distribution.percentiles 在你的应用程序中发布计算的百分比的值
management.metrics.distribution.expiry,
management.metrics.distribution.buffer-length
给最近的样本更大的权重,使用一个可配置的缓冲长度,在一个可配置的期限的环缓冲区循环累计他们
management.metrics.distribution.slo 发布一个使用你的服务级别目标定义的存储器的累积的柱状图

要了解关于percentiles-histogram,percentilesslo的概念的更多细节,请查看Micrometer文档的“Histograms and percentiles”部分。

13.6.6. 指标端点

Spring Boot提供metrics端点,你可以使用它诊断地检查应用程序收集的指标。默认情况下这个端点是不可用的并必须暴露。请查看暴露端点了解更多详情。

导航到/actuator/metrics展示可用仪器名称列表。你可以通过提供他的名字作为选择器深入展示关于特别的仪器信息–例如,/actuator/metrics/jvm.memory.max

在这里你使用的名字应该与代码中使用的名字匹配,不是与已经装运到用于监控系统经过命名约定规范化后的名字。换句话说,如果jvm.memory.max在Prometheus中显示为jvm_memory_max,这是因为它的蛇形命名规则,当在metrics端点检查仪器时,你应该仍使用jvm.memory.max作为选择器。

你也可以添加任意数量的tag=KEY:VALUE查询参数到URL的末尾以便在仪器上维度深入-例如,/actuator/metrics/jvm.memory.max?tag=area:nonheap

报告的测量值是所有匹配仪器名称和已经应用的任意标签的仪器统计的和。在前面的示例中,返回的Value统计是堆中“代码缓存”,“压缩的类空间”,“元空间”区域的内存足迹最大值的和。如果你想要只查看“元空间”的最大值大小,你可以添加额外的tag=id:Metaspace – 也就是,/actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace

13.7. 审核

一旦Spring Security开始运作,Spring Boot Actuator有灵活的发布事件的审核框架(默认情况下,“身份认证成功”,“失败”和“访问受限”异常)。这个特性对于报告和实现基于身份验证失败的锁定策略是非常有用的。

你可以通过在应用程序配置中提供类型为AuditEventRepository的bean启用审核。为了方便起见,Spring Boot提供一个InMemoryAuditEventRepositoryInMemoryAuditEventRepository有限制功能,而我们建议只在开发环境使用它。对于生产环境,考虑创建自己的可替代的AuditEventRepository实现。

13.7.1. 自定义审核

要定制推送安全时间,你可以停工你自己的AbstractAuthenticationAuditListenerAbstractAuthorizationAuditListener实现。

你也可以为你自己的业务服务使用审核服务。为此,注入AuditEventRepositorybean到你自己的组件并直接使用它或者使用Spring的ApplicationEventPublisher发布一个AuditApplicationEvent(通过实现ApplicationEventPublisherAware)。

13.8. HTTP追踪

你可以通过提供你的应用程序的配置中类型为HttpTraceRepository的bean来启用HTTP追踪。为了方便起见,Spring Boot提供InMemoryHttpTraceRepository,它存储对最后100(默认)请求响应的交换追踪。InMemoryHttpTraceRepository与其他追踪解决方案相比是有限制的,我们建议只在开发环境使用它。对于生产环境,我们建议使用生产就绪追踪或者可观察的解决方案,例如Zipkip或者Spring Cloud Sleuth。或者,你可以创建你自己的HttpTraceRepository

你可以使用httptrace端点来获得关于存储在HttpTraceRepository中的请求-响应交换信息。

13.8.1. 自定义HTTP追踪

要自定义包含在每一个追踪的项目,使用management.trace.http.include配置属性。对于高级定制,考虑注册你自己的HttpExchangeTracer实现。

13.9. 过程控制

spring-boot模块,你可以发现创建文件的两个类,他们对过程控制是非常有用的。

  • ApplicationPidFileWriter创建包含应用程序PID的文件(默认情况下,在应用程序文件名为application.pid的目录)
  • WebServerPortFileWriter创建包含运行web服务器端口的文件(或者多个)( 默认情况下,在应用程序文件名为application.port的目录)。

默认情况下,这些写入是不激活的,但是你可以启用他们:

  • 通过扩展配置
  • 程序化启用过程控制

13.9.1. 扩展配置

META-INF/spring.factories文件中,你可以激活写PID文件的监听器:

org.springframework.context.ApplicationListener=\
org.springframework.boot.context.ApplicationPidFileWriter,\
org.springframework.boot.web.context.WebServerPortFileWriter

13.9.2. 程序化启用过程控制

你也可以通过调用SpringApplication.addListeners(...)方法激活一个监听器并传到合适的Writer类。这个方法也让你在Writer构造器中定制文件名称和路径。

13.10. Cloud Foundry Support

Spring Boot的actuator模块包括额外的支持,当你发布到兼容的Cloud Found实例时,它是激活的。/cloudfoundryapplication路径提供一个可替代的安全路由到所有的@Endpointbean。

扩展的支持让Cloud Foundry管理 UI(比如你可以用来展示已发布的应用程序的web应用程序)通过Spring Bootactuator信息增强。例如,应用程序状态页可以包含全量的健康状态信息,而不是典型的"运行中"或者“停止”状态。

/cloudfoundryapplication路径不能让常规用户直接访问。要使用这个端点,你必须使用请求传入一个验证的UAA token。

13.10.1. 禁用扩展的Cloud Foundry Actuator支持

如果你想要全面禁用/cloudfoundryapplication端点,你可以添加以下设置到你的application.properties文件:

management:
  cloudfoundry:
    enabled: false

13.10.2. Cloud Foundry 自签名证书

默认情况下,对/cloudfoundryapplication端点的安全验证会对各种Cloud Foundry服务进行SSL调用。如果你的Cloud Foundry UAA或者Cloud Controller服务使用自签名的证书,你需要设置以下属性:

management:
  cloudfoundry:
    skip-ssl-validation: true

13.10.3. 自定义上下文路径

如果服务器的上下文路径已经配置到除了/任何地方,在根应用程序Cloud Foundry端点是不可用的。例如,如果server.servlet.context-path=/app,Cloud Foundry端点在/app/cloudfoundryapplication/*是可用的。

如果你期望Cloud Foundry端点在/cloudfoundryapplication/*一直可用,不管服务器的上下文路径,你需要在应用程序中显示地配置它。这个配置的不同,取决于web服务器的使用。对于Tomcat,你可以添加以下配置:

import java.io.IOException;
import java.util.Collections;

import jakarta.servlet.GenericServlet;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.apache.catalina.Host;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCloudFoundryConfiguration {

    @Bean
    public TomcatServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory() {

            @Override
            protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
                super.prepareContext(host, initializers);
                StandardContext child = new StandardContext();
                child.addLifecycleListener(new Tomcat.FixContextListener());
                child.setPath("/cloudfoundryapplication");
                ServletContainerInitializer initializer = getServletContextInitializer(getContextPath());
                child.addServletContainerInitializer(initializer, Collections.emptySet());
                child.setCrossContext(true);
                host.addChild(child);
            }

        };
    }

    private ServletContainerInitializer getServletContextInitializer(String contextPath) {
        return (classes, context) -> {
            Servlet servlet = new GenericServlet() {

                @Override
                public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
                    ServletContext context = req.getServletContext().getContext(contextPath);
                    context.getRequestDispatcher("/cloudfoundryapplication").forward(req, res);
                }

            };
            context.addServlet("cloudfoundry", servlet).addMapping("/*");
        };
    }

}

13.11. 下一步读什么

你可能想读关于图形工具,例如Graphite。

除此之外,你可以继续读关于"发布选项"或者抢先一步了解关于Spring Boot的构建工具插件的一些深入信息。

14. 发布Spring Boot应用程序

Spring Boot的灵活的打包选项在部署应用程序时提供了大量的选择。你可以部署Spring Boot应用程序到各种各样的云平台,虚拟/真实的机器或者在Unix系统使他们完全可执行。

这个部分涵盖一些更常用的部署场景。

14.1. 发布到云

Spring Boot的可执行jar是为大多数流行的云Paas(平台及服务)提供商准备的。这些提供商往往要求你“携带你自己的容器”。他们管理应用程序进程(不是特定的Java应用程序),所以他们需要中间层,以便使你的应用程序适应云中运行进程的概念。

两个比较流行的云提供商,Heroku和Cloud Foundry,利用“构建打包”方法。这个构建打包将你部署的代码封装在启动应用程序所需的任何内容中。它可能是JDK和java调用,一个内嵌的web服务器,或者全面的应用程序服务器。构建打包是可插入的,但是理想情况下,你应该尽可能少的对它进行定制。这个减少不受你控制的功能的痕迹。它将开发环境和生产环境的差异减到最少。

在理想情况下,你的应用程序,比如Spring Boot可执行jar,需要运行的所有东西都打包其中。

在这部分,我们将了解如何让在入门章节我们开发的应用程序在云启动和运行。

14.1.1. Cloud Foundry

Cloud Foundry提供默认的构建打包,如果没有其他指定的构建打包,默认的将生效。Cloud Foundry Java构建打包已经非常好的支持Spring应用程序,包括Spring Boot。你可以发布单独的可执行的jar以及传统的.war打包的应用程序。

一旦你已经构建你的应用程序(例如,通过使用mvn clean package)并且已经安装cf命令行工具,使用cf push命令部署你的应用程序,将你编译的.jar的路径代入。在推送应用程序之前请确保使用cf命令行客户端登陆。以下行展示了使用cf push命令部署应用程序:

$ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar

在前面的历史中,我们将acloudyspringtime代入为你给的cf任何值作为应用程序的名称。

请查看cf push文档了解更多选项。如果在相同的目录中存在Cloud Foundrymanifest.yml文件,则认为它存在。

基于这点,cf开始上传应用程序,生成类似于以下示例的输出:

Uploading acloudyspringtime... OK
Preparing to start acloudyspringtime... OK
-----> Downloaded app package (8.9M)
-----> Java Buildpack Version: v3.12 (offline) | https://github.com/cloudfoundry/java-buildpack.git#6f25b7e
-----> Downloading Open Jdk JRE 1.8.0_121 from https://java-buildpack.cloudfoundry.org/openjdk/trusty/x86_64/openjdk-1.8.0_121.tar.gz (found in cache)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.6s)
-----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (found in cache)
       Memory Settings: -Xss349K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xms681574K -XX:MetaspaceSize=104857K
-----> Downloading Container Certificate Trust Store 1.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-certificate-trust-store/container-certificate-trust-store-1.0.0_RELEASE.jar (found in cache)
       Adding certificates to .java-buildpack/container_certificate_trust_store/truststore.jks (0.6s)
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)
Checking status of app 'acloudyspringtime'...
  0 of 1 instances running (1 starting)
  ...
  0 of 1 instances running (1 starting)
  ...
  0 of 1 instances running (1 starting)
  ...
  1 of 1 instances running (1 running)

App started

恭喜!应用程序现在已经运行了。

只要你的应用程序运行,你可以使用cf apps命令验证部署的应用程序的状态,如下示例所示:

$ cf apps
Getting applications in ...
OK

name                 requested state   instances   memory   disk   urls
...
acloudyspringtime    started           1/1         512M     1G     acloudyspringtime.cfapps.io
...
绑定服务

默认情况下,关于运行应用程序的元数据以及服务连接信息已经作为环境变量公开给应用程序(例如:$VCAP_SERVICES)。这个架构决策是由于Cloud Foundry的支持多语言特点(任何语言和平台支持作为构建打包)。过程作用域环境变量是语言无关的。

环境变量并不总是最简单的API,所以Spring Boot自动提取他们并将数据扁平化放入到属性,可以通过Spring的Environment实现访问他们,如下示例所示:

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class MyBean implements EnvironmentAware {

    private String instanceId;

    @Override
    public void setEnvironment(Environment environment) {
        this.instanceId = environment.getProperty("vcap.application.instance_id");
    }

    // ...

}

所以的Cloud Foundry属性是以vacp开头。你可以使用vcap以访问应用程序信息(例如应用程序的公共URL)和服务信息(例如数据库凭证)。请查看‘CloudFoundryVcapEnvironmentPostProcessor’Javadco了解完整详情。

Java CFEnv项目更适合像配置DataSource这样的任务。

14.1.2. Kubernetes

Spring Boot通过检查"*_SERVICE_HOST""*_SERVICE_PORT"变量自动检测Kubernetes部署环境。你可以使用spring.main.colud-platform配置属性覆盖这个检测。

Spring Boot帮助你管理应用程序的状态并且使用Actuator用HTTP Kubernetes Porbes导出它。

Kubernetes容器生命周期

当Kubernetes删除应用程序实例,停机步骤同时涉及几个子系统:停机钩子,注销服务,从负载均衡中移除实例…因为关机过程并行发生(由于分布式系统的特性),在此期间存在一个窗口期,流量可以路由到一个也开始进行管理处理的pod。

你可以在预停止的处理器中定义一个休眠执行来防止请求被路由到一个已经准备开始停止的pod。这个休眠应该足够长,以便新的请求停止路由到pod,并且其持续时间因部署而异。预停止处理器可以通过使用在pod的配置文件的PodSpec进行配置,如下:

spec:
  containers:
  - name: "example-container"
    image: "example-image"
    lifecycle:
      preStop:
        exec:
          command: ["sh", "-c", "sleep 10"]

一旦预停止钩子已经完成,SIGTERM将被发送到容器并且优雅停机将开始,允许任何剩下的处理中的请求完成。

当Kubernetes发送SIGTERM信号到pod,它等待一个被称为终止宽限期的特定时间(对此的默认时间是30秒)。如果容器在宽限期之后仍在运行,他们将发送SIGKILL 信号并且强制地移除。如果pod超过30秒关闭,这可能是因为你添加了spring.lifecycle.timeout-per-shutdown-phase,确保通过在Pod的YAML中设置terminationGracePeriodSeconds选项增加终止宽限期。

14.1.3. Heroku

Heroku是另一个有名的PaaS平台。要定制Heroku构建,你提供一个Procfile,它提供了需要部署应用程序的咒语。Heroku分配一个端口给Java应用程序使用,然后保证路由到外部的URI有效。

你必须配置你的应用程序监听到正确的端口。以下示例展示用于我们启动器的REST应用程序的Procfile

web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar

Spring Boot使-D参数可以作为Spring Environment实例的属性访问。server.port配置属性被提供给内嵌的Tomcat或者Undertow实例然后他们启动时使用这个端口。$PORT环境变量通过Heroku PaaS分配给我们的。

这应该是你需要的所有东西。Heroku部署最常见的部署工作流程是git push代码到生产环境,如下示例所示:

$ git push heroku main

他将输出以下结果:

Initializing repository, done.
Counting objects: 95, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (78/78), done.
Writing objects: 100% (95/95), 8.66 MiB | 606.00 KiB/s, done.
Total 95 (delta 31), reused 0 (delta 0)

-----> Java app detected
-----> Installing OpenJDK 1.8... done
-----> Installing Maven 3.3.1... done
-----> Installing settings.xml... done
-----> Executing: mvn -B -DskipTests=true clean install

       [INFO] Scanning for projects...
       Downloading: https://repo.spring.io/...
       Downloaded: https://repo.spring.io/... (818 B at 1.8 KB/sec)
        ....
       Downloaded: https://s3pository.heroku.com/jvm/... (152 KB at 595.3 KB/sec)
       [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/...
       [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ...
       [INFO] ------------------------------------------------------------------------
       [INFO] BUILD SUCCESS
       [INFO] ------------------------------------------------------------------------
       [INFO] Total time: 59.358s
       [INFO] Finished at: Fri Mar 07 07:28:25 UTC 2014
       [INFO] Final Memory: 20M/493M
       [INFO] ------------------------------------------------------------------------

-----> Discovering process types
       Procfile declares types -> web

-----> Compressing... done, 70.4MB
-----> Launching... done, v6
       https://agile-sierra-1405.herokuapp.com/ deployed to Heroku

To [email protected]:agile-sierra-1405.git
 * [new branch]      main -> main

现在,你的应用程序应该启动并运行在Heroku。要了解更多细节,请查看部署Spring Boot应用程序到Heroku。

14.1.4. OpenShift

OpenShift有许多资源描述如何部署Spring Boot应用程序,包括:

  • 使用S2I构造器
  • 架构指南
  • 在Wildfly作为传统的Web应用程序运行
  • OpenShift Commons Briefing

14.1.5. Amazon Web服务(AWS)

Amazon Web Service提供多种方式安装Spring Boot应用程序,或者传统的web应用程序(war)或者带有内嵌web服务器的可执行jar文件。选项包括:

  • AWS Elastic Beanstalk
  • AWS Code Deploy
  • AWS OPS Works
  • AWS Cloud Formation
  • AWS Container Registry

每一个有不同的特性和定价模式。在这个文档中,我们描述了使用AWS Elastic Beanstalk的方法

AWS Elastic Beanstalk

正如在官方Elastic Beanstalk Java 指南中所描述的,有两个主要选项来部署Java应用程序。你可以使用"Tomcat平台"或者“Java SE平台”。

使用Tomcat平台

这个选项应用到提供一个war文件的Spring Boot项目。无需特定的配置。你只需要遵循官方指南。

使用Java SE平台

这个选项应用到提供一个jar文件的Spring Boot项目并运行在内嵌的web容器。Elastic Beanstalk环境在端口80运行一个nginx实例来代理运行在端口5000的真正的应用程序。为配置它,添加以下行到你的application.properties文件:

server.port=5000

上传二进制文件而不是源文件
默认情况下,Elastic Beanstalk上传源文件并在AWS中编译他们。然而,最好是上传二进制文件代替。为此,添加类似于以下行到你的.elasticbeanstalk/config.yml文件:

deploy:
   artifact: target/demo-0.0.1-SNAPSHOT.jar

通过设置环境类型减少耗时
默认情况下,Elastic Beanstalk环境是负载均衡的。这个负载均衡器有明显消耗。为避免该消耗,设置环境类型为"单实例",正如在Amazon文档中描述的。你也可以通过使用CLI和以下命令创建单个实例环境:

eb create -s
总结

这个是访问AWS最简单的方式之一,但还有更多的事情需要涉及,比如如何将Elastic Beanstalk集成到CI/CD工具,使用Elastic Beanstalk Maven插件代替CLI等待。有博客包含这些更细节的主题。

14.1.6. CloudCaptain和Amazon Web Services

CloudCaptain的工作原理是将Spring Boot可执行jar或者war转变为最小的VM镜像,可以不加修改地部署到VirtualBox或者AWS。CloudCaptain为Spring Boot提供了深度集成,并使用Spring Boot配置文件信息来自动化配置端口和健康度检查URL。CloudCaptain充分利用这个信息用于它生成的镜像以及用于它提供的所有资源(实例,安全组,灵活的负载均衡等等)。

一旦你已经创建一个ClouodCaptain账户,连接它到你的AWS账户,安装CloudCaptain客户端的最新版本并确保应用程序通过Maven或者Gradle构建(例如,使用mvn clean package),你可以使用类似于以下命令部署你的Spring Boot应用程序到AWS:

$ boxfuse run myapp-1.0.jar -env=prod

请查看boxfuse run文档了解更多选项。如果在当前目录存在boxfuse.conf文件,则考虑它。

默认情况下,CloudCaptain在启动时激活Spring 名称为boxfuse配置文件。如果你的可执行jar或者war包含一个application-boxfuse.properties文件,CloudCaptain基于它包含的属性文件进行配置。

在这一点上,CloudCaptain为你的应用程序创建一个镜像,上传它并配置和启动在AWS上的必须的资源,在输出中的结果类似于以下示例:

Fusing Image for myapp-1.0.jar ...
Image fused in 00:06.838s (53937 K) -> axelfontaine/myapp:1.0
Creating axelfontaine/myapp ...
Pushing axelfontaine/myapp:1.0 ...
Verifying axelfontaine/myapp:1.0 ...
Creating Elastic IP ...
Mapping myapp-axelfontaine.boxfuse.io to 52.28.233.167 ...
Waiting for AWS to create an AMI for axelfontaine/myapp:1.0 in eu-central-1 (this may take up to 50 seconds) ...
AMI created in 00:23.557s -> ami-d23f38cf
Creating security group boxfuse-sg_axelfontaine/myapp:1.0 ...
Launching t2.micro instance of axelfontaine/myapp:1.0 (ami-d23f38cf) in eu-central-1 ...
Instance launched in 00:30.306s -> i-92ef9f53
Waiting for AWS to boot Instance i-92ef9f53 and Payload to start at https://52.28.235.61/ ...
Payload started in 00:29.266s -> https://52.28.235.61/
Remapping Elastic IP 52.28.233.167 to i-92ef9f53 ...
Waiting 15s for AWS to complete Elastic IP Zero Downtime transition ...
Deployment completed successfully. axelfontaine/myapp:1.0 is up and running at https://myapp-axelfontaine.boxfuse.io/

现在,你的应用程序应该已经启动并在WAS上运行。

请查看关于在EC2部署Spring Boot应用程序的博客以及CloudCaptain Spring Boot集成文档来入门使用Maven构建来运行应用程序。

14.1.7. Azure

这个入门指南带你了解部署Spring Boot应用程序到Azure Spring Cloud或者Azure App Service。

14.1.8. Google Cloud

Google Cloud有几个选项可以用来发动Spring Boot应用程序。最容易上手的可能是APP引擎,但是你也可以发现在容器中使用容器引擎或者在虚拟机使用计算引擎运行Spring Boot的方式。

要在App引擎中运行,首先,你可以在UI中创建一个项目,为你设置唯一的标志符,同时设置HTTP路由。将Java应用程序添加到项目中并保持为空,然后使用Google Cloud SDK从命令行或者CI构建将Spring Boot应用程序推送到该位置。

App引擎标准要求你使用WAR打包,按照这些步骤来部署App引擎标准应用程序到Google Cloud。

或者,App Engine Flex要求你创建一个app.yaml文件来描述你app所需要的资源。通常,你将这个文件放入到src/main/appengine,它应该类似于以下文件:

service: "default"

runtime: "java"
env: "flex"

runtime_config:
  jdk: "openjdk8"

handlers:
- url: "/.*"
  script: "this field is required, but ignored"

manual_scaling:
  instances: 1

health_check:
  enable_health_check: false

env_variables:
  ENCRYPT_KEY: "your_encryption_key_here"

你可以通过添加项目ID到构建配置来部署app(例如,使用Maven插件),如下示例所示:

<plugin>
    <groupId>com.google.cloud.toolsgroupId>
    <artifactId>appengine-maven-pluginartifactId>
    <version>1.3.0version>
    <configuration>
        <project>myprojectproject>
    configuration>
plugin>

然后使用mvn appengine:deploy部署(如果首先你需要身份认证,构建失败)

14.2. 安装Spring Boot应用程序

除了使用java -jar运行Spring Boot应用程序,也可以制造在Unix系统完全可执行的应用程序。完全可执行的jar可以被执行就像任何其他可执行二进制或者使用init.d或者systemd注册它一样。当在常用的生产环境安装或者管理Spring Boot应用程序时是有帮助的。

完全可执行jar通过在文件前嵌一个额外的脚本运行。当前,一些工具不接收这种格式,所以你可能不会一直能使用这个技术,jar -xf提取一个已经制作为完全可执行的jar或者war文件可能默默地失败。建议如果你只打算直接执行它,你制作的jar或者war完全可执行,而不是使用java -jar运行它或者将它部署到servlet容器。

zip64格式的jar文件不能被制作完全可执行。尝试这样做会导致jar文件在直接执行或者使用java -jar执行时报告被损坏。一个标准格式的jar文件包含一个或者多个zip64格式嵌套的jar可以完全可执行。

要使用Maven创建一个完全可执行的jar,使用以下插件配置:

<plugin>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-maven-pluginartifactId>
    <configuration>
        <executable>trueexecutable>
    configuration>
plugin>

以下示例展示等价的Gradle配置:

tasks.named('bootJar') {
    launchScript()
}

你仍可以通过键入./my-application.jarmy-application是你的artifact的名字)运行你的应用程序。目录包含被用作你应用程序的工作目录的jar。

14.2.1. 支持的操作系统

默认的脚本支持大多数Linux发行版并且在CentOS和Ubuntu做了测试。其他平台,比如OS X和FreeBSD,需要一个自定义的embeddedLaunchScript的使用。

14.2.2. Unix/Linux服务

Spring Boot应用程序可以使用init.d或者systemd很容易作为Unix/Linux服务启动。

作为init.d服务安装(System V)

如果你配置Spring Boot的Maven或者Gradle插件来生成完全执行jar,你不能使用一个自定义embeddedLaunchScript,你的应用程序可以用作一个init.d服务。为此,符号链接这个jar到init.d来支持标准的start,stop,restartstatus命令。

脚本支持一下特性:

  • 以拥有jar文件的用户身份启动服务
  • 使用/var/run//.pid跟踪应用程序的PID
  • 将控制台日志写入到/var/log/.log

假设你有安装在/var/myapp的Spring Boot应用程序,要安装一个Spring Boot应用程序作为init.d服务,创建一个符号链接,如下:

$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

一旦安装,你可以以平常的方式启动或者停止服务。例如,在基于Debian的系统,你可以使用以下命令启动它:

$ service myapp start

如果你的应用程序启动失败,检查写入/var/log/.log日志文件是否有错误。

你也可以通过使用标准的操作系统工具给应用程序做标记来实现自动化启动。例如,在Debian,你可以使用以下命令:

$ update-rc.d myapp defaults <priority>
使init.d服务安全

以下内容是关于如何使作为一个init.d服务运行的Spring Boot应用程序安全的参考的集合。本文并不是要详尽地列出加固应用程序及其运行环境所做的所有事情。

当root用户运行时,就像当root用户用来启动一个init.d服务这种情况一样,默认的可执行脚本作为在RUN_AS_USER环境变量指定用户运行应用程序。当环境变量没有设置,使用拥有jar文件的用户代替。你应该从不使用root用户运行应用程序,所以RUN_AS_USER应该从不使用root并且你的应用程序的jar应该从不被root用户拥有。反而,创建一个特定的用户运行应用程序并设置RUN_AS_USER环境变量或者使用chown使他成为jar文件的拥有者,如下示例所示:

$ chown bootapp:bootapp your-app.jar

在这种情况,默认的可执行脚本作为bootapp用户运行应用程序。

要减少应用程序用户被盗用的可能性,你应该考虑阻止它使用登陆Shell。例如,你可以设置账号的shell为usr/sbin/nologin

你也应该采取措施来阻止应用程序的jar文件的修改。首先,配置它的权限以便它不能被写入并只能被他自己读和执行,如下示例所示:

$ chmod 500 your-app.jar

第二,你也应该采取措施来限制如果正在运行的应用程序或者账号被盗用的危害。如果一个攻击者获得访问,他们可能使jar文件可写并改变他们的内容。防范这种情况的一种方式是使用chattr使其不可修改,如下示例所示:

$ sudo chattr +i your-app.jar

这个将防止任何用户,包括root,来修改jar。

如果root用来控制应用程序的服务,你使用.conf文件来定制它的启动,通过root用户读取和评估.conf文件。它应该被响应的保护。使用chmod以便文件只能通过拥有者读取并使用chown来使root为所有者,如下示例所示:

$ chmod 400 your-app.conf
$ sudo chown root:root your-app.conf
作为systemd服务安装

systemd是System V初始系统的继承者并且现在被许多现在Linux发行版使用。尽管你可以继续使用init.d脚本与systemd,它也可以使用systemd‘服务’脚本发动Spring Boot应用程序。

假设你有安装在/var/myapp的Spring Boot应用程序,要安装Spring Boot应用程序为systemd服务,创建一个名称为myapp.service的脚本并将它放入到/etc/systemd/system目录。以下脚本提供一个示例:

[Unit]
Description=myapp
After=syslog.target

[Service]
User=myapp
ExecStart=/var/myapp/myapp.jar
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

记住改变Descrption,UserExecStart字段为你的应用程序。

ExecStart字段没有声明脚本动作命令,他意味着默认使用run命令。

注意,与作为init.d服务运行时不同,运行应用程序的用户,PID文件和控制台日志文件是通过systemd本身管理的,因为必须在’service’脚本中使用合理的字段配置。查阅服务单元配置管理页面了解更多详情。

要标记应用程序在系统启动时自动启动,使用以下命令:

$ systemctl enable myapp.service

运行man systemctl了解更多详情。

定制启动脚本

通过Maven或者Gradle插件写的默认的内嵌启动脚本可以以许多方式定制。对于大多数人,使用默认的脚本连同一些定制通常是足够的。如果你发现你不能定制你所需要的东西,使用embeddedLaunchScript选项来完全地写你自己的文件。

当编写启动脚本时定制它

在将启动脚本写入到jar文件时定制它的元素通常是有意义的。例如,init.d脚本可以提供一个’描述’。因为你预先知道这个描述(你不需要更改),你可能在jar生成时提供它。

要定制编写的元素,使用embeddedLaunchScriptPropertiesSpring Boot Maven插件选项或者Spring Boot Gradle插件的脚本的properties属性。

默认的脚本支持以下属性替代:

名称 描述 Gradle默认 Maven默认
mode 脚本模式 auto auto
initInfoProvides "INIT INFO"的Provides部分 ${task.baseName} ${project.artifactId}
initInfoRequiredStart "INIT INFO"的Required-Start部分 $remote_fs $syslog $network $remote_fs $syslog $network
initInfoRequiredStop "INIT INFO"的Required-Stop部分 $remote_fs $syslog $network $remote_fs $syslog $network
initInfoDefaultStart "INIT INFO"的Default-Start部分 2 3 4 5 2 3 4 5
initInfoDefaultStop "INIT INFO"的Default-Stop部分 0 1 6 0 1 6
initInfoShortDescription "INIT INFO"的Short-Description部分 ${project.descrption}(求助于${task.baseName})的单行版本 ${project.name}
initInfoDescription "INIT INFO"的Description部分 ${project.descrption}(求助于${task.baseName} ${project.descrption}(求助于${task.baseName}
initInfoChkconfig "INIT INFO"的chkconfig部分 2345 99 01 2345 99 01
confFolder CONF_FOLDER的默认值 包含jar的文件夹 包含jar的文件夹
inlinedConfScript 依赖于应该内联在默认的启动脚本的文件脚本。这个可以用来设置环境变量,例如任何外部配置加载之前的JAVA_POTS
logFolder LOG_FOLDER的默认值。仅校验init.d服务
logFilename LOG_FILENAME的默认值。仅校验init.d服务
pidFolder PID_FOLDER的默认值。仅校验init.d服务
pidFilename PID_FOLDER中PID文件名称的默认值。仅校验init.d服务
useStartStopDaemon start-stop-daemon命令可用,是否应该使用它来控制进程 true true
stopWaitTime STOP_WAIT_TIME的默认值,以秒为单位。只校验init.d服务 60 60
当运行时定制脚本

对于在jar已经被书写的之后需要定制的脚本的项目,你可以使用环境变量或者配置文件.

以下环境属性使用默认的脚本支持:

变量 描述
MODE 操作的"模式"。默认值取决于构建jar的方式,但是它通常auto(意味着它试图通过检测它是否是init.d目录中的符号猜测它是否是一个初始化脚本)。你可以显示设置它为service以便`stop
RUN_AS_USER 操作的"模式"。默认值取决于构建jar的方式,但是它通常auto(意味着它试图通过检测它是否是init.d目录中的符号猜测它是否是一个初始化脚本)。你可以显示设置它为service以便`stop
USE_START_STOP_DAEMON 如果start-stop-daemon可用,是否使用它控制进程。默认为true
PID_FOLDER pid文件夹的根名称(默认为/var/run
LOG_FOLDER 存放日志文件的文件夹名称(默认为/var/log
CONF_FOLDER 读取.conf文件的文件夹的名称(默认与jar文件夹一样)
LOG_FILENAME LOG_FOLDER中日志文件的名称(默认.log
APP_NAME app名称.如果jar自符号链接运行,这个脚本猜测app名称。如果它不是一个符号链接或者你想显示地设置app名称,这个是有用的
RUN_ARGS 传入到程序(Spring Boot应用)的参数
JAVA_HOME 使用默认的PATH发现java可执行的位置,但是如果$JAVA_HOME/bin/.java存在一个可执行jar,可以显示地设置它
JAVA_OPTS 当启动时传入到JVM的选项
JARFILE jar文件明确的位置,以防脚本用来启动jar但是实际上没有jar嵌入
DEBUG 如果不为空,在shell进程设置-x标志,允许你查看脚本逻辑
STOP_WAIT_TIME 在强制停机之前,停止应用程序所需等待的时间,以秒为单位(默认60

PID_FOLDER,LOG_FOLDERLOG_FILENAME变量只对于init.d服务进行校验。对于systemd,通过使用‘service’脚本实现等价的定制。请查看服务单元配置管理页面了解更多详情。

除了JARFILEAPP_NAME,在前面章节的设置列表可以通过使用.conf文件配置。这个文件期望挨着jar文件并且有相同的名字只是以.conf结尾而不是.jar.例如,名称为/var/myapp/myapp.jar的jar使用名称为/var/myapp/myapp.conf配置文件,如下示例所示:
myapp.conf

JAVA_OPTS=-Xmx1024M
LOG_FOLDER=/custom/log/folder

要了解如何适当地保护这个文件,请查看针对使init.d service安全的参考。

14.2.3. Microsoft Windows Services

一个Spring Boot应用程序通过使用winsw可以作为Windows服务启动。

A(单独维护的示例) 描述了如何逐笔为Spring Boot应用程序创建Window服务。

14.3. 下一步读什么

请查看Cloud Foundry,Heroku,OpenShift和Boxfuse web站点了解关于PaaS可以提供的这种特性的更多信息。这里仅仅是四个最出名的Java PaaS提供商。因为Spring Boot非常适合基于云部署,所以你也可以大量地考虑其他提供商。

下一章节继续介绍Spring Boot CLI,或者你可以抢先一步阅读构建工具插件。

15. Spring Boot CLI

Spring Boot CLI是一个命令行工具,如果你想快速开发一个Spring 应用程序,你可以它。它让你运行Groovy脚本,这意味着你可以使用类似于类Java预发而无需那么多的样板代码。你也可以引导一个新的项目或者为其写你自己的命令。

15.1. 安装CLI

Spring Boot CLI(command line interface)可以通过使用 SDKMAN!(SDK管理器)或者使用Homebrew或者如果你是OSX用户 来使用MacPorts进行手动安装。请查看在入门章节安装Spring Boot CLI来了解全面的安装介绍。

15.2. 使用CLI

一旦你已经安装CLI,你可以通过键入spring和按下Enter在命令行来使用它。如果你运行spring没有任何参数,展示一个帮助画面,如下:

$ spring
usage: spring [--help] [--version]
       <command> [<args>]

Available commands are:

  run [options] <files> [--] [args]
    Run a spring groovy script

  _... more command help is shown here_

你可以键入spring help来获取更多关于任何支持的命令的信息,如下示例所示:

$ spring help run
spring run - Run a spring groovy script

usage: spring run [options] <files> [--] [args]

Option                     Description
------                     -----------
--autoconfigure [Boolean]  Add autoconfigure compiler
                             transformations (default: true)
--classpath, -cp           Additional classpath entries
--no-guess-dependencies    Do not attempt to guess dependencies
--no-guess-imports         Do not attempt to guess imports
-q, --quiet                Quiet logging
-v, --verbose              Verbose logging of dependency
                             resolution
--watch                    Watch the specified file for changes

version命令提供一个快速的方式验证你正在使用哪个版本的Spring Boot,如下:

$ spring version
Spring CLI v3.0.0-SNAPSHOT

15.2.1. 使用CLI运行应用程序

你可以通过使用run命令编译和运行Grooy源码。Spring Boot CLI是完全自包含的,所以你不需要任何额外的Groovy安装。

以下示例展示了一个使用Groovy的“hello world”web应用程序书写:

@RestController
class WebApplication {

    @RequestMapping("/")
    String home() {
        "Hello World!"
    }

}

要编译和运行应用程序,键入以下命令:

$ spring run hello.groovy

要传入命令行参数到应用程序,使用--来分隔命令与"spring"命令行参数,如下示例所示:

$ spring run hello.groovy -- --server.port=9000

要设置JVM命令行参数,你可以使用JAVA_OPTS环境变量,如下示例所示:

$ JAVA_OPTS=-Xmx1024m spring run hello.groovy

当在Microsoft Windows设置JAVA_OPTS时,一定要引用全部说明,例如set "JAVA_OPTS=-Xms256m -Xmx2048m"。这样做保证值正确传入到进程。

推导“抓取”依赖项

标准的Groovy包括一个@Grab注解,它让你声明第三方类库依赖。这个有用的技术让Groovy与Maven或者Gradle相同的方式下载jar,但没有要求你使用构建工具。

Spring Boot进一步扩展这个技术,并尝试推导哪个类库可以基于你的代码“抓取”。例如,因为WebApplication代码展示前面的使用@RestController注解,Spring Boot 抓取“Tomcat”和“Spring MVC”.

以下项目用作“抓取点”:

项目 抓取
JdbcTemplate,NamedParameterJdbcTemplate,DataSource JDBC应用程序
@EnableJms JMS应用程序
@EnableCaching 缓存抽象
@Test JUnit.
@EnableRabbit RabbitMQ.
扩展Specification Spock测试.
@EnableBatchProcessing Spring Batch.
@MessageEndpoint @EnableIntegration Spring Integration.
@Controller @RestController @EnableWebMvc Spring MVC + 内嵌Tomcat
@EnableWebSecurity Spring Security.
@EnableTransactionManagement Spring Transaction Management.

请查看Spring Boot CLI源码中的CompilerAutoConfiguration的子类来精确理解定制是如何应用的。

推导“抓住”坐标

Spring Boot通过让你指定一个没有group或者版本的依赖扩展Groovy的标准的@Grab支持(例如,@Grab('freemarker'))。这样做参考Spring Boot的默认依赖元数据来推导出artifact的group和版本。

默认引入语句

为帮助减少Groovy代码的大小,自动包含几个import语句。注意前面的示例如何引用@Component,@RestController,和@RequestMapping无需使用全量限定名称或者import语句。

许多Spring注解工作无需使用import语句。在添加引入之前,尝试运行你的应用程序来看看有什么失败。

自动化的Main方法

不像同等的Java应用程序,你不需要在Groovy脚本中包含一个public static void main(String[] args)方法。SpringApplication自动创建,使用你的编译的代码充当source

自定义依赖项管理

默认情况下,当解析@Grap声明时,CLI使用在spring-boot-dependencies中声明的依赖管理。额外的依赖管理,他覆盖了默认的依赖管理,使用@DependencyManagementBom注解配置它。这个注解的值应该指定一个或者多个Maven BOM的坐标(groupId:artifactId:version

例如,考虑以下声明:

@DependencyManagementBom("com.example.custom-bom:1.0.0")

前面的声明在Maven仓库com/example/custom-versions/1.0.0/下获得custom-bom-1.0.0.pom

当我们指定多个BOM时,他们按照声明他们的顺序应用,如下示例所示:

@DependencyManagementBom([
    "com.example.custom-bom:1.0.0",
    "com.example.another-bom:1.0.0"])

前面的示例表明在another-bom中的依赖管理覆盖在custom-bom中的依赖管理。

你可以使用@Grab的任何地方使用@DependencyManagementBom。然而,要保证依赖管理顺序的一致性,你最多可以在应用程序中使用@DependencyManagementBom一次。

15.2.2. 使用多源文件的应用程序

你可以使用“shell globbing”和接收文件输入的所有命令。这样做让你使用单个目录的多个文件,如下示例所示:

$ spring run *.groovy

15.2.3. 打包你的应用程序

你可以使用jar命令打包你的应用程序到一个自包含的可执行jar文件,如下示例所示:

$ spring jar my-app.jar *.groovy

结果jar包含编译应用程序产生的类和所有应用程序依赖以便它可以使用java-jar运行。jar文件也包含来自所有应用程序类路径的条目。你可以使用--include--exclude显性地添加或者移除指向jar的路径。两者都是逗号分隔并且接收前缀,以“+”和“-”的形式表示他们应该从默认值中移除。默认包含如下:

public/**, resources/**, static/**, templates/**, META-INF/**, *

默认的排除如下:

.*, repository/**, build/**, target/**, **/*.jar, **/*.groovy

在命令行键入spring help jar了解更多信息。

15.2.4. 初始化一个新项目

init命令让你通过使用start.spring.io创建一个新的项目,而不用离开shell。如下示例所示:

$ spring init --dependencies=web,data-jpa my-project
Using service at https://start.spring.io
Project extracted to '/Users/developer/example/my-project'

上面的示例创建了my-project目录和使用spring-boot-starter-webspring-boot-starter-data-jpa基于Maven项目。你可以使用--list标识列出这个服务的功能,如下示例所示:

$ spring init --list
=======================================
Capabilities of https://start.spring.io
=======================================

Available dependencies:
-----------------------
actuator - Actuator: Production ready features to help you monitor and manage your application
...
web - Web: Support for full-stack web development, including Tomcat and spring-webmvc
websocket - Websocket: Support for WebSocket development
ws - WS: Support for Spring Web Services

Available project types:
------------------------
gradle-build -  Gradle Config [format:build, build:gradle]
gradle-project -  Gradle Project [format:project, build:gradle]
maven-build -  Maven POM [format:build, build:maven]
maven-project -  Maven Project [format:project, build:maven] (default)

...

init命令支持许多选项。请查看help输出了解更多详情。例如,下面的命令创建一个使用Java 8 和war打包的Gradle项目:

$ spring init --build=gradle --java-version=1.8 --dependencies=websocket --packaging=war sample-app.zip
Using service at https://start.spring.io
Content saved to 'sample-app.zip'

15.2.5. 使用内嵌的Shell

Spring Boot包括用于BASE和zsh shell的命令行补全脚本。如果你不使用这些脚本(假如你是一个Windows用户),你可以使用shell命令来运行一个集成的shell,如下示例所示:

$ spring shell
Spring Boot (v3.0.0-SNAPSHOT)
Hit TAB to complete. Type \'help' and hit RETURN for help, and \'exit' to quit.

从内嵌的shell内部,你可以直接运行其他的命令:

$ version
Spring CLI v3.0.0-SNAPSHOT

内嵌的shell支持ANSI颜色输出以及tab补全。如果你需要运行一个本地的命令,你可以使用!开头 。要退出内嵌的shell,按ctrl-c

15.2.6. 添加扩展到CLI

你可以通过使用install命令添加扩展到CLI。这个命令使用一个或者多个格式为group:artifact:version artifact坐标的集合,如下示例所示:

$ spring install com.example:spring-boot-cli-extension:1.0.0.RELEASE

除了安装你提供的坐标识别的artifact,所有的artifact的依赖项也被安装。

要卸载依赖项,使用uninstall命令。正如install命令,它使用一个或者多个格式为group:artifact:version artifact坐标的集合,如下示例所示:

$ spring uninstall com.example:spring-boot-cli-extension:1.0.0.RELEASE

它卸载了通过你提供的坐标和他们依赖识别的artifact。

要卸载所有额外的依赖项,你可以使用--all选项,如下示例所示:

$ spring uninstall --all

15.3. 使用Groovy Bean DSL开发应用程序

Spring Framework 4.0 对beans{} “DSL”(从Grails借来的)有原生的支持,你可以通过使用相同的格式在Groovy应用程序脚本中嵌入bean定义。有时候这是一个好的方式来包含外部特性,比如中间件声明,如下示例所示:

@Configuration(proxyBeanMethods = false)
class Application implements CommandLineRunner {

    @Autowired
    SharedService service

    @Override
    void run(String... args) {
        println service.message
    }

}

import my.company.SharedService

beans {
    service(SharedService) {
        message = "Hello World"
    }
}

你可以将类的声明与beans{}混合在同一个文件中,只要他们保持在顶级。或者,如果你愿意,你可以将bean DSL放在一个单独的文件中。

15.4. 使用setting.xml配置CLI

Spring Boot CLI使用Maven Resolver,Maven的依赖解析引擎,来解析依赖项。CLI利用在~/.me/setting.xml中发现的Maven配置配置Maven解析器。CLI支持以下配置设置:

  • Offline
  • Mirrors
  • Servers
  • Proxies
  • Profiles
    • Activation
    • Repositories
  • Active profiles

请查看Maven的设置文档了解进一步信息。

15.5. 下一步读什么

在Github仓库有一些groovy 脚本的示例,你可以用来尝试Spring Boot CLI。源码中还有大量的Javadoc。

如果你发现你达到了CLI工具的限制,你可能想看下转换你的应用程序为完整的Gradle或者Maven构建的“Groovy项目”。下一章节涵盖Spring Boot的“构建工具插件”,可以在Gradle或者Maven中使用它。

16. 构建工具插件

Spring Boot为Maven和Gradel提供构建工具插件。插件提供大量的特性,包括可执行jar文件打包。这章节提供这两个插件更多细节,以及一些帮助,如果你需要扩展一个不支持的构建系统。如果你只是想入门,你可能想要阅读来自“使用Spring Boot开发”的“构建系统”

16.1. Spring Boot Maven插件

Spring Boot Maven插件在Maven中提供Spring Boot支持,让你打包可执行jar或者war归档并就地运行应用程序。要使用它,你必须使用Maven 3.2(或者更晚版本)。

请查看插件文档了解更多:

  • 参考(HTML和PDF)
  • API

16.2. Spring Boot Gradle插件

Spring Boot Gradle插件在Gradle中提供Spring Boot支持,让你打包可执行jar文件或war归档,运行Spring Boot应用程序,并使用通过spring-boot-dependencies提供的依赖项。它要求Gradle 7.x(7.4或者更晚)。

请查看插件文档了解更多:

  • 参考(HTML和PDF)
  • API

16.3. Spring Boot AntLib模块

Spring Boot AntLib模块对Apache Ant提供基本的Spring Boot支持。你可以使用这个模块创建可执行jar。要使用这个模块,你需要在你的build.xml声明一个额外的spring-boot命名空间,如下示例所示:

<project xmlns:ivy="antlib:org.apache.ivy.ant"
    xmlns:spring-boot="antlib:org.springframework.boot.ant"
    name="myapp" default="build">
    ...
project>

你需要记住使用-lib选项启动Ant,如下示例所示:

$ ant -lib <directory containing spring-boot-antlib-3.0.0-SNAPSHOT.jar>

"使用Spring Boot"章节包括一个更完整的使用Apache Ant和spring-boot-antlib示例.

16.3.1. Spring Boot Ant Tasks

一旦spring-boot-antlib命名空间已经声明,以下额外的任务是可用的:

  • 使用“exejar”任务
  • 使用“findmainclass”任务
使用“exejar”任务

你可以使用exejar任务创建Spring Boot可执行jar.通过任务支持以下属性

属性 描述 要求
destfile 创建目的jar文件 是的
classes Java类文件根目录 是的
start-class 要运行的主要应用程序 否(默认是找到的第一个声明main方法的类)

以下内嵌的元素可以与Task一起使用:

元素 描述
resources 一个或者多个Resource Collections, 描述的一组被添加到创建的jar文件内容的Resource
lib 一个或者多个Resource Collections 应该被加到一组jar类库,组成运行时应用程序的依赖类路径
示例

这部分展示了Ant Task的两个示例:
指定启动类

<spring-boot:exejar destfile="target/my-application.jar"
        classes="target/classes" start-class="com.example.MyApplication">
    <resources>
        <fileset dir="src/main/resources" />
    resources>
    <lib>
        <fileset dir="lib" />
    lib>
spring-boot:exejar>

检测启动类

<exejar destfile="target/my-application.jar" classes="target/classes">
    <lib>
        <fileset dir="lib" />
    lib>
exejar>

16.3.2. 使用“exejar”任务

findmainclass任务被exejar内部使用来定位声明main的类。如果必须,你也可以直接在你的构建中使用这个任务。支持以下属性:

属性 描述 要求
classesroot Java类文件的根目录 是的(除非指定mainclass
mainclass 可以用来缩短main类搜索
property Ant属性,应该使用结果设置 否(如果没有指定,结果将被记录)
示例

这部分包含使用findmainclass的三个示例:
查找和记录

<findmainclass classesroot="target/classes" />

查找和设置

<findmainclass classesroot="target/classes" property="main-class" />

覆盖和设置

<findmainclass mainclass="com.example.MainClass" property="main-class" />

16.4. 支持其他构建系统

如果你想使用一个构建系统除了Maven,Gradle,或者Ant,你可能需要开发你自己的插件。可执行jar需要遵循特定的格式和某个条目需要以未压缩形式书写(请查看在附录中可执行jar格式章节了解更多详情)。

Spring Boot Maven和Gradle插件两者利用spring-boot-loader-tools来实际生成jar。如果你需要,你可以直接使用这个类库。

16.4.1. 重新打包归档

要重新打包现有的归档以便它变为一个自包含的可执行归档,使用org.springframework.boot.loader.tools.RepackagerRepackage类使用一个单构造器参数,他引用一个现有jar或者war归档。使用两个可用的repackage()方法的其中一个要么替换原始文件要么写入一个新的目标。在他执行之前在repackager上可以配置多种设置。

16.4.2. 内嵌类库

当重新打包一个归档,你可以通过使用org.springframework.boot.loader.tools.Libraries接口包含对依赖文件的引用。这里,我们不提供任何具体的Libraries的实现因为他们通常是特定于构建系统。

16.4.3. 查找一个主类

如果你没有使用Repackager.setMainClass()来指定一个主类,repacker使用ASM来读取类文件并尝试查找一个合适的带有public static void main(String[] args)方法的类。如果超过一个候选被发现则抛出一个异常。

16.4.4. 重新打包实现示例

以下示例展示一个典型的重新打包实现:

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.springframework.boot.loader.tools.Library;
import org.springframework.boot.loader.tools.LibraryCallback;
import org.springframework.boot.loader.tools.LibraryScope;
import org.springframework.boot.loader.tools.Repackager;

public class MyBuildTool {

    public void build() throws IOException {
        File sourceJarFile = ...
        Repackager repackager = new Repackager(sourceJarFile);
        repackager.setBackupSource(false);
        repackager.repackage(this::getLibraries);
    }

    private void getLibraries(LibraryCallback callback) throws IOException {
        // Build system specific implementation, callback for each dependency
        for (File nestedJar : getCompileScopeJars()) {
            callback.library(new Library(nestedJar, LibraryScope.COMPILE));
        }
        // ...
    }

    private List<File> getCompileScopeJars() {
        return ...
    }

}

16.5. 下一步读什么

如果你对构建工具插件如何工作的感兴趣,你可以看下在Githubspring-boot-tools模块。更多的可执行jar的技术格式详情可以在附录中找到。

如果你有特别的构建相关的问题,请查看“如何做”指南。

你可能感兴趣的:(spring-boot,spring,spring,boot)