springboot的web应用支持

3.1 web应用配置

3.1.1 设置Http端口

一般是在配置文件中通过server.port进行设置,也可以通过环境变量SERVER_PORT设置端口,通过环境变量设置的端口优先级更高

3.1.2配置随机Http端口

使用随机、未分配的端口只需要设置 server.prot=0即可,如果不希望对外提供Http服务,只需要设置server.prot=-1即可

3.1.3获取运行时Http端口

此外,如果需要应用在运行时动态地获取HTTP端口,则可通过SpringBoot为获取HTTP端口提供的如下两种方式。

➢通过WebServerApplicationContext来获取WebServer对象( WebServer就代表了Spring Boot所使用的Web服务器),接下来即可通过WebServer来获取端口,启动或关闭Web服务

➢通过实现ApplicationListener<WebServerInitializedEvent>接口的Bean (监听器)来监听容器初始化事件,这样同样可获取WebServer对象。

下面通过例子来示范如何在运行时获取HTTP端口。首先创建一个Maven项目,然后修改该项目的pom.xml文件,即进行如下两项修改。

➢让项目的pom.xml文件继承最新版的spring-boot-starter-parent POM文件。
➢添加Spring Boot的springboot-starter web.jar依赖。

如果程序需要在普通组件中动态地获取HTTP端口,则可让该组件实现ApiationLitener<WeSeializedEvenD接口,这样该组件就变成了监听服务器事件的一个容器监听器。

如下是监听器类的代码。

@Component
public class ContainerEventListener
implements ApplicationListener<WebServerInitializedEvent> {@Overridepublic void onApplicationEvent(WebServerInitializedEvent evt) {System.out.println("动态HTTP端口为:"+ evt.getWebServer().getPort());}
}

从上面的粗体字代码可以看出,该Bean类实现了ApplicationListener<WebServerInitializedEvent接口,这样Spring容器就会自动将它注册为容器中的监听器。

当应用使用ApplicationContext作为Spring容器时,Spring 容器会自动将容器中所有实现了监听器接口的Bean注册为监听器;但如果使用BeanFactory作为Spring容器,则需要调用BeanFactory的方法来手动注册监听器。

上面的容器监听器还实现了onApplicationEvent( WebServerInitializedEvent evt)方法,该方法将会在Web服务器初始化完成时被自动触发,程序通过该事件方法的参数即可获取WebServer对象(应用所使用的Web服务器),进而获取HTTP端口。

程序获取到HTTP端口只是简单地打印,至于实际应用怎么使用该端口,则需要根据应用的实际业务来定。
此外,还可通过依赖注入来注入WebServerApplicationContext成员变量,这样即可通过该变量来获取WebServer 对象,进而获取HTTP端口。例如如下控制器代码。

@RestController
public class HelloController
{@Autowiredprivate WebServerApplicationContext ctx;@GetMapping("/hello")public String hello(){return "HTTP端口为:" + ctx.getWebServer().getPort();}
}

上面程序中的粗体字代码使用@Autowired修饰了WerepplpationContext 类型的变量,
接下来即可通过该变量来获取WebServer对象,进而获取HTTP端口。
运行该应用,当应用的Web服务器初始化完成时,将可以在控制台看到如下输出:

动态HTTP端口为: 50828

上面这行输出即表明应用通过监听器动态获取了HTTP端口。
如果在测试阶段使用@SpringBootTest( webEnvironment=WebEnvironment.RANDOM_PORT指定随机端口进行测试,则可直接使用@LocalServerPort注解修饰成员变量来获取随机的HTTP端口.
例如如下测试用例的代码片段:

@SpringBootTest (webEnvironment=WebEnvironment.RANDOM_PORT)
class MvWebIntearat ionTests{@LocalServerPortint port;
}

上面测试用例中的粗体字代码即可通过依赖注入来获取HTTP端口。

**注意:@LocalServerPort获取端口

@LocalServerPort只是@Value("$S {local.server.port'")的元注解,千万不要在普通应用中使用该注解来注入HTTP端口。这是因为:该注解修饰的成员变量必须在Web 服务器初始化完成后才会被注入,这样可能导致应用代码去访问该成员变量时,该成员变量还没来得及被注入。**

3.1.4 启用HTTP响应压缩

当使用Tomcat、Jetty 或Undertow 作为Spring Boot 应用的Web 服务器时,可通过oplication.properties (或application.yaml)文件中设置如下属性来开启HTTP响应压缩。

server.compression.enabled=true

开启HTTP响应压缩后,可以减少网络传输的数据量,从而提高HTTP响应的速度。

在默认情况下,只有当HTTP响应的数据大于2048字节时才会开启HTTP响应压缩(道理很简单,如果响应数据本身就不多,压缩就失去意义了)。当然,Spring Boot也允许通过属性来改变该默认行为,例如,在applcation.properteies (或aplpcatoin,yaon))文件中设置如下属性:

server.compression.min- response-size=1024

上面的属性设置表明:只要HTTP响应的数据大于1024字节就会开启HTTP响应压缩。

在默认情况下,只有当HTTP响应的内容类型(content type)是以下几种时才会开启HTTP响
应压缩。

text/xml

text/plain

text/css

text/javascript

application/javascript

➢application/json

➢application/xml

