渐行渐远的Servlet

渐行渐远的Servlet_第1张图片

Servlet简介

Servlet 是一种基于 Java 技术的 Web 组件,用于生成动态内容,由容器管理。类似于其他 Java 技术组件,Servlet 是平台无 关的 Java 类组成,并且由 Java Web 服务器加载执行。通常情况,由 Servlet 容器提供运行时环境。Servlet 容器,有时候也 称作为 Servlet 引擎,作为Web服务器或应用服务器的一部分。通过请求和响应对话,提供Web 客户端与 Servlets 交互的能 力。容器管理Servlets实例以及它们的生命周期。

从功能上,Servlet 介于 CGI(Common Gateway Interface)与服务扩展(如:Netscape Server API 或 Apache 模块)之 间。

在体系上,Servlet 技术(或者规范)属于 Java EE 技术(规范)的一部分。不过 Servlet 并非一开始就隶属于 J2EE 或者 Java EE。接下来的小节将会介绍 Servlet 各个版本。

Servlet 版本

规范版本 发布时间 Java平台 主要更新
Servlet 4.0 2017年9月 Java EE 8 支持Http/2
Servlet 3.1 2013年5月 Java EE 7 非阻塞I/O、Http协议更新机制(WebSocket)
Servlet 3.0 2009年12月 Jave EE 6 可插拔、简化部署、异步Servlet、安全、文件上传
Servlet 2.5 2005年9月 Java EE 5 Annotation支持
Servlet 2.4 2003年11月 J2EE 1.4 web.xml 支持 XML Scheme
Servlet 2.3 2001年8月 J2EE 1.3 新增Filter、事件/监听器、Wrapper
Servlet 2.2 1999年8月 J2EE 1.2 作为J2EE的一部分,以.war 文件作为独立web应用

Servlet 核心API

核心组件API 说明 起始版本 SpringFramework代表实现
javax.servlet.Servlet 动态内容组件 1.0 DispatcherServlet
javax.servlet.Filter Servlet过滤器 2.3 CharacterEncodingFilter
javax.servlet.ServletContext Servlet应用上下文
javax.servlet.AsyncContext 异步上下文 3.0
javax.servlet.ServletContextListener ServletContext生命周期监听器 2.3 ContextLoaderListener
javax.servlet.ServletRequestListener ServletRequest生命周期监听器 2.3 RequestContextListener
javax.servlet.http.HttpSessionListener HttpSession生命周期监听器 2.3 HttpSessionMutexListener
javax.servlet.AsyncListener 异步上下文监听器 3.0 StandardServletAsyncWebRequest
javax.servlet.ServletContainerInitializer Servlet容器初始化器 3.0 SpringServletContainerInitializer

Servlet 组件注册

Servlet注册

注册方式 传统方式 注解方式 编程方式
Servlet注册 web.xml 部署 + @WebServlet ServletContext#addServlet
Fileter注册 web.xml部署 + @WebFilter ServletContext#addFilter
*Listener注册 web.xml 部署 @WebListener ServletContext#addListener


    
        
Spring 配置文件路径参数,
该参数值将被 org.springframework.web.context.ContextLoaderListener 使用 
        contextConfigLocation
        
            classpath*:/META-INF/spring/spring-context.xml
        
    
    
        
org.springframework.web.context.ContextLoaderListener 为可选申明Listener 
        org.springframework.web.context.ContextLoaderListener
    

Spring Servlet Web

理解Servlet生命周期

  • 初始化:init(ServletConfig)
  • 服务:service(ServletRequest,ServletResponse)
  • 销毁:destroy()

DispatcherServlet 初始化过程

渐行渐远的Servlet_第2张图片
Servlet初始化过程

理解Filter生命周期

  • 初始化
  • 服务
  • 销毁

理解ServletContext生命周期

  • 初始化:contextInitialized(ServletContextEvent)
  • 销毁:contextDestroyed(ServletContextEvent)

Servlet 异步支持

@WebServlet(asyncSupported = true,//激活异步特性
        name = "asyncServlet",// servlet 名字
        urlPatterns = "/async-servlet")
public class AsyncServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
        // 判断是否支持异步
        if (request.isAsyncSupported()) {
            // 创建 AsyncContext
            AsyncContext asyncContext = request.startAsync();
            // 设置超时时间
            asyncContext.setTimeout(50L);
            asyncContext.addListener(new AsyncListener() {
                @Override
                public void onComplete(AsyncEvent event) throws IOException {
                    println("执行完成");
                }

                @Override
                public void onTimeout(AsyncEvent event) throws IOException {
                    HttpServletResponse servletResponse = (HttpServletResponse) event.getSuppliedResponse();
                    servletResponse.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
                    println("执行超时");
                }

                @Override
                public void onError(AsyncEvent event) throws IOException {
                    println("执行错误");
                }

                @Override
                public void onStartAsync(AsyncEvent event) throws IOException {
                    println("开始执行");
                }
            });
        }

            println("Hello,World");
