Spring Boot 实践折腾记(六):Spring Boot中的容器配置和SSL支持

328 阅读7分钟

每日金句

在人生或者职业的各种事务中,性格的作用比智力大得多,头脑的作用不如心情,天资不如由判断力所节制着的自制,耐心和规律。——源自 海明威

题记

虽然以前在Spring MVC中有时会涉及到配置容器,但是大多数同学会觉得这是运维或者测试的工作,只要能用就行,只要自己的代码能运行就行。其实,多了解一些原理的作用不只是为了完成任务,它可以帮助你更积极的去思考代码运行的原理,提升你的思维结构,因为你习惯知其所以然,以后你不管是做需求分析,架构设计,模块重构优化、性能调优等等,都会有很多帮助的。扯远了点,本章讲解的比较简单的,也是常用的容器的配置的修改,ssl支持这几年越来越受到重视了,开始实战吧。

实战

servlet容器配置

Spring Boot快速的原因除了自动配置外,另一个就是将web常用的容器也集成进来并做自动配置,让使用它的人能更快速的搭建web项目,快速的实现自己的业务目的。什么是容器?在这里就是支持java程序运行的程序。本节内容只详细展开Tomcat配置,不过,本节内容对后面提到的Jetty、Undertow都是通用。

1-配置文件配置Tomcat

之前我们在配置章节介绍了如何查看配置的定义,这里,我们同样能在org.springframework.boot.autoconfigure.web中找到ServerProperties,通用的servler通用的配置就是在这里定义的,以“server”作为前缀,而作为默认内嵌容器的Tomcat的配置是以server.tomcat作为前缀的。以下为举例:

// servlet 容器
server.port=9090   #监听端口,默认是8080
server.context-path=  #访问路径,默认为/
// 配置tomcat
server.tomcat.uri-encoding=  #tomcat编码,默认为UTF-8
server.tomcat.accesslog.directory=  #访问日志,默认为logs

以上为简单说明,详细的配置可在application.properties输入server或server.tomcat来查看,idea可以很方便的提示有哪些功能,如图:
这里写图片描述

2-代码配置Tomcat

Spring Boot的自动配置有一个特性就是能够通过代码来修改配置,这样可以很方便的修改配置,而我们只需要实现Spring Boot定义的接口即可。这里,我们需要注册一个实现了EmbeddedServletContainerCustomizer的Bean。而如果直接配置指定容器,那么使用对应工厂类实现即可,对应如下:

Tomcat   ---> TomcatEmbeddedServletContainerFactory
Jetty    ---> JettyEmbeddedServletContainerFactory
Undertow ---> UndertowEmbeddedServletContainerFactory

公用配置

新建一个可修改的公用server配置:

package com.hjf.boot.demo.boot_ssl.config;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;

public class CustomerServlet implements EmbeddedServletContainerCustomizer {

    public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
        configurableEmbeddedServletContainer.setPort(9090); //1
        configurableEmbeddedServletContainer.setContextPath("/test"); //2
    }
}  

说明:
1:修改监听端口
2:修改访问路径,和配置文件修改是类似的。

特殊配置

增加配置类,并注册Bean

@Configuration
public class ServletConfig {
}

Tomcat配置

@Bean
    public EmbeddedServletContainerFactory servletContainer(){
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.setPort(9999);
        factory.setContextPath("/test");
        return factory;
    }

Jetty配置

@Bean
    public EmbeddedServletContainerFactory servletContainer(){
        JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
        factory.setPort(9999);
        factory.setContextPath("/test");
        return factory;
    }

Undertow配置

@Bean
    public EmbeddedServletContainerFactory servletContainer(){
        UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
        factory.setPort(9999);
        factory.setContextPath("/test");
        return factory;
    }

注意:一个项目只用配置一个容器即可,不要重复注册多个。

替换内嵌容器

Spring Boot默认是用Tomcat作为Servlet的容器,我们上面可以配置另外另个容器,那么这里就需要排除掉Tomcat为对应容器:

使用Jetty

在pom.xml中修改如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starte-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

使用Undertow

在pom.xml中修改如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starte-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

使用SSL

什么是SSL?百度百科这样解释的,SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

使用SSL通常就两步,一是,生成有效的证书,让你的http链接有据可循,这个证书是可以自签名的,也可以是从SSL证书授权中心获得的,一般大的网站都是授权了,比如,百度、京东等,也有没授权的,例如:12306,但是都不影响使用;二是,在web容器里配置开启SSL,让配置的ssl生效。

生成证书

1、先找到你使用的java JDK,在bin文件夹中找到工具keytool,如何你设置了java的环境变量的话,直接在命令行执行命令如下(Windows和Linux都是一样的):

keytool -genkey -alias mickjoust -keyalg RSA  //1

说明:
1:如果不指定算法格式的话,会使用老的加密格式,高版本的容器,都会报安全格式不支持的错误。
这里写图片描述

这时生成了一个.keystore,就是证书文件了。

配置SSL

在Spring Boot中配置SSL非常简单,同样在application.properties下配置:

server.port=8443  //1
#server.session.timeout=
#server.context-path=

server.tomcat.uri-encoding=UTF-8
#server.tomcat.compression= #新版已经没有了

server.ssl.key-store=.keystore  //2
server.ssl.key-store-password=123456 //3
server.ssl.key-store-type=JKS   //4
server.ssl.key-alias=mickjoust  //5

说明:
1:指定监听端口
2:ssl存储的文件名
3:证书密码
4:证书类型
5:证书别名

使用代码配置http自动跳转https

上面配置了SSL,只是支持SSL,也就是说,当你输入同样的网址带上https时,是可以访问的,但我们有时习惯了只输入网址,而浏览器默认是使用的http,这时我们希望能够自动跳转,要实现这个功能,我们需要配置容器的自动重定向功能。使用tomcat作为示例,jetty和Undertow类似,需要查看对应文档。

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Http2HttpsConfig {

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory(){//1
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }

    @Bean
    public Connector httpConnector(){//2
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(9090);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
}

说明:
1:重写上下文设置,添加路径和安全集合。
2:创建一个httpconnector以被使用。

启动成功,看到https端口了
这里写图片描述

执行localhost:9090测试
这里写图片描述

自动跳转到https了
这里写图片描述

很多同学比较疑惑,这也太麻烦了,还不如直接使用tomcat,当然,使用某种方法,也就有某种方法的代价牺牲,这里其实是通过代码的方式去配置tomcat,而平时我们都是手动操作tomcat的xml配置,这也是上面最开始说到的,如果没有一定的耐心,那么只是在完成任务,一旦遇见有一点困难的配置或任务,那么就不知道该怎么办了。其实,只要理解了原理,无论用什么配置,都是达到目的的手段而已。

小结

本章内容主要介绍了Spring Boot中如何配置内嵌tomcat和替换tomcat的方法,同时对ssl的配置进行了实战,其中要主要的是,内嵌的配置是通过代码的方式来配置的,和通用的容器里的ssl配置还有点区别,网上有很多教程,这里就不再介绍类似tomcat如何配置ssl的方法了。本章比较简单,算是配置的完结了,Spring Boot的配置其实有很多,需要在使用时自己去使用体会。


示例地址:boot-ssl


page 174 of 366 in chapter 2016