从上面这些内容类型可以看出,Spring Boot默认只会对常见的文本响应(javascript、 json响应依然是文本响应)执行压缩。如果希望应用对某些特定的响应类型进行压缩,则可通过application.properties ( 或application.yaml)文件中的**server.compression.mime-types 属性**进行配置。

server.compression.mime-types=text/html, text/ CSS

上面的属性配置意味着仅当HTTP响应的内容类型是text/html和text/css时才执行压缩。

3.1.5 Web服务器的编程式配置

如果希望使用编程式的方式对Web服务器进行配置,SpringBoot则提供了如下两种方式。

定义一个实现WebServerFactoryCustomizer接口的Bean实例。

直接在容器中配置一个 自定义的ConfigurableServletWebServerFactory,它负贵创建Web服务器。

实现WebServerFactoryCustomizer接口的Bean 实例可以访问ConfigurableServletWebServerFactory对象,调用ConfigurableServletWebServerFactory的方法即可对Web服务器进行配置。

如下例子示范了通过实现WebServerFactoryCustomizer接口来配置Web服务器。首先创建一个Maven项目,然后修改该项目的pom.xml文件,即进行如下两项修改。

➢让项目的pom.xml文件继承最新版的spring-boot-starter-parent POM文件。
➢添加Spring Boot的spring-boot-starter-web.jar依赖。
接下来为应用添加一个控制器来生成RESTful响应用于测试,并通过如下Bean类对Web服务器进行配置。

@Component
public class CustomizationBean
implements ** WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>**
{@Overridepublic void customize(ConfigurableServletWebServerFactory server){// 设置端口server.setPort(8181);// 设置该服务器的context Pathserver.setContextPath("/mytest");Compression compression = new Compression();compression.setMinResponseSize(DataSize.ofBytes(1024));// 设置启用HTTP响应压缩server.setCompression(compression);}
}

正如从上面代码所看到的,该Bean类实现了WebServerFactoryCustomizer接口,该Bean就必须实现public void customize()方法,通过该方法的参数即可访问ConfigurableServletWebServerFactory参数,该参数就代表了本应用所使用的Web服务器,剩下的就是调用该参数的方法对Web服务器进行配置。

上面示例将应用的HTTP端口设为8181,并将应用的context Path 修改为“/mytest",还设置了开启HTTP响应压缩一只要响应数据大于1024字节就开启HTTP响应压缩。

运行该应用的主类来启动应用,将可以在控制台看到如下日志输出:

正如从该示例所看到的,使用编程式配置完全可以获得对Web服务器的全部控制权。换句话说,编程式配置才是Web服务器配置的本质,使用application.properties ( 或application.yaml)配置只是一种快捷方式。

提示:
有些开发者往往对aplcationproperties配置感到困惑:觉得该文件支持的配置选:项太多了,好像除了查文档或死记,全无任何规律可循。其实这都是因为没有掌握Spring Boot本质的缘故,一旦明白了 applcation.propertes配置只是编程式配置的快捷方式,以及application.properties 文件中所有的配置选项通常完全对应于编程式配置的setter方法,就不会对application.properties文件感到困惑了。

除可通过实现WebServerFactoryCustomizer接口对Web服务器进行配置之外,还可直接在容器中配置**一个自定义的ConfigurableServletWebServerFactory来对Web服务器进行配置**,正如前面所介绍的,开发者配置了自定义的ConfigurableServletWebServerFactory之后,它就取代了Spring Boot自动配置的ConfigurableServletWebServerFactory,而ConfigurableServletWebServerFactory则负责创建Web服器。
由于ConfigurableServletWebServerFactory 只是一个接口, 因此通常会使用它的如下三个实现
类来进行具体设置。

JettyServletWebServerFactory: 代表Jetty服务器。

TomcatServletWebServerFactory: 代表Tomcat服务器。

UndertowServletW ebServerFactory:代表Undertow服务器。

下面的例子示范了使用自定义的ConfigurableServletWebServerFactory代替自动配置的该Bean.首先创建一个Maven项目,然后让其pom.xml 文件继承spring-boot-starter-parent, 并添加spring-boot-starter-web.jar依赖。
接下来使用Java配置方式创建并返回一个ConfigurableServletWebServerFactory Bean,它就会
代替Spring Boot自动配置的ConfigurableServletWebServerFactory Bean。

@Configuration
public class AppConfig
{@Beanpublic ConfigurableServletWebServerFactory webServerFactory(){**TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();**// 设置端口factory.setPort(8181);Session session = new Session();// 设置服务器session的超时时长为10分钟session.setTimeout(Duration.ofMinutes(10));factory.setSession(session);// 设置404的错误页面factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));// 设置该服务器的context Pathfactory.setContextPath("/newtest");Compression compression = new Compression();compression.setMinResponseSize(DataSize.ofBytes(1024));// 设置启用HTTP响应压缩factory.setCompression(compression);return factory;}
}

上面AppConfig 类使用了@Configurntion注解修饰,这意味着该Java 类其实就相当于一份Spring配置文件,可以近似地把该注解当成XML配置文件的<beans…/>根元素,

上面AppConfig类中被@Bean注解修饰的方法就相当于配置了一个Bean实例(其作用大致类似于XML配置文件中的ban…>.元素),这意味着上面的webServerFactory()方法其实就是在Spring容器中配置了一个ConfigurableServletWebServerFactory对象,它就代替了Spring Boot自动配置的该Bean,而该Bean将会负责创建Web服务器。

上面程序中的粗体字代码创建了一个TomeatServletWebServerFactory对象,这表明本应用将会使用Tomcat作为Web服务器,接下米的代码就是调用该对象的setter方法来对Web服务器进行配置了。

上面示例将应用的HTTP端口设为8181,将服务器sossion的超时时长设为10分钟,并将应用的context Path修改为“/newtest",还设置了开启HTTP响应压缩一-只 要响应数据大于1024字节就开启HTTTP响应压缩。
运行该应用的上类来启动应用,将可以在控制台看到如下日志输出:

可见,直接在容鼎申定义ConfgurableServetWebServerFactory来配置Web服务器不仅可以设置一些通用行为, 还可以针对特定的Web服好牌(例如该示例中的Tomeat)进行设置。

事实上,使用applicaion.properties文件同样可针对特定的Web服务器进行特定的设置、例如,server.tomcat.*.代表专门针对Tonneat进行设理: server.jetty 代表专门针对Jetty进行设置。

3.2为应用添 加Servlet、Fiter. Listener

对于传统Web应用而言, Servlet、Filter和Listener是最重要的“三大金刚”,但自从Spring MVC(Spring Boot 自动整合了Spring MVC)流行之后,很多开发者甚至忘记了这三种最重要的组件,
实际上,即使使用Spring MVC,在某些极端场景下,开发者也依然需要使用传统的Servlet、Filter和Listener组件。
Spring Boo允许开发者在Web应用中使用传统的Srvlet、Filter 、Listener 组件,为Spring Boot应用添加Servlet. Filter Listener 有如下三种方式:

使用Spring Bean添加Servlet、Filter 或Listener

>使用XxzRegistrationBean手动添加Servlet. Filter 或Listener.

使用Classpath扫描添加Servlet、Filter 或Listener.

3.2.1使 用Spring Bean添加Servlet、Filter 或Listener

对于Spring Boot 而言,它会自动把Spring容器中的Servlet、Filter、 Listener 实例注册为Web服务器中对应的组件。
通过这种方式添加的Servlet、Filter 或Listener,由于它们都是Spring容器中的Bean,因此可以方便地访问application.properties中配置的属性值,也可以利用依赖注入将Spring容器中的其他Bean注入这些Servlet、Filter 或Listener.
当Spring容器中只有一个Servlet时,它默认被映射到应用的根路径为“/”当Spring容器中包含多个Servlet时,它们的映射地址就是其Bean名称(name属性值)而Filter的映射地址则默认为“/*”。

下面的例子将会示范通过Spring Bean来添加Servlet、Filter 或Listener。首先创建一个 Maven项目,然后让其pom.xml文件继承springobot-tarter-parent,并添加sringot-strterwebjar依赖。

接下来为该应用添加如下Servlet。

public class FirstServlet extends HttpServlet
{@Value("${crazyit.greeting}")private String greeting;@Overridepublic void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{log("----FirstServlet---");resp.setContentType("text/html");resp.setCharacterEncoding("utf-8");PrintWriter out = resp.getWriter();out.println("为Spring Boot添加的第一个Servlet,信息:" + greeting);}
}

上面的FirstServlet类继承了HttpServlet, 表明它就是一个标准的Servlet; 但由于在本例中会通过把它配置成Spring Bean的方式来注册它,因此它可以很方便地访问application properties中配置的属性值,如上面程序中的粗体字注解@Value(“S rcrtyitgeeting”),它的作用就是将application.properties中的crazyit.greeting属性值赋值给greeting 成员变量。

由于该Servlet是Spring容器中的Bean,因此也可以将容器中的其他Bean注入该Servlet

本例还提供了另一个Servlet-- SecondSerlvet, 其代码也比较简单,

public class SecondServlet extends HttpServlet
{@Overridepublic void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{resp.setContentType("text/html");resp.setCharacterEncoding("utf-8");PrintWriter out = resp.getWriter();out.println("为Spring Boot添加的第二个Servlet");}
}

下面是本例的Filter类代码。

public class CrazyitFilter implements Filter
{private static final Logger LOG = LoggerFactory.getLogger(CrazyitFilter.class);@Overridepublic void doFilter(ServletRequest requ, ServletResponse resp,FilterChain filterChain) throws IOException, ServletException{LOG.info("处理请求之前的过滤处理");// 放行请求,继续让目标Servlet(或其他Web组件)处理用户请求filterChain.doFilter(requ, resp);LOG.info("处理请求之后的过滤处理");}
}

上面的CrazyitFilter类实现了Filter 接口,因此它就是-个标准的Filter.

下面是本例的Listener类代码。

上面的CrazyitListener类实现了ServletContextListener 接口,因此它就是一个可用 于监听Web应用初始化和应用销毁两个事件的监听器。

根据监听目标的不同,Servlet 规范提供了如下监听器接口供开发者使用,分别用于实现监听不同目标的监听器。

ServletContextAttributeListener: 监听ServletContext ( application)范围内属性变化事件的监听器接口。

ServletRequestListener: 监听ServletRequest (用户请求)创建或关闭事件的监听器接口。

ServletRequsetAttributeListener : 监听ServletRequet (用户请求)范围内属性变化事件的监听器接口。

HttpSessionAttributeLitener监听HttpSession (用户会话)范围内属性变化事件的监听器接口。

HttpSessionListener:监听HtpSession (用户会话)创建或关闭事件的监听器接口。

ServletContextListener: 监听ServletContext (application) 启动或关闭事件的监听器接口。

不管是上面哪一种监听器,只要将其部署成Spring容器中的Bean,SpringBoot就会自动把它
注册成Web应用中的监听器。

接下来同样使用Java配置方式将这些Servlet、Filter和Listener部署成Spring容器中的Beano
下面是本例的AppConfig类代码。

@Configuration
public class AppConfig
{@Bean("first")public HttpServlet createServlet1(){FirstServlet firstServlet = new FirstServlet();return firstServlet;}@Bean("second")public HttpServlet createServlet2(){SecondServlet secondServlet = new SecondServlet();return secondServlet;}@Beanpublic ServletContextListener createListener(){CrazyitListener listener = new CrazyitListener();return listener;}@Beanpublic Filter createFilter(){CrazyitFilter filter = new CrazyitFilter();return filter;}
}

上面@Configuration修饰的AppConfig 类定义了4个@Bean修饰的方法,这些方法用于将FirstServlet、SecondServlet、CrazyitListener、CrazyitFilter部署成Spring容器中的Bean,而Spring Boot会自动把它们注册成Web容器中的Servlet、Listener、 Filter。

运行该示例的主类来启动应用,将可以在控制台看到如下日志输出:

---- Web应用初始化完成----

上面的输出即表明CrazyitListener 已经开始起作用了一当Web 应用初始化时,该监听器监听到了该事件。

使用浏览器向http:/主机名:8080/first/" (不要忘记了first 后面的斜杠)地址发送请求,即可在控制台看到如下输出:

上面的输出就是CrazyitFilter和FirstServlet的日志输出结果。

上面示例的Spring容器中配置了两个Servlet, 因此它们的映射地址就是其Bean名称(name属性值)。例如,上面配置FirstServlet的name属性值为“first",因此它的映射地址就是“ first/";配置SecondServlet的name属性值为“second",因此它的映射地址就是“ second/".

注意:Spring容器中只有一个Servlet

当Spring容器中只有一个Servlet时, 该Servlet的name属性不会起作用,它的映射地址总是“/ ”

3.2.2 使用XxxRegistrationBean注册Servlet、 Filter或Listener

前面介绍的方式是Servlet、Filter 总是使用默认的映射地址,如果嫌这种约定的映射方式不够灵活,则可使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean 来注册Servlet、Filter 和Listener,这样开发者就可以获得**全部控制权**

从它们的名字不难看出,ServletRegistrationBean 专门用于注册Servlet; FilterRegistrationBean用于注册Filter; ServletListenerRegistrationBean则用于注册Listener,它同样可以注册这些不同类型的Listener: ServletContextAttributeListener 、ServletRequestListener 、ServletRequestAttributeListener、
HttpSessionAttributeListener、HttpSessionListener、 ServletContextListener。
本例使用与前面例子相同的Servlet、 Listener 和Filter,只是改为使用XxxRegistrationBean来

注册它们。下面是本例的AppConfig类代码。

@Configuration
public class AppConfig {@Beanpublic ServletRegistrationBean<FirstServlet> createServlet1() {FirstServlet firstServlet = new FirstServlet();// 注册Servlet**  ServletRegistrationBean<FirstServlet> registrationBean =new ServletRegistrationBean<>(firstServlet, "/first");**return registrationBean;}@Beanpublic ServletRegistrationBean<SecondServlet> createServlet2() {SecondServlet secondServlet = new SecondServlet();// 注册ServletServletRegistrationBean<SecondServlet> registrationBean =new ServletRegistrationBean<>(secondServlet, "/second");return registrationBean;}@Beanpublic ServletListenerRegistrationBean<CrazyitListener> createListener() {CrazyitListener listener = new CrazyitListener();// 注册ListenerServletListenerRegistrationBean<CrazyitListener> registrationBean =new ServletListenerRegistrationBean<>(listener);return registrationBean;}@Beanpublic FilterRegistrationBean<CrazyitFilter> createFilter() {CrazyitFilter filter = new CrazyitFilter();// 注册FilterFilterRegistrationBean<CrazyitFilter> registrationBean =new FilterRegistrationBean<>(filter);return registrationBean;}
}

正如从上面的粗体字代码所看到的,使用XxxRegistrationBean 注册Servlet、 Listener、Filter的方法非常简单,程序只要在Spring容器中部署包装Servlet、Listener Filter的XxxRegistrationBea对象,Spring Boot就会自动注册被包装的Servlet、Listener、 Filter。
在使用XxxRegistrationBean注册Servlet 和Filter 时,可以直接指定它们的映射地址,如上面
的粗体字代码所示。
运行该示例的主类来启动应用,然后使用浏览器向“http://主机名:8080/first”(注意first 后面没有斜杠,与程序中注册的映射地址保持一致)地址发送请求,依然可以在控制台看到如下输出:

处理请求之前的过滤处理
----FirstServlet---
处理请求之后的过滤处理

此时可以在浏览器中看到如图3.2所示的输出。


从图3.2所示的结果可以看到,此时FirstServlet的greeting成员变量的值为null,这意味着Spring Boot没有将crazyit.greeting属性值注入FirstServlet- 一原因也很简单:此时的FirstServlet 并不是Spring容器中的Bean, 而是由开发者自行创建的对象,开发者获得了该对象的全部控制权,开发者需要自行对其进行设置。

3.2.3使用ClassPath扫描添加Servlet、Filter 或Listener

使用ClassPath扫描添加Servlet、Filter 或Listener的方式更加简单,开发者只要在Servlet类Filter类和Listener 类上分别添加@WebServlet、@WebFilter 和@WebListener注解,再通过@ServletComponentScan注解告诉Spring Boot自动扫描这些Web组件即可。
通过这种方式来添加Servlet、 Filter 和Listener 时,只要简单地添加几个注解即可,基本无须
手动使用代码进行注册。下面是本例的Servlet类代码。

@WebServlet("/first")
public class FirstServlet extends HttpServlet
{@Value("${crazyit.greeting}")private String greeting;@Overridepublic void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{log("----FirstServlet---");resp.setContentType("text/html");resp.setCharacterEncoding("utf-8");PrintWriter out = resp.getWriter();out.println("为Spring Boot添加的第一个Servlet,信息:" + greeting);}
}
@WebServlet("/second")
public class SecondServlet extends HttpServlet
{@Overridepublic void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{resp.setContentType("text/html");resp.setCharacterEncoding("utf-8");PrintWriter out = resp.getWriter();out.println("为Spring Boot添加的第二个Servlet");}
}

Listener代码

@WebListener
public class CrazyitListener implements ServletContextListener
{private static final Logger LOG = LoggerFactory.getLogger(CrazyitFilter.class);@Overridepublic void contextInitialized(ServletContextEvent sce){LOG.info("----Web应用初始化完成----");}@Overridepublic void contextDestroyed(ServletContextEvent sce){LOG.info("----Web应用销毁之前----");}
}

Filter代码

@WebFilter("/*")
public class CrazyitFilter implements Filter
{private static final Logger LOG = LoggerFactory.getLogger(CrazyitFilter.class);@Overridepublic void doFilter(ServletRequest requ, ServletResponse resp,FilterChain filterChain) throws IOException, ServletException{LOG.info("处理请求之前的过滤处理");// 放行请求,继续让目标Servlet(或其他Web组件)处理用户请求filterChain.doFilter(requ, resp);LOG.info("处理请求之后的过滤处理");}
}

,使用@ServletComponentScan注解让@WebServlet、@WebFilter 和@WebListener注解生效

@Configuration
// 通过该注解设置到指定包中扫描Servlet、Filter、Listener
@ServletComponentScan("org.crazyit.app.web")
public class AppConfig {}

启动主启动类
输入http://主机名:8080/first”

从图3.3所示的结果可以看到,此时FirstServlet的greeting成员变量有值( 接受了Spring 容器的依赖注入),这表明通过这种方式添加的FirstServlet同样可以接受Spring容器的依赖注入一原因也很简单:此时的FirstServlet依然是由Spring Boot扫描并添加到Spring容器中的Bean(它的Beanid就是其全限定类名),因此它可以接受Spring容器的依赖注入

3.3配置内嵌Web服务器

前面示例使用的都是默认的Tomcat服务器,本节将会详细介绍关于内嵌Web服务器的

3.3.1切换到其他Web服务器

很多Spring Boot的Starter都包含了默认的内嵌服务器。其默认的服务器规则如下:

对于基于Servlet 的应用,spring- boot-starter- web.jart默认依赖spring- boot-starter- tomcar. jar因此它默认包含Tomat 作为内嵌服务器。如果项目需要,则也可改为依赖spring-boot-starter-jetty.jar 或spring-boot-starter-undertow.jar,,这将意味着使用Jetty或Undertow作为内嵌服务器。

对于反应式应用,spring- boot-starter-webflux.jar默认依赖spring- boot-starter-reactor-netty.jar,因此它默认包含Reactor Netty 作为内嵌服务器。如果项目需要,则也可改为依赖spring-boot-starter-tomcat.jar、spring-boot-starter-jetty.jar 或spring-boot-starter-undertow.jar,这将意味着使用Tomcat、Jetty或Undertow作为内嵌Reactor服务器。

下面以一个基于Servlet的应用为例来示范如何切换内嵌服务器。依然是先创建一个Maven项目,然后让其pom.xml文件继承pring- boot-starter-parent,并添加pring- boot-starter-web.jar依赖。由于spring-boot-starter-web.jar默认依赖spring- boot-starter- tomcar. jar(这代表使用Tomcat作为内嵌服务器),为了切换到其他Web服务器,需要对pom.xml文件进行如下两步修改:

在spring-boot starter-web.jar依赖配置内使用<exclusios…>元素排除spring-boot-starter-tomcat.jar依赖。

显式添加spring-boot-starter-jetty.jar或spring-boot-starter-undertow.jar依赖。

如果打算使用Undertow作为内嵌服务器,则将pom.xml文件的依赖管理改为如下形式。

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><!-- 排除对Tomcat的依赖 --><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!-- 显式添加对Undertow的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

上面配置中第一段粗体 字代码为spring-boot starter-web;jar依赖排除了springoo-tarter-tomcat.jar依赖,这表示不再使用默认的Tomcat 作为内嵌服务器;第二段粗体字代码显式添加了spring- boot-starter -undertow.jar依赖,这意味着使用Undertow 作为内嵌服务器。

运行该示例的主类来启动应用,将可以在控制台看到如下输出:

通过上面的输出即可看出,本应用不再使用Tomcat 作为内嵌服务器,而是使用Undertow-2.1 .4.Final作为内嵌服务器。

如果想使用Jetty作为内嵌服务器,则将pom.xml文件改为如下形式。

 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>11</java.version><servlet-api.version>3.1.0</servlet-api.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><!-- 排除对Tomcat的依赖 --><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!-- 显式添加对Jetty的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

上面第二段粗体字代码同样是为springboot-starter-web.jar 依赖排除了默认的spring-boot-starter-tomcatjar依赖;第三段粗体字代码同样是显式添加了springboot-starterjetty.jar 依赖。但由于Jetty9.4系列还不支持Servlet 4.0规范,因此上面配置中第一行粗体字代码显式指定使用Serlet 3.1规范,

然后运行该示例的主类来启动应用,将可以在控制台看到如下输出:

Server initialized with port: 8080
jetty-9.4.31.v20200723;
......
Jetty started on port(s) 8080 (http/1.1) with context path '/

通过上面的输出即可看出,本应用不再使用Tomcat作为内嵌服务器,而是使用Jetty9.4.31作为内嵌服务器。

3.3.2 配置SSL

出于安全考虑,现在都推荐基于SSL访问主流的应用,只要稍微留意一下就不难发现,在大部分网站的网址中都使用了https:// (注意多了一个s),而不是传统的http://,这就意味着该网站是基于SSL的。

为Spring Boot应用配置SSL (Secure Sockets Layer,安全套接字层)非常简单,只需如下两步即可。

➊生成或购买SSL证书。

开发者自己生成的SSL证书通常只是用于测试,如果要部署实际运行的项目,浏览器会提示该SSL证书是不可信任的证书。对于实际运行的项目,应该购买CA机构颁发的SSL证书,只有CA机构颁发的SSL证书才会被浏览器信任,这样浏览器才不会提示证书不可信任。

❷在application.properties (或application.yaml)文件中通过serer.s.*属性进行配置。

需要说明的是,一 旦在applcation.properties (或application.yam)文件中配置了基于SSL的HTTPS连接器,传统的HTTP连接器就被自动关闭了。

提示:
Web服务器接收用户请求、对外提供服务的组件叫作连接器(Connector),不同的连接器在不同的端口对外提供服务。一个Web服务器可配置多个连接器,这样该Web服务器即可在多个端口接收请求、提供服务。打开Tomeat的conf/目录下的server.xml .文件,可以看到有多个<Connector…/>元素,它们就用于为Tomcat配置连接器。打开Jetty的etc/目录下的jty-http.xml文件,可以看到其中有一个
<Call name-"addConector…>. 元素,该元素用于添加传统的HTTP连接器。

Spring Boot不支持在application.properties (或application.yaml)文件中同时配置HTTPS连接器和HTTP连接器。如果希望应用能同时支持HTTPS连接器和HTTP连接器,则推荐使用application.properties ( 或application.yaml) 文件配置HTTPS连接器,然后使用编程式的方式添加HTTP连接器,因为使用编程式的方式添加HTTP连接器比较容易。

下面先创建一个Maven项目,让其pom.xml文件继承spring bo-stater-parent,并添加spring -boot-starter-web.jar依赖。然后为该项目添加一个简单的控制器,并对主类进行简单修改,使之成为一个Spring Boot应用。
接下来为Spring Boot应用配置SSL,只要如下两步即可。

➊生成SSL证书(如果打算购买CA机构颁发的SSL证书,这一步可以省略)。

启动命令行窗口,在该窗口中输入如下命令:

keytool -genkey -v -alias spring -keyalg RSA -keystore D:/spring.keystore -validity 36500

上面命令所使用的keytool是JDK提供的一个工具,如果读者运行该命令时提示找不到该工具,那么一定是JDK还没有配置好。

keytool命令的-genkey是它的子命令,用于生成key。该子命令支持如下常用选项。

-alias: 指定证书别名。
-keyalg: 指定算法。
-kevetore.指定证书存储在哪里
-validity: 指定证书的有效时间,此处指定36500, 这意味着有效期是100年。

接下来会要求输入证书的密码,该密码在后面配置的时候要用到,因此必须记牢。接下来该命令会提示输入姓名、组织、城市、省份、国家信息,逐项完成输入并确认之后,就会在D:/盘下生成一个spring.keystore文件。
生成SSL证书的详细过程如图3.4所示。

❷为SpringBoot配置SSL连接器。

将第1步生成的SSL证书复制到应用的resources目录下(与application.properties位于相同目录下),然后在应用的apliatio.properties文件中添加如下配置:

# 配置SSL的服务端口
server.port=8443
# 指定SSL证书的存储位置
server.ssl.key-store=classpath:spring.keystore
# 指定SSL证书的密码
server.ssl.key-store-password=123456

上面配置中的seressl.keystore passord用于指定SSL证书的密码,该密码就是第1步在包建该证书时所输入的密钥库口令密码。

运行该示例的主类来启动应用,将可以在控制台看到如下输出:

Tomcat started on port(s): 8443 (https) with context path ''

从上面的输出可以看到,该应用改为使用8443端口对外提供HTPS服务。
使用浏览器向https://主机名:8444/hello”(注意是htps:/:不再是htptp:/)/ 地址发送请求,此时可以看到如图35所示的输出:

从图35可以看出,此时Spring Boot 应用已改为在8443端口对外提供HTTPS服务。只是游览器会提示“警告:面临潜在的安全风险”,这是由于该应用所使用的SSL证书是我们自己创建的(没得到认证),如果改为使用从CA购买的SSL安全证书,浏览器将不再提示该警告。

3.3.3配置HTTP/2

通过为Spring Boot应用配置serer.http2.enabled属性可以开启HTTP/2支持,但这种支持依在Web服务器和JDK上略有不同。对于JDK 8, HTTP/2 支持不是开箱即用的,建议大家升级JDK 11 (目前Java最新的长期支持版)。
提示:
HTTP/2是为了解决现有的HTTP/1.1 性能不好、安全性不足的问题才出现的,它是目前主流的HTTP协议。

需要说明的是,Spring Boot不支持传统HTTP的HTTP/2,它只支持基于HTTPS的HTTP/2,因此在配置HTTP/2之前必须先配置SSL.
下面针对不同的Web服务器介绍HTTP/2配置。

1. Undertow的HTTP/2支持

从Undertow1.4.0+开始,即使使用早期的JDK8,Undertow也可以很好地支持HTTP/2。

2. Tomcat的HTTP/2支持

从Tomcat9.0.x开始,如果使用JDK 9及更新版本的JDK,Tomcat 默认就可以支持HTTP/2。

如果一定要使用JDK 8让Tomcat 9.0.x 支持HTTP/2,则必须为JDK 8安装libtcnative库,并在操作系统中为libtcnative 库安装它的依赖。

如果没有安装JDK 8所依赖的native库,直接使用Tomcat 9.0.x来开启HTTP/2支持,将会在控制台看到如下错误信息:

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"1 connector that
does not support ALPN 。

该错误并不是致命的,但它会导致该应用依然使用HTTP/1.1的SSL支持。

要开启HTTP/2支持,只要将前一一个示例中的application.properties文件改为如下形式即可。

# 配置SSL的服务端口
server.port=8443
# 指定SSL证书的存储位置
server.ssl.key-store=classpath:spring.keystore
# 指定SSL证书的密码
server.ssl.key-store-password=123456# 开启HTTP/2支持
**server.http2.enabled=true**

上面粗体字代码为Spring Boot应用开启了HTTP/2 支持。由于本书使用JDK 11环境,因此无须为Tomcat添加其他额外的库。
运行该示例的主类来启动应用,,然后使用浏览器向“https://主机名:8443/hello"地址发送请求,接下来可以在控制台看到如图3.6所示的结果。

3. Jetty的HTTP/2支持

为了支持HTTP/2, Jetty 需要额外的org.eclipse.jetty.http2的http2-server.jar 依赖支持。此外,根据配置环境的不同,可能还需要添加以下额外的不同依赖。

如果使用 JDK9及更新版本的JDK,则需要添加org.eclipse.jetty的jetty-alpn-java-server.jar依赖。

如果使用JDK 8u252+及更新版本的JDK 8,则需要添加org.eclipse.jetty的jety-alpn-openjdk8-server.jar依赖。

对于其他JDK,则需要添加org.eclipse.jetty的jetty-alpn-conscrypt-server.jar依赖及Conscrypt库。

4. Reactor Netty的HTTP/2支持

spring-boot-webflux- starter默认使用Reactor Netty作为内嵌服务器,如果使用JDK9及更新版本的JDK, Reactor Netty完全可以支持HTTP/2;如果使用JDK 8环境,则需要额外的原生库来支持HTTP/2。

3.3.4 配置访客日志

Web服务器可以将所有访问记录以日志形式记录下来,Spring Boot同样为这种访客日志提了支持 ,Spring Boot为Tomcat、Jetty、 Undertow 分别提供了相应的属性来配置访客日志。依然使用前一个示例,只要在它的application.properties文件中添加如下内容即可。

# 配置SSL的服务端口
server.port=8443
# 指定SSL证书的存储位置
server.ssl.key-store=classpath:spring.keystore
# 指定SSL证书的密码
server.ssl.key-store-password=123456# 开启HTTP/2支持
server.http2.enabled=true# 配置Tomcat的基路径
server.tomcat.basedir=my-tomcat
# 开启Tomcat的访客日志记录
server.tomcat.accesslog.enabled=true
# 指定访客日志的记录格式
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)

正如从上面配置所看到的,为Tomeat配置访客日志时配置了三个属性。但为Jetty、Undertow配置访客日志时,通常只需要配置两个属性。

➢sever.xxxx. acesslog enable:用于开启日志。其中xxx可被更换为tomcat、jetty或undertow.

➢senver.xxx. acsslog.pattern: 指定日志的记录格式。其中xx可被更换为tomcat或Undertow

server.jetty. accesslog.file-date-format: 指定日志的记录格式 用于jetty

Tomcat往往需要额外配置一个属性,这是由于Tomcat的访客日志默认总保存在Tomcat基路径下的logs目录(该目录可通过server.tomcat.accesslog.directory属性修改)中,因此为Tomcat配置访客日志时需要额外配置-、个servertomeat.basedir属性,用于指定Tomcat的基路径。

运行该示例的主类来启动应用,然后使用浏览器向“https://主机名:8443/hello"地址多次发送请求,接下来即可在该应用的路径下发现一个my-tomcat目录,该目录下包含了一个logs目录,该目录中保存了Tomcat 的访客日志文件。

如果使用Undertow作为服务器,则需要在application.properties文件中添加如下配置:

#开启Undertow的访客日志记录
server.undertow.accesslog.enabled=true
#推定访客日志的记录格式
serverundertow、accesslog.pattern=%t %a "%r" %s (%D ms)

添加上面配置之后,Spring Boot会自动将Undertow的访客日志记录在应用路径下的logs目录(该目录可通过server.undertow.accesslog. directory属性修改)中。

如果使用Jetty作为服务器,则需要在application.properties文件中添加如下配置:

#开启Jetty的访客日志记录
server.jetty.accesslog.enabled=true
#指定日志文件的存储路径
server.jetty.accesslog.filename=/var/log/ jetty-access.log

3.4 管理Spring MVC

SpringBoot的真正功能只是自动配置和快速整合,在SpringBoot应用中前端MVC由Spring MVC充当。因此,前面示例中用到的@Controller、@RestController @RequestMapping

Restful服务支持

访问sql数据库

疯狂springboot终极讲义笔记(二)相关推荐

  1. 【免费送书】《疯狂Spring Boot终极讲义》

    有些人还在直接用Jedis操作Redis数据库,但这种方式非常不方便,而且很不灵活.用Spring Boot整合Redis之后,既能非常方便地操作Redis数据库,Spring Boot又可以自由地在 ...

  2. 《疯狂前端开发讲义jQuery+Angular+Bootstrap前端开发实践》学习笔记

    <疯狂前端开发讲义jQuery+Angular+Bootstrap前端开发实践>学习笔记 二〇一九年二月十三日星期三2时28分54秒 前提:本书适合有初步HTML.CSS.JavaScri ...

  3. 《疯狂的JAVA讲义》笔记-第8章集合

    <疯狂的JAVA讲义>笔记-第8章集合 Iterator .ListIterator接口 Iterator迭代时是将元素的值返回,并不是将元素本身返回,所以迭代时无法更改元素的值.但是可以 ...

  4. 【Visual C++】游戏开发笔记二十一 游戏基础物理建模(三) 摩擦力系统模拟

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. http://blog.csdn.net/zhmxy555/article/details/7555785 作者:毛星云    邮箱: h ...

  5. SpringBoot源码笔记分析

    SpringBoot源码笔记分析 1.基础 1.配置SpringBoot热部署 1.引入依赖 <dependency><groupId>org.springframework. ...

  6. 高斯课堂数电讲义笔记_学技树

    [高斯课堂]概率论与数理统计\1.mp4 [高斯课堂]概率论与数理统计\10.mp4 [高斯课堂]概率论与数理统计\11.mp4 [高斯课堂]概率论与数理统计\12.mp4 [高斯课堂]概率论与数理统 ...

  7. 8. SpringBoot基础学习笔记

    SpringBoot基础学习笔记 课程前置知识说明 1 SpringBoot基础篇 1.1 快速上手SpringBoot SpringBoot入门程序制作 1.2 SpringBoot简介 1.2.1 ...

  8. 尚硅谷springboot学习课程笔记

    **一.**Spring Boot 入门 !!!此文并非原创,只是转载分享尚硅谷的springboot原学习笔记 1.Spring Boot 简介 简化Spring应用开发的一个框架: 整个Sprin ...

  9. 【Visual C++】游戏开发笔记二十一 游戏基础物理建模 三 摩擦力系统模拟

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

最新文章

  1. ssh免密连接远程服务器
  2. 【算法】动态规划+“背包九讲”原理超详细讲解+常见dp问题(9种)总结
  3. Linux pg数据库导出数据,linux下 postgres实现导出和导入
  4. TaggingJS – 可以灵活定制的 jQuery 标签系统插件
  5. Java IO流之随机读写流RandomAccessFile
  6. 树莓派lnmp安装mysql_在树莓派上安装 LNMP
  7. python常见面试题目(面试官最爱问的python面试题)
  8. 详解数字电视机顶盒的功能技术与应用3
  9. IDEA 修改项目名称
  10. 乔布斯首份手写求职信再次被拍卖
  11. English Learning from research paper
  12. rinetd 安装、配置方法 通过端口转发来访问内网服务
  13. JAVA学习:坦克大战(怀旧版)游戏开发代码
  14. Windows系统口令扫描之——使用Tscrack扫描3389口令
  15. 计算机图形学-消隐算法
  16. 微信小程序登陆流程详详详解 看这一篇就够了
  17. oracle cogs 科目,OM模块关于COGS的生成
  18. 怎样使用 Hardhat 开发 Solidity 智能合约
  19. 顺丰云服务器,基于华为云云原生解决方案,顺丰“快递+”这一项业务效率提升了48倍...
  20. 字体图标在服务器上显示不出来,fontawesome图标字体库组件在服务器上显示不出来图标的解决...

热门文章

  1. 强主动性的人,如何做事一杠子到底?
  2. github账户登录ArcGIS developer并申请API key
  3. 如何获取 ChatGPT OpenAI API Key
  4. DAMA数据治理与数据质量--非结构化数据的数据质量管理
  5. 如何读到一个文件的最后更新日期和时间
  6. inno setup使用1 记录一下相关参数
  7. 软件“生命”系统进化论——软件以负熵为生!
  8. 塔顶分凝器全凝器区别_(单选)在相同的回流比和塔顶蒸汽组成下,采用分凝器+全凝器的二元连续精馏塔与仅采用全凝器的塔相比,()...
  9. 写点看Harvard CS50 公开课的感受
  10. Java如何输出Word报告