//            ServletResponse servletResponse = asyncContext.getResponse();
//            // 设置响应媒体类型
//            servletResponse.setContentType("text/plain;charset=UTF-8");
//            // 获取字符输出流
//            PrintWriter writer = servletResponse.getWriter();
//            writer.println("Hello,World");
//            writer.flush();
    }

        private static void println(Object object) {
            String threadName = Thread.currentThread().getName();
            System.out.println("AsyncServlet[" + threadName + "]: " + object);
        }

}

DeferredResult 支持

@GetMapping("/hello-world")
    public DeferredResult helloWorld() {
        DeferredResult result = new DeferredResult<>(50L);
//        result.setResult("Hello,World");
        // 入队操作
//        queue.offer(result);
        println("Hello,World");
        result.onCompletion(() -> {
            println("执行结束");
        });

        result.onTimeout(() -> {
            println("执行超时");
        });

        return result;
    }

Callable支持

@GetMapping("/callable-hello-world")
    public Callable callableHelloWorld() {
        final long startTime = System.currentTimeMillis();

        println("Hello,World");

        return () -> {
            long costTime = System.currentTimeMillis() - startTime;
            println("执行计算结果,消耗:" + costTime + " ms.");
            return "Hello,World";
        };
    }

CompletionStage支持

@GetMapping("/completion-stage")
    public CompletionStage completionStage(){
        final long startTime = System.currentTimeMillis();

        println("Hello,World");

        return CompletableFuture.supplyAsync(()->{
            long costTime = System.currentTimeMillis() - startTime;
            println("执行计算结果,消耗:" + costTime + " ms.");
            return "Hello,World"; // 异步执行结果
        });
    }

Spring Web MVC异步Servlet实现原理

Java Specification Requests (JSR) : https://github.com/mercyblitz/jsr

Spring Boot Servlet Web

Spring Boot嵌入式Servlet容器限制

Servlet特性 兼容性 解决方案
web.xml 不支持 RegistrationBean或 @Bean 注册
ServletContainerInitializer 不支持 ServletContextInitializer
@WebServlet等 有限支持 依赖@ServletComponentScan

参考资料一

87.2 Convert an Existing Application to Spring Boot

you may need to add some configuration to your Application context, by replacing those elements from the web.xml , as follows:
A @Bean of type Servlet or ServletRegistrationBean installs that bean in the container as if it were a  and  in web.xml .
A @Bean of type Filter or FilterRegistrationBean behaves similarly (as a  and  ).
An ApplicationContext in an XML file can be added through an @ImportResource in your Application . Alternatively, simple cases where annotation configuration is heavily used already can be recreated in a few lines as @Bean definitions.

参考资料二

27.4.2 Servlet Context Initialization

Embedded servlet containers do not directly execute the Servlet 3.0+
javax.servlet.ServletContainerInitializer interface or
Spring’s org.springframework.web.WebApplicationInitializer interface. This is an intentional design decision intended to reduce the risk that third party libraries designed to run inside a war may break Spring Boot applications.

参考资料三

Scanning for Servlets, Filters, and listeners

When using an embedded container, automatic registration of classes annotated
with @WebServlet , @WebFilter , and @WebListener can be enabled by using @ServletComponentScan .

Spring Boot Servlet注册

通过RegistrationBean 注册

  • ServletContextInitializer

    • RegistrationBean
      • ServletListenerRegistrationBean
        • @WebListener
      • FilterRegistrationBean
        • @WebFilter
      • ServletRegistrationBean
        • @WebServlet

    @ServletComponentSacn 扫描package->@Web* ->RegistrationBean Bean定义 -> RegistrationBean Bean

通过@Bean注册

通过@ServletComponentScan注册

Spring Boot应用传统Servlet容器部署

基本原理

扩展SpringBootServletInitializer

public class DefaultSpringBootServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        builder.sources(SpringBootServletBootstrap.class);
        return builder;
    }

}
@EnableAutoConfiguration
@ServletComponentScan(basePackages = "com.imooc.spring.web.servlet")
class SpringBootServletBootstrap {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootServletBootstrap.class, args);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ServletRegistrationBean asyncServletServletRegistrationBean(){
        ServletRegistrationBean registrationBean =  new ServletRegistrationBean(new AsyncServlet(),"/");
        registrationBean.setName("MyAsyncServlet");
        return registrationBean;
    }

    @Bean
    public ServletContextInitializer servletContextInitializer() {
        return servletContext -> {
            CharacterEncodingFilter filter = new CharacterEncodingFilter();
            FilterRegistration.Dynamic registration = servletContext.addFilter("filter", filter);
            registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/");
        };
    }
}

使用Tomcat 7插件(Servlet3.0)

 

    
        
            org.apache.tomcat.maven
            tomcat7-maven-plugin
            2.1
            
                
                    tomcat-run
                    
                        exec-war-only
                    
                    package
                    
                        
                        /
                    
                
            
        
    

使用 Tomcat 8 插件(Servlet 3.1)


        
            
             
            org.apache.tomcat.maven
            tomcat8-maven-plugin
            3.0-r1655215
            
                
                    tomcat-run
                    
                        
                        exec-war-only
                    
                    package
                    
                        
                        /
                    
                
            
        
        
    
    
        
            
            Alfresco
            Alfresco Repository https://artifacts.alfresco.com/nexus/content/repositories/public/ 
            false
        
        
    
  

你可能感兴趣的:(渐行渐远的Servlet)