zoukankan      html  css  js  c++  java
  • 20191127 Spring Boot官方文档学习(9.1-9.3)

    9.“使用方法”指南

    9.1。Spring Boot应用程序

    9.1.1。创建自己的FailureAnalyzer

    FailureAnalyzer被包装在FailureAnalysis中,可以在启动时拦截异常并将其转换为易于阅读的消息。Spring Boot为与应用程序上下文相关的异常,JSR-303验证等提供了此类分析器。您也可以创建自己的。

    AbstractFailureAnalyzer是一个方便的FailureAnalyzer扩展,它检查要处理的异常中是否存在指定的异常类型。您可以对此进行扩展,以便您的实现只有在指定的异常出现时才有机会处理该异常。如果由于某种原因无法处理该异常,请返回null以使另一个实现有机会处理该异常。

    FailureAnalyzer实现必须在META-INF/spring.factories中注册。以下示例注册ProjectConstraintViolationFailureAnalyzer

    org.springframework.boot.diagnostics.FailureAnalyzer=
    com.example.ProjectConstraintViolationFailureAnalyzer
    

    如果您需要访问BeanFactoryEnvironment,则FailureAnalyzer可以分别实现BeanFactoryAwareEnvironmentAware

    源码学习:

    org.springframework.boot.SpringApplication#run(java.lang.String...)
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
          new Class[] { ConfigurableApplicationContext.class }, context);
    

    spring.factories里读取org.springframework.boot.SpringBootExceptionReporter后,实例化FailureAnalyzers(通过构造函数将spring.factories中所有org.springframework.boot.diagnostics.FailureAnalyzer的值作为FailureAnalyzers构造器的参数)

    org.springframework.boot.SpringBootExceptionReporter=
    org.springframework.boot.diagnostics.FailureAnalyzers
    
    org.springframework.boot.diagnostics.FailureAnalyzer=
    xxx
    
    org.springframework.boot.diagnostics.FailureAnalyzers#FailureAnalyzers(org.springframework.context.ConfigurableApplicationContext)
    

    org.springframework.boot.SpringApplication中有两个getSpringFactoriesInstances方法,都是用来获取实例的,第一个方法使用的是无参构造函数,第二个使用有参构造函数(可以为多个)。例如,FailureAnalyzers就是使用的第二个方法,在构造器中调用方法获取FailureAnalyzer

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
       return getSpringFactoriesInstances(type, new Class<?>[] {});
    }
    
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
       ClassLoader classLoader = getClassLoader();
       // Use names and ensure unique to protect against duplicates
       Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
       List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
       AnnotationAwareOrderComparator.sort(instances);
       return instances;
    }
    

    9.1.2。自动配置故障排除

    Spring Boot自动配置会尽力“做正确的事”,但是有时事情会失败,并且很难说出原因。

    任何Spring Boot ApplicationContext都有一个非常有用的功能ConditionEvaluationReport。如果启用DEBUG日志记录输出,则可以看到它。如果使用spring-boot-actuator(请参阅“执行器”一章),那么还有一个conditions端点,该端点以JSON形式呈现报告。使用该端点来调试应用程序,并在运行时查看Spring Boot添加(未添加)了哪些功能。

    通过查看源代码和Javadoc,可以回答更多问题。阅读代码时,请记住以下经验法则

    • 查找名称为 *AutoConfiguration 的类并阅读其源代码。特别注意@Conditional*注释,以了解它们启用了哪些功能以及何时启用。添加--debug到命令行或系统属性-Ddebug以在控制台上获取在您的应用中做出的所有自动配置决策的日志。在启用了执行器的运行应用程序中,查看conditions端点(/actuator/conditions或等效的JMX)以获取相同信息。
    • 查找@ConfigurationProperties(例如ServerProperties)的类,然后从中读取可用的外部配置选项。@ConfigurationProperties注释具有一个name充当前缀外部性能属性。因此,ServerProperties拥有prefix="server"并且它的配置属性是server.portserver.address以及其他。在启用了执行器的运行应用程序中,查看configprops端点。
    • 寻找对bind方法的使用,以一种轻松的方式Binder将配置值明确地拉出Environment。它通常与前缀一起使用。
    • 查找@Value注释直接绑定到Environment
    • 寻找@ConditionalOnExpression注释以响应SpEL表达式来打开或关闭功能,这些注释通常使用从Environment中解析的占位符进行评估。

    源码学习:

    Binder的简单使用:

    Binder binder = Binder.get(ctx.getEnvironment()); //绑定简单配置
    MyProperties myProperties = binder.bind("my", Bindable.of(MyProperties.class)).get();
    System.out.println(myProperties);
    

    @ConfigurationProperties(prefix = "my")使用原理:
    通过后置处理器,在实例化Bean之前,调用org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
    底层也是使用Binder实现的。

    9.1.3。启动之前自定义Environment或ApplicationContext

    一个SpringApplication具有ApplicationListenersApplicationContextInitializers,可以被用于应用自定义的context或environment。Spring Boot从META-INF/spring.factories加载了许多此类自定义项,以供内部使用。注册其他自定义项的方法有多种:

    • 在运行之前,通过对每个应用程序进行编程,方法是调用SpringApplication的addListenersaddInitializers方法。
    • 通过设置context.initializer.classescontext.listener.classes属性,以声明方式针对每个应用程序。
    • 声明性地,对于所有应用程序,通过添加META-INF/spring.factories和打包一个jar文件,这些文件都被应用程序用作库。

    SpringApplication发送一些特殊ApplicationEvents给监听器(一些甚至在context创建之前),然后注册了监听ApplicationContext发布事件的监听器。参考文档

    还可以使用EnvironmentPostProcessor在刷新应用程序上下文之前来自定义Environment。每个实现都应在META-INF/spring.factories中注册,如以下示例所示:

    org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
    

    该实现可以加载任意文件并将其添加到中Environment。例如,以下示例从类路径加载YAML配置文件:

    public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {
    
        private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
            Resource path = new ClassPathResource("com/example/myapp/config.yml");
            PropertySource<?> propertySource = loadYaml(path);
            environment.getPropertySources().addLast(propertySource);
        }
    
        private PropertySource<?> loadYaml(Resource path) {
            if (!path.exists()) {
                throw new IllegalArgumentException("Resource " + path + " does not exist");
            }
            try {
                return this.loader.load("custom-resource", path).get(0);
            }
            catch (IOException ex) {
                throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
            }
        }
    
    }
    

    Environment已经准备与所有Spring Boot默认加载的常见的属性来源。因此可以从Environment中获取文件的位置。前面的示例将custom-resource属性源添加到列表的末尾,以便在其他任何常见位置定义的键具有优先权。定制实现可以定义另一个顺序。

    @SpringBootApplication使用@PropertySource似乎是从Environment中加载在一个自定义资源的便利和简单的方法,然而我们不建议这样做,因为Spring Boot准备Environment在ApplicationContext被刷新之前。用@PropertySource定义的任何键加载得太晚,对自动配置没有任何影响。

    源码学习:

    使用事件监听器将PropertySource添加到Environment

    org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent
    

    9.1.4。建立ApplicationContext层次结构(添加父上下文或根上下文)

    您可以使用ApplicationBuilder类创建父/子ApplicationContext层次结构。有关更多信息,请参见“Spring Boot功能”部分中的“ Fluent Builder API”

    9.1.5。创建一个非Web应用程序

    并非所有的Spring应用程序都必须是Web应用程序(或Web服务)。如果要在main方法中执行一些代码,又要引导Spring应用程序以设置要使用的基础结构,则可以使用Spring Boot 的SpringApplication功能。SpringApplication根据是否需要Web应用程序来更改其ApplicationContext类。您可以做的第一件事是让服务器相关的依赖项(例如Servlet API)脱离类路径。如果你不能做到这一点(例如,您使用相同的代码库的运行两个应用程序),那么你可以显式调用SpringApplication实例的setWebApplicationType(WebApplicationType.NONE)或设置applicationContextClass属性(通过Java API或与外部属性)。您可以将要作为业务逻辑运行的应用程序代码实现为CommandLineRunner并作为@Bean定义放到上下文中。

    9.2。属性(Properties)和配置(Configuration)

    9.2.1。在构建时自动扩展属性

    您可以使用现有的构建配置自动扩展它们,而不是对项目的构建配置中也指定的某些属性进行硬编码。在Maven和Gradle中都是可行的。

    使用Maven自动扩展属性

    您可以使用资源过滤从Maven项目自动扩展属性。如果使用spring-boot-starter-parent,则可以使用@..@占位符引用Maven的“项目属性” ,如以下示例所示:

    app.encoding=@project.build.sourceEncoding@
    app.java.version=@java.version@
    

    这样只会过滤生产配置(也就是说,不会对进行过滤src/test/resources)。

    如果启用addResources标志,则spring-boot:run goal 可以将src/main/resources直接添加到类路径中(用于热重载)。这样做避免了资源过滤和此功能。相反,您可以使用exec:java goal或自定义插件的配置。

    如果您不使用parent启动器,则需要在pom.xml<build/>元素中包括以下元素:

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    

    您还需要在其中包含以下元素<plugins/>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.7</version>
        <configuration>
            <delimiters>
                <delimiter>@</delimiter>
            </delimiters>
            <useDefaultDelimiters>false</useDefaultDelimiters>
        </configuration>
    </plugin>
    

    如果在配置中使用标准的Spring占位符(例如${placeholder}),则 useDefaultDelimiters属性很重要。如果该属性未设置为false,则可以通过构建扩展它们。

    使用Gradle自动扩展属性

    您可以通过配置Java插件的processResources任务来自动扩展Gradle项目中的属性,如以下示例所示:

    processResources {
        expand(project.properties)
    }
    

    然后,您可以使用占位符来引用Gradle项目的属性,如以下示例所示:

    app.name=${name}
    app.description=${description}
    

    Gradle的expand方法使用Groovy 的SimpleTemplateEngine方法来转换${..}令牌。${..}风格与Spring自己的属性占位符机制冲突。要将Spring属性占位符与自动扩展一起使用,请按以下步骤对Spring属性占位符进行转义:${..}

    !!!按照文档不能实现功能

    9.2.2。外部化配置SpringApplication

    SpringApplication具有bean属性(主要是setter),因此在创建应用程序时可以使用其Java API修改其行为。或者,您可以通过在spring.main.*中设置属性来外部化配置。例如,在application.properties中,您可能具有以下设置:

    spring.main.web-application-type=none
    spring.main.banner-mode=off
    

    然后,启动时不会打印Spring Boot标语,并且应用程序也没有启动嵌入式Web服务器。

    外部配置中定义的属性会覆盖用Java API指定的值,但用于创建ApplicationContext的sources例外。考虑以下应用程序:

    new SpringApplicationBuilder()
        .bannerMode(Banner.Mode.OFF)
        .sources(demo.MyApp.class)
        .run(args);
    

    现在考虑以下配置:

    spring.main.sources=com.acme.Config,com.acme.ExtraConfig
    spring.main.banner-mode=console
    

    实际应用中,现在显示Banner(配置覆盖),并且ApplicationContext使用了三个sources(按以下顺序): demo.MyApp,com.acme.Config和com.acme.ExtraConfig。

    9.2.3。更改应用程序外部属性的位置

    默认情况下,来自不同来源的属性会以Environment定义的顺序添加到Spring 中。

    扩充和修改此顺序的一种不错的方法是在应用程序源中添加@PropertySource注释。检查传递给SpringApplication静态方法的类以及使用setSources()添加的类,以查看它们是否具有@PropertySources。如果确实如此,那么这些属性会尽早添加到Environment,以便在ApplicationContext生命周期的所有阶段中使用。以这种方式添加的属性的优先级低于使用默认位置(例如application.properties),系统属性,环境变量或命令行添加的属性。

    您还可以提供以下系统属性(或环境变量)来更改行为:

    • spring.config.name(SPRING_CONFIG_NAME):默认application作为文件名。
    • spring.config.location(SPRING_CONFIG_LOCATION):要加载的文件(例如类路径资源或URL)。为此文档设置了单独的Environment属性源,可以通过系统属性,环境变量或命令行来覆盖它。

    无论您在Environment中进行什么设置,Spring Boot都将始终如上所述进行加载application.properties。默认情况下,如果使用YAML,则扩展名为.yml的文件也将添加到列表中。

    Spring Boot在DEBUG级别记录加载的配置文件以及在TRACE级别找不到的候选文件。

    请参阅参考资料ConfigFileApplicationListener

    9.2.4。使用“简短”命令行参数

    有些人喜欢使用(例如)--port=9000而不是--server.port=9000在命令行上设置配置属性。您可以通过在application.properties中使用占位符来启用此行为,如以下示例所示:

    server.port=${port:8080}
    

    如果您从spring-boot-starter-parent POM 继承,则将maven-resources-plugins的默认过滤器令牌从${*}更改为@(即,@maven.token@而不是${maven.token}),以防止与Spring样式的占位符冲突。如果直接为application.properties启用了Maven过滤,则可能还需要更改默认过滤器令牌以使用其他定界符。

    在这种特定情况下,端口绑定可在PaaS环境(例如Heroku或Cloud Foundry)中工作。在这两个平台中,PORT环境变量是自动设置的,Spring可以绑定到大写的Environment属性同义词。

    9.2.5。对外部属性使用YAML

    YAML是JSON的超集,因此是一种方便的语法,用于以分层格式存储外部属性,如以下示例所示:

    spring:
        application:
            name: cruncher
        datasource:
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://localhost/test
    server:
        port: 9000
    

    创建一个名为application.yml的文件,并将其放在类路径的根目录中。然后添加snakeyaml到您的依赖项(Maven坐标org.yaml:snakeyaml,如果使用spring-boot-starter,则已经包含在内)。将YAML文件解析为Java Map<String,Object>(就像JSON对象),然后Spring Boot展宽Map,使其深一层,并具有句点分隔的键,这是许多人习惯使用Java中的Properties文件的原因。

    前面的示例YAML对应于以下application.properties文件:

    spring.application.name=cruncher
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost/test
    server.port=9000
    

    9.2.6。设置激活的Spring Profiles

    Spring Environment为此提供了一个API,但是您通常会设置一个System属性(spring.profiles.active)或OS环境变量(SPRING_PROFILES_ACTIVE)。另外,您可以使用-D参数启动应用程序(请记住将其放在主类或jar存档之前),如下所示:

    $ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
    

    在Spring Boot中,您还可以在application.properties中设置激活的profiles,如以下示例所示:

    spring.profiles.active=production
    

    以这种方式设置的值将由系统属性或环境变量设置代替,而不由SpringApplicationBuilder.profiles()方法替代。因此,后一种Java API可用于扩充配置文件,而不是更改默认值。

    9.2.7。根据Environment更改配置

    YAML文件实际上是由---行分隔的文档序列,每个文档都分别解析为Map。

    如果YAML文档包含spring.profiles键,则将profiles文件值(以逗号分隔的profiles列表)输入到Spring Environment.acceptsProfiles()方法中。如果这些配置文件中的任何一个处于活动状态,那么该文档将包含在最终合并中(否则,它不会包含在此文档中),如以下示例所示:

    server:
        port: 9000
    ---
    
    spring:
        profiles: development
    server:
        port: 9001
    
    ---
    
    spring:
        profiles: production
    server:
        port: 0
    

    在前面的示例中,默认端口为9000。但是,如果名为“development”的Spring profile处于活动状态,则端口为9001。如果“production”为活动状态,则该端口为0。

    YAML文档按照它们遇到的顺序进行合并。以后的值将覆盖以前的值。

    要对属性文件执行相同的操作,可以使用application-${profile}.properties指定特定于profile的值。

    9.2.8。发现外部属性的内置选项

    Spring Boot 在运行时将application.properties中的外部属性(或.yml文件和其他位置)绑定到应用程序中。在一个位置上没有(而且从技术上来说不是)所有受支持属性的详尽列表,因为可能有来自类路径上的其他jar文件的属性。

    具有Actuator功能的正在运行的应用程序具有一个configprops终结点,该终结点显示了可通过@ConfigurationProperties访问的所有绑定和可绑定属性。

    附录中包含一个application.properties示例,其中列出了Spring Boot支持的最常见属性。最终列表来自搜索源代码中的@ConfigurationProperties@Value注释,以及偶尔使用的Binder

    9.3。嵌入式Web服务器

    9.3.1。使用其他Web服务器

    许多Spring Boot启动器都包含默认的嵌入式容器。
    对于servlet堆栈应用程序,通过spring-boot-starter-web包括spring-boot-starter-tomcat来包括Tomcat ,但是您可以使用spring-boot-starter-jettyspring-boot-starter-undertow代替。
    对于反应栈的应用,spring-boot-starter-webflux通过包括spring-boot-starter-reactor-netty包括反应堆的Netty,但你可以使用spring-boot-starter-tomcatspring-boot-starter-jettyspring-boot-starter-undertow代替。

    切换到其他HTTP服务器时,除了包括所需的依赖关系之外,还需要排除默认的依赖关系。Spring Boot为HTTP服务器提供了单独的启动器,以帮助简化此过程。

    以下Maven示例显示了如何排除Tomcat并包括Spring MVC的Jetty:

    <properties>
        <servlet-api.version>3.1.0</servlet-api.version>
    </properties>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <!-- Exclude the Tomcat dependency -->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- Use Jetty instead -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    

    Servlet API的版本已被覆盖,因为与Tomcat 9和Undertow 2.0不同,Jetty 9.4不支持Servlet 4.0。

    以下Gradle示例显示了如何排除Netty并包括Spring WebFlux的Undertow:

    configurations {
        // exclude Reactor Netty
        compile.exclude module: 'spring-boot-starter-reactor-netty'
    }
    
    dependencies {
        compile 'org.springframework.boot:spring-boot-starter-webflux'
        // Use Undertow instead
        compile 'org.springframework.boot:spring-boot-starter-undertow'
        // ...
    }
    

    spring-boot-starter-reactor-netty使用WebClient类是必需的,因此即使您需要包括其他HTTP服务器,也可能需要保持对Netty的依赖。

    9.3.2。禁用Web服务器

    如果您的类路径包含启动Web服务器所需的库,则Spring Boot将自动启动它。要禁用此行为,请在application.properties中配置WebApplicationType,如以下示例所示:

    spring.main.web-application-type=none
    

    9.3.3。更改HTTP端口

    在独立应用程序中,主HTTP端口默认为8080,但可以使用server.port(例如,在application.properties中或作为System属性)进行设置。由于宽松绑定了Environment值,因此还可以使用SERVER_PORT(例如,作为OS环境变量)。

    要完全关闭HTTP端点,但仍创建一个WebApplicationContext,请使用server.port=-1(这样做有时对测试很有用)。

    有关更多详细信息,请参阅ServerProperties源代码。

    9.3.4。使用随机未分配的HTTP端口

    要扫描可用端口(使用OS本机来防止冲突),请使用server.port=0

    9.3.5。在运行时发现HTTP端口

    您可以从日志输出或通过ServletWebServerApplicationContextWebServer访问服务器正在运行的端口。最好的方法是确保它已初始化,并添加一个@Bean类型为ApplicationListener<ServletWebServerInitializedEvent>,然后在发布事件时将其从事件中拉出。

    @Component
    public class MyListener implements ApplicationListener<ServletWebServerInitializedEvent> {
        @Override
        public void onApplicationEvent(ServletWebServerInitializedEvent event) {
            System.out.println("MyListener...onApplicationEvent...");
            System.out.println(event.getSource().getPort());
        }
    }
    

    使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)的测试还可以通过使用@LocalServerPort注解将实际端口注入字段,如以下示例所示:

    @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
    public class MyWebIntegrationTests {
    
        @Autowired
        ServletWebServerApplicationContext server;
    
        @LocalServerPort
        int port;
    
        // ...
    
    }
    

    @LocalServerPort@Value("${local.server.port}")的元注释。不要尝试在常规应用程序中注入端口。如我们所见,仅在初始化容器之后才设置该值。与测试相反,应早处理应用程序代码回调(在值实际可用之前)。

    9.3.6。启用HTTP响应压缩

    Jetty,Tomcat和Undertow支持HTTP响应压缩。可以在application.properties中启用它,如下所示:

    server.compression.enabled=true
    

    默认情况下,响应的长度必须至少为2048个字节才能执行压缩。您可以通过设置server.compression.min-response-size属性来配置此行为。

    默认情况下,仅当响应的内容类型为以下之一时,它们才被压缩:

    • text/html
    • text/xml
    • text/plain
    • text/css
    • text/javascript
    • application/javascript
    • application/json
    • application/xml

    您可以通过设置server.compression.mime-types属性来配置此行为。

    9.3.7。配置SSL

    可以通过设置各种server.ssl.*属性来声明性地配置SSL ,通常在application.properties或中application.yml。以下示例显示了在application.properties中设置SSL属性:

    server.port=8443
    server.ssl.key-store=classpath:keystore.jks
    server.ssl.key-store-password=secret
    server.ssl.key-password=another-secret
    

    有关Ssl所有受支持属性的详细信息,请参见org.springframework.boot.web.server.Ssl

    使用上述示例的配置意味着应用程序不再在端口8080上支持纯HTTP连接器。SpringBoot不支持通过application.properties同时进行HTTP连接器和HTTPS连接器的配置。如果要同时拥有两者,则需要以编程方式配置其中之一。我们建议您使用application.properties进行HTTPS配置,因为HTTP连接器是两者中以编程方式进行配置的较容易方式。

    9.3.8。配置HTTP/2

    您可以使用server.http2.enabled配置属性在Spring Boot应用程序中启用HTTP/2支持。该支持取决于所选的Web服务器和应用程序环境,因为JDK8对协议的支持不是开箱即用的。

    Spring Boot不支持h2c(HTTP/2协议的明文版本)。因此,您必须先配置SSL。

    Undertow与HTTP/2

    从Undertow 1.4.0+开始,在JDK8上没有任何其他要求就支持HTTP/2。

    HTTP/2与Jetty

    从Jetty 9.4.8开始,Conscrypt库还支持HTTP/2 。要启用该支持,您的应用程序需要具有两个附加依赖项:org.eclipse.jetty:jetty-alpn-conscrypt-serverorg.eclipse.jetty.http2:http2-server

    Tomcat与HTTP/2

    默认情况下,Spring Boot随Tomcat 9.0.x一起提供,当使用JDK 9或更高版本时,Tomcat 9.0.x支持HTTP/2。另外,如果libtcnative库及其依赖项已安装在主机操作系统上,则可以在JDK 8上使用HTTP/2 。

    如果没有,则必须使库文件夹可用于JVM库路径。您可以使用JVM参数(例如-Djava.library.path=/usr/local/opt/tomcat-native/lib)来执行此操作。有关更多信息,请参见Tomcat官方文档

    在没有本机支持的情况下,在JDK 8上启动Tomcat 9.0.x会记录以下错误:

    ERROR 8787 --- [ main] o.a.coyote.http11.Http11NioProtocol : The
    upgrade handler [org.apache.coyote.http2.Http2Protocol] for [h2] only supports upgrade
    via ALPN but has been configured for the ["https-jsse-nio-8443"] connector that does
    not support ALPN.
    

    此错误不是致命错误,并且该应用程序仍以HTTP/1.1 SSL支持启动。

    HTTP/2和Reactor Netty

    默认情况下,spring-boot-webflux-starter使用Reactor Netty作为服务器使用。使用JDK 9或更高版本的JDK支持,可以将Reactor Netty配置为HTTP/2。对于JDK 8环境或最佳运行时性能,此服务器还支持带有本机库的HTTP/2。为此,您的应用程序需要具有其他依赖关系。

    Spring Boot管理io.netty:netty-tcnative-boringssl-static“超级jar” 的版本,其中包含所有平台的本机库。开发人员可以选择使用分类器仅导入所需的依赖项(请参阅Netty官方文档)。

    9.3.9。配置Web服务器

    通常,您首先应该考虑使用许多可用的配置键之一,并通过在您的application.properties(或application.yml,或环境等)中添加新条目来自定义Web服务器。请参阅“发现外部属性的内置选项 ”。server.*命名空间是非常有用的在这里,它包括命名空间像server.tomcat.*server.jetty.*和其他,针对服务器的特定功能。

    前面的部分已经介绍了许多常见的用例,例如压缩,SSL或HTTP/2。但是,如果您的用例不存在配置key,则应查看WebServerFactoryCustomizer。您可以声明一个这样的组件,并访问与您选择的服务器相关的工厂:您应该为所选服务器(Tomcat,Jetty,Reactor Netty,Undertow)和所选Web堆栈(Servlet或Reactive)选择变体。

    以下示例适用于带有spring-boot-starter-web(Servlet堆栈)的Tomcat :

    @Component
    public class MyTomcatWebServerCustomizer
            implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
        @Override
        public void customize(TomcatServletWebServerFactory factory) {
            // customize the factory here
        }
    }
    

    此外,Spring Boot还提供:

    Server Servlet stack Reactive stack
    Tomcat TomcatServletWebServerFactory TomcatReactiveWebServerFactory
    Jetty JettyServletWebServerFactory JettyReactiveWebServerFactory
    Undertow UndertowServletWebServerFactory UndertowReactiveWebServerFactory
    Reactor N/A NettyReactiveWebServerFactory

    一旦访问了WebServerFactory,就可以经常向其添加定制,以配置特定的部分,例如连接器,服务器资源或服务器本身,全部使用服务器特定的API。

    作为最后的选择,您也可以声明自己的 WebServerFactory组件,该组件将覆盖Spring Boot提供组件。在这种情况下,您不能再依赖server命名空间中的配置属性。

    9.3.10。将Servlet,Filter或Listener添加到应用程序

    在一个使用spring-boot-starter-web的servlet栈的应用,有两种方法可以添加ServletFilterServletContextListener,和由Servlet API支持的其他监听器:

    • 使用Spring Bean添加Servlet,Filter或Listener
    • 使用类路径扫描添加Servlet,Filter和Listener

    使用Spring Bean添加Servlet,Filter或Listener

    要使用Spring bean添加ServletFilterServlet *Listener,你必须提供一个它的@Bean定义。当您要注入配置或依赖项时,这样做非常有用。但是,您必须非常小心,以免引起过多其他bean的急切(Eager)初始化,因为必须在应用程序生命周期的早期就将它们安装在容器中。(例如,让它们依赖于您DataSource或JPA配置不是一个好主意。)您可以通过在首次使用bean时而不是在初始化时对bean进行初始化(即懒加载)来解决这些限制。

    在Filters和Servlets的情况下,还可以通过添加FilterRegistrationBeanServletRegistrationBean来添加映射和初始化参数。

    如果在过滤器注册上未指定dispatcherType ,则使用REQUEST。这符合Servlet规范的默认调度程序类型。

    像其他任何Spring bean一样,您可以定义Servlet过滤器bean的顺序。参考文档

    禁用Servlet或Filter的注册

    正如前面所述,任何Servlet或Filter bean自动注册进servlet容器。要禁用特定Filter或Servlet bean的注册,请为其创建注册bean并将其标记为已禁用,如以下示例所示:

    @Bean
    public FilterRegistrationBean registration(MyFilter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(filter);
        registration.setEnabled(false);
        return registration;
    }
    
    使用类路径扫描添加Servlet,Filter和Listener

    @WebServlet@WebFilter@WebListener可以通过向注释@ServletComponentScan@Configuration类并指定包含要注册的组件的包来自动向嵌入式servlet容器注册。默认情况下,从带@ServletComponentScan注释的类的包进行扫描。

    9.3.11。配置访问日志

    可以通过它们各自的名称空间为Tomcat,Undertow和Jetty配置访问日志。

    例如,以下设置使用自定义模式记录对Tomcat的访问。

    server.tomcat.basedir=my-tomcat
    server.tomcat.accesslog.enabled=true
    server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
    

    日志的默认位置是相对于Tomcat基本目录的logs目录。默认情况下,logs目录是一个临时目录,因此您可能需要修复Tomcat的基本目录或对日志使用绝对路径。在前面的示例中,日志相对于应用程序的工作目录my-tomcat/logs可用。

    可以用类似的方式配置Undertow的访问日志,如以下示例所示:

    server.undertow.accesslog.enabled=true
    server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)
    

    日志存储在相对于应用程序工作目录的logs目录中。您可以通过设置server.undertow.accesslog.dir属性来自定义此位置。

    最后,Jetty的访问日志也可以配置如下:

    server.jetty.accesslog.enabled=true
    server.jetty.accesslog.filename=/var/log/jetty-access.log
    

    默认情况下,日志重定向到System.err

    9.3.12。在前端代理服务器后面运行

    您的应用程序可能需要发送302重定向或使用绝对链接将内容呈现回自身。当在代理后面运行时,调用者需要链接到代理,而不要链接到托管您的应用程序的计算机的物理地址。通常,此类情况是通过与代理之间的协议来处理的,该代理添加了标头,以告诉后端如何构造与自身的链接。

    如果代理添加常规X-Forwarded-ForX-Forwarded-Proto标头(大多数代理服务器都这样做),则绝对链接应正确呈现,只要在application.properties中将server.forward-headers-strategy设置为NATIVEFRAMEWORK

    如果您的应用程序在Cloud Foundry或Heroku中运行,则server.forward-headers-strategy属性默认为NATIVE。在所有其他情况下,默认为NONE

    自定义Tomcat的代理配置

    如果使用Tomcat,则可以另外配置用于携带“转发”信息的标头名称,如以下示例所示:

    server.tomcat.remote-ip-header=x-your-remote-ip-header
    server.tomcat.protocol-header=x-your-protocol-header
    

    Tomcat还配置有一个默认正则表达式,该正则表达式与要信任的内部代理匹配。默认情况下,IP地址10/8,192.168/16,169.254/16和127/8是值得信赖的。您可以通过在application.properties上添加一个条目来自定义阀门的配置,如以下示例所示:

    server.tomcat.internal-proxies=192\.168\.\d{1,3}\.\d{1,3}
    

    仅当使用properties文件进行配置时,才需要双反斜杠。如果使用YAML,则单个反斜杠就足够了,并且与上一个示例中所示的192.168.d{1,3}.d{1,3}值相等。

    您可以通过将internal-proxies设置为空来信任所有代理(但在生产环境中不要这样做)。

    您可以通过关闭自动开关(设置 server.forward-headers-strategy=NONE)并在TomcatServletWebServerFactory bean中添加新的Valve实例来完全控制Tomcat的RemoteIpValve配置。

    9.3.13。使用Tomcat启用多个连接器

    您可以在TomcatServletWebServerFactory中添加org.apache.catalina.connector.Connector以允许多个连接器,包括HTTP和HTTPS连接器,如以下示例所示:

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createSslConnector());
        return tomcat;
    }
    
    private Connector createSslConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
        try {
            File keystore = new ClassPathResource("keystore").getFile();
            File truststore = new ClassPathResource("keystore").getFile();
            connector.setScheme("https");
            connector.setSecure(true);
            connector.setPort(8443);
            protocol.setSSLEnabled(true);
            protocol.setKeystoreFile(keystore.getAbsolutePath());
            protocol.setKeystorePass("changeit");
            protocol.setTruststoreFile(truststore.getAbsolutePath());
            protocol.setTruststorePass("changeit");
            protocol.setKeyAlias("apitester");
            return connector;
        }
        catch (IOException ex) {
            throw new IllegalStateException("can't access keystore: [" + "keystore"
                    + "] or truststore: [" + "keystore" + "]", ex);
        }
    }
    

    9.3.14。使用Tomcat的LegacyCookieProcessor

    默认情况下,Spring Boot使用的嵌入式Tomcat不支持Cookie格式的“版本0”,因此您可能会看到以下错误:

    java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
    

    如果有可能,您应该考虑将代码更新为仅存储符合以后Cookie规范的值。但是,如果无法更改cookie的编写方式,则可以将Tomcat配置为使用LegacyCookieProcessor。要切换到LegacyCookieProcessor,请使用添加了TomcatContextCustomizerWebServerFactoryCustomizer Bean,如以下示例所示:

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
        return (factory) -> factory
                .addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
    }
    

    9.3.15。启用Tomcat的MBean Registry

    默认情况下,嵌入式Tomcat的MBean注册表是禁用的。这样可以最大程度地减少Tomcat的内存占用。例如,如果要使用Tomcat的MBean,以便可以通过Micrometer公开它们,则必须使用server.tomcat.mbeanregistry.enabled属性,如以下示例所示:

    server.tomcat.mbeanregistry.enabled=true
    

    9.3.16。使用Undertow启用多个侦听器

    UndertowServletWebServerFactory中添加一个UndertowBuilderCustomizer,并在Builder中添加一个侦听器,如以下示例所示:

    @Bean
    public UndertowServletWebServerFactory servletWebServerFactory() {
        UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
        factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
    
            @Override
            public void customize(Builder builder) {
                builder.addHttpListener(8080, "0.0.0.0");
            }
    
        });
        return factory;
    }
    

    9.3.17。使用@ServerEndpoint创建WebSocket端点

    如果要在使用嵌入式容器的Spring Boot应用程序中使用@ServerEndpoint,必须声明一个单个的ServerEndpointExporter @Bean,如以下示例所示:

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
    

    前面示例中显示的bean将所有带@ServerEndpoint注释的bean 注册到基础WebSocket容器中。当部署到独立servlet容器时,此角色由servlet容器初始化程序执行,并且不需要ServerEndpointExporter bean。

  • 相关阅读:
    2-5-归并链式存储的单链表-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
    2-4-单链表链式存储结构-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
    2-3-归并单链表(顺序表)-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
    2-2-求并集A=A∪B-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
    2-1-单链表顺序存储结构-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
    线性表-第2章-《数据结构题集》习题解析-严蔚敏吴伟民版
    绪论-第1章-《数据结构题集》习题解析-严蔚敏吴伟民版
    1-1-绪论-第1章-《数据结构》课本源码-严蔚敏吴伟民版
    【十大经典数据挖掘算法】PageRank
    灵活可扩展的工作流管理平台Airflow
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/11944866.html
Copyright © 2011-2022 走看看