共计 3882 个字符,预计需要花费 10 分钟才能阅读完成。
本文首发于个人网站:Spring Boot 项目如何同时支持 HTTP 和 HTTPS 协议
如今,企业级应用程序的常见场景是同时支持 HTTP 和 HTTPS 两种协议,这篇文章考虑如何让 Spring Boot 应用程序同时支持 HTTP 和 HTTPS 两种协议。
准备
为了使用 HTTPS 连接器,需要生成一份 Certificate keystore,用于加密和机密浏览器的 SSL 沟通。
如果你使用 Unix 或者 Mac OS,可以通过下列命令:keytool -genkey -alias tomcat -keyalg RSA
,在生成过程中可能需要你填入一些自己的信息,例如我的机器上反馈如下:
可以看出,执行完上述命令后在 home 目录下多了一个新的.keystore 文件。
实战
- 首先在 resources 目录下新建一个配置文件tomcat.https.properties,用于存放 HTTPS 的配置信息;
custom.tomcat.https.port=8443
custom.tomcat.https.secure=true
custom.tomcat.https.scheme=https
custom.tomcat.https.ssl=true
custom.tomcat.https.keystore=${user.home}/.keystore
custom.tomcat.https.keystore-password=changeit
- 然后在 WebConfiguration 类中创建一个静态类TomcatSslConnectorProperties;
@ConfigurationProperties(prefix = "custom.tomcat.https")
public static class TomcatSslConnectorProperties {
private Integer port;
private Boolean ssl = true;
private Boolean secure = true;
private String scheme = "https";
private File keystore;
private String keystorePassword;
// 这里为了节省空间,省略了 getters 和 setters,读者在实践的时候要加上
public void configureConnector(Connector connector) {if (port != null) {connector.setPort(port);
}
if (secure != null) {connector.setSecure(secure);
}
if (scheme != null) {connector.setScheme(scheme);
}
if (ssl != null) {connector.setProperty("SSLEnabled", ssl.toString());
}
if (keystore != null && keystore.exists()) {connector.setProperty("keystoreFile", keystore.getAbsolutePath());
connector.setProperty("keystorePassword", keystorePassword);
}
}
}
- 通过注解加载 tomcat.https.properties 配置文件,并与 TomcatSslConnectorProperties 绑定,用注解修饰 WebConfiguration 类;
@Configuration
@PropertySource("classpath:/tomcat.https.properties")
@EnableConfigurationProperties(WebConfiguration.TomcatSslConnectorProperties.class)
public class WebConfiguration extends WebMvcConfigurerAdapter {...}
- 在 WebConfiguration 类中创建 EmbeddedServletContainerFactory 类型的 Srping bean,并用它添加之前创建的 HTTPS 连接器。
@Bean
public EmbeddedServletContainerFactory servletContainer(TomcatSslConnectorProperties properties) {TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addAdditionalTomcatConnectors(createSslConnector(properties));
return tomcat;
}
private Connector createSslConnector(TomcatSslConnectorProperties properties) {Connector connector = new Connector();
properties.configureConnector(connector);
return connector;
}
- 通过
mvn spring-boot:run
启动应用程序; - 在浏览器中访问 URL
https://localhost:8443/internal/tomcat.https.properties
- 在浏览器中访问 URL
http://localhost:8080/internal/application.properties
分析
根据之前的文章和官方文档,Spring Boot 已经对外开放了很多服务器配置,这些配置信息通过 Spring Boot 内部的 ServerProperties 类完成绑定,若要参考 Spring Boot 的通用配置项,请点击这里
Spring Boot 不支持通过 application.properties 同时配置 HTTP 连接器和 HTTPS 连接器。在官方文档 70.8 中提到一种方法,是将属性值硬编码在程序中。
因此我们这里新建一个配置文件 tomcat.https.properties 来实现,但是这并不符合“Spring Boot 风格”,后续有可能应该会支持“通过 application.properties 同时配置 HTTP 连接器和 HTTPS 连接器”。我添加的 TomcatSslConnectorProperties 是模仿 Spring Boot 中的 ServerProperties 的使用机制实现的,这里使用了自定义的属性前缀 custom.tomcat 而没有用现有的 server. 前缀,因为 ServerProperties 禁止在其他的配置文件中使用该命名空间。
@ConfigurationProperties(prefix = “custom.tomcat.https”)这个注解会让 Spring Boot 自动将 custom.tomcat.https 开头的属性绑定到 TomcatSslConnectorProperties 这个类的成员上(确保该类的 getters 和 setters 存在)。值得一提的是,在绑定过程中 Spring Boot 会自动将属性值转换成合适的数据类型,例如 custom.tomcat.https.keystore 的值会自动绑定到 File 对象 keystore 上。
使用 @PropertySource(“classpath:/tomcat.https.properties”) 来让 Spring Boot 加载 tomcat.https.properties 文件中的属性。
使用 @EnableConfigurationProperties(WebConfiguration.TomcatSslConnectorProperties.class) 让 Spring Boot 自动创建一个属性对象,包含上述通过 @PropertySource 导入的属性。
在属性值导入内存,并构建好 TomcatSslConnectorProperties 实例后,需要创建一个 EmbeddedServletContainerFactory 类型的 Spring bean,用于创建 EmbeddedServletContainer。
通过 createSslConnector 方法可以构建一个包含了我们指定的属性值的连接器,然后通过 tomcat.addAdditionalTomcatConnectors(createSslConnector(properties)); 设置 tomcat 容器的 HTTPS 连接器。
参考资料
- 配置 SSL
Spring Boot 1.x 系列
- Spring Boot 的自动配置、Command-line-Runner
- 了解 Spring Boot 的自动配置
- Spring Boot 的 @PropertySource 注解在整合 Redis 中的使用
- Spring Boot 项目中如何定制 HTTP 消息转换器
- Spring Boot 整合 Mongodb 提供 Restful 接口
- Spring 中 bean 的 scope
- Spring Boot 项目中使用事件派发器模式
- Spring Boot 提供 RESTful 接口时的错误处理实践
- Spring Boot 实战之定制自己的 starter
本号专注于后端技术、JVM 问题排查和优化、Java 面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。