SpringBoot 教程核心功能-Web 开发(Web原生组件注入、嵌入式 Web 容器、定制化Servlet、Web开发总结)

1.Web 原生组件注入(Servlet、Filter、Listener)

1.1 使用 Servlet API

  • 在启动类加上【@ServletComponentScan】注解,指定原生 Servlet 扫描包的路径。
  • 在原生 Servlet 类加上 【@WebServlet(urlPatterns = "/my")】注解
  • 在原生 Filter 类加上注解 【@WebFilter(urlPatterns = {"/form/*","/images/*"})】
  • 在原生 Listener 类加上注解 【@WebListener】

启动类源码:

@ServletComponentScan("com.cj.web")
@SpringBootApplication
public class Boot05Web01Application {
    public static void main(String[] args) {
        SpringApplication.run(Boot05Web01Application.class, args);
    }
}

其他源码

@WebServlet(urlPatterns = "/my") //urlPatterns 定义映射路径
public class MyServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("666");
    }
}
@Slf4j
@WebFilter(urlPatterns = {"/form/*","/images/*"}) //注意元素使用 * ,SpringMVc使用 **
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("MyFilter doFilter");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("MyFilter 初始化");
    }

    @Override
    public void destroy() {
        log.info("MyFilter 销毁");
    }
}
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("MyListener 启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("MyListener 销毁");
    }
}

1.2.使用 RegistrationBean

沿用 1.1节中的类,并去掉 注解

@Slf4j
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("MyListener 启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("MyListener 销毁");
    }
}

@Slf4j
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("MyFilter doFilter");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("MyFilter 初始化");
    }

    @Override
    public void destroy() {
        log.info("MyFilter 销毁");
    }
}

public class MyServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("666");
    }
}

然后使用配置类配置 相关 Bean

@Configuration(proxyBeanMethods = true)
public class RegistrationBeanConfig {
    @Bean
    ServletRegistrationBean myServlet() {
        MyServlet myServlet = new MyServlet();
        return new ServletRegistrationBean(myServlet, "/my");
    }

    @Bean
    FilterRegistrationBean myFilter() {
        MyFilter myFilter = new MyFilter();
//        return new FilterRegistrationBean(myFilter, myServlet()); //第一种方式
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(myFilter);
        registrationBean.setUrlPatterns(Arrays.asList("/form/*","/images/*"));
        return registrationBean;
    }

    @Bean
    ServletListenerRegistrationBean myListener() {
        return new ServletListenerRegistrationBean(new MyListener());
    }
}

1.3 DispatcherServlet 如何注入

  • SpringBoot 通过 DispatcherServletAutoConfiguration 自动配置了 DispatcherServlet 组件,DispatcherServlet 相关属性绑定到了 WebMvcProperties。对应的配置文件项以【spring.mvc】开头。
  • 通过 ServletRegistrationBean<DispatcherServlet> 把 DispatcherServlet 配置进来。
  • 默认的映射路径是【/】

Tomcat-Servlet:多个 Servlet 都能处理到同一请求时,遵循精确匹配原则。

由此原则可知,上面章节例子运行时会在Tomcat 容器中有 DispatcherServlet MyServlet ,当发出 /my 请求时,Tomcat 会直接调用 MyServlet 中的方法,所以我们定义的 SpringMVC 拦截器没有执行。

2.嵌入式 Web 容器

SpringBoot 默认支持的 WebServer 有:Tomcat、Jetty、Undertow。

官方文档说明

  • SpringBoot 应用启动发现当前是 Web 应用。Web 场景包导入 Tomcat。
  • web 应用会创建一个 Web 版的 IOC 容器 ServletWebServerApplicationContext。
  • ServletWebServerApplicationContext 会在启动的时候寻找 ServletWebServerFactory(Servlet 的 Web 服务器工厂)。
  • SpringBoot 底层有很多的 WebServlet工厂:TomcatServletWebServerFactory、 JettyServletWebServerFactory、 UndertowServletWebServerFactory。

通过 SpringBoot 源码分析

  • SpringBoot 底层会有一个自动配置类 ServletWebServerFactoryAutoConfiguration。配置类导入了 ServletWebServerFactoryConfiguration 。

  • ServletWebServerFactoryConfiguration 配置类根据动态判断系统中到底导入了哪个 Web 服务器的包,而创建对于的 web 服务器工厂。

默认是导入 tomcat 包,所以会创建 TomcatServletWebServerFactory 。

@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	static class EmbeddedTomcat {

		@Bean
		TomcatServletWebServerFactory tomcatServletWebServerFactory(
				ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
				ObjectProvider<TomcatContextCustomizer> contextCustomizers,
				ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
			...
		}

	}

	/**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	static class EmbeddedJetty {

		@Bean
		JettyServletWebServerFactory JettyServletWebServerFactory(
				ObjectProvider<JettyServerCustomizer> serverCustomizers) {
			...
		}

	}

	/**
	 * Nested configuration if Undertow is being used.
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	static class EmbeddedUndertow {

		@Bean
		UndertowServletWebServerFactory undertowServletWebServerFactory(
				ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers,
				ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
			...
		}

		...

	}

}
  • TomcatServletWebServerFactory 会创建 Tomcat 服务器(TomcatWebServer)。TomcatWebServer 的构造器函数会调用初始化方法 initialize() 该方法会启动 Tomcat,如下图。

内嵌服务器,就是手动调用启动服务器的代码(Tomcat 核心 jar 包存在),启动 Tomcat。

下图是系统中各个服务对应的类型:

切换服务器

官方文档网址

<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>

3.定制化Servlet

定制方法:

1、 修改配置文件 server.xxx 【对应类型为 ServerProperties】

2、直接自定义 ConfigurableServletWebServerFactory (实现它)

3、实现 WebServerFactoryCustomizer<T extends WebServerFactory>。把配置文件的值和 ServletWebServerFactory 进行绑定。官方说明链接

在 SpringBoot 中 xxxxCustomizer 就是是定制化器,可以改变 xxxx 默认规则

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    @Override
    public void customize(ConfigurableServletWebServerFactory server) {
        server.setPort(9000); //修改 tomcat 服务端口
    }

}

4.Web开发总结

4.1 常见的定制化方式

  • @Bean 替换、增加容器中默认组件、视图解析器。
  • 修改配置文件
  • xxxxCustomizer
  • 编写自定义的配置类 xxxConfiguration
  • web 应用编写一个配置类实现 WebMvcConfigurer 即可定制化 web 功能
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
}
  • @EnableWebMvc + WebMvcConfigurer —— @Bean 可以全面接管 SpringMVC,所有规则全部自己重新设置;实现定制和扩展功能。
@EnableWebMvc
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
}

 @EnableWebMvc 全面接管后

  • 静态资源、视图解析器、欢迎页、......,将会全部失效

4.2 使用 @EnableWebMvc 所有规则全部自己重新设置的原因

  • WebMvcAutoConfiguration 是默认的 SpringMVC 的自动配置功能类。
  • WebMvcAutoConfiguration 里面的配置要能生效,则必须 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
  • 我们一旦使用了 @EnableWebMvc 注解后会自动导入 DelegatingWebMvcConfiguration 类,
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
  • 而 DelegatingWebMvcConfiguration 是 WebMvcConfigurationSupport 的子类,所以使用 @EnableWebMvc 注解后,WebMvcAutoConfiguration 就不会生效,很多的默认的 SpringMVC 组件都不能生效,需要自行定制。
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
  •  而且 DelegatingWebMvcConfiguration 的作用是指保证 SpringMVC 的最基本使用

DelegatingWebMvcConfiguration 的功能如下:

  • 把系统中所有定制的 WebMvcConfigurer  合并起来一起生效。
  • 自动配置了一些非常底层的组件,如 RequestMappingHandlerMapping ,这些组件依赖的组件都是从容器中获取的。

4.3 原理分析套路

场景starter - xxxxAutoConfiguration - 导入 xxx 组件 - 绑定 xxxProperties - 绑定配置文件项

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值