美文网首页
渐行渐远的Servlet

渐行渐远的Servlet

作者: gringotts | 来源:发表于2018-12-27 19:38 被阅读0次

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 部署<servlet> + <servlet-mapping> @WebServlet ServletContext#addServlet
Fileter注册 web.xml部署<filter> + <filter-mapping> @WebFilter ServletContext#addFilter
*Listener注册 web.xml 部署<listener> @WebListener ServletContext#addListener
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd"
         metadata-complete="true" version="2.5">
    <context-param>
        <description>
Spring 配置文件路径参数,
该参数值将被 org.springframework.web.context.ContextLoaderListener 使用 </description>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:/META-INF/spring/spring-context.xml
        </param-value>
    </context-param>
    <listener>
        <description>
org.springframework.web.context.ContextLoaderListener 为可选申明Listener </description>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

Spring Servlet Web

理解Servlet生命周期

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

DispatcherServlet 初始化过程

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<String> helloWorld() {
        DeferredResult<String> 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<String> 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<String> 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 <servlet/> and <servlet-mapping/> in web.xml .
A @Bean of type Filter or FilterRegistrationBean behaves similarly (as a <filter/> and <filter- mapping/> ).
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)

 
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <executions>
                <execution>
                    <id>tomcat-run</id>
                    <goals>
                        <goal>exec-war-only</goal>
                    </goals>
                    <phase>package</phase>
                    <configuration>
                        <!-- ServletContext path -->
                        <path>/</path>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

使用 Tomcat 8 插件(Servlet 3.1)

<build>
        <plugins>
            <!-- Tomcat 8 Maven 插件用于构建可执行 war -->
            <!-- https://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat8-maven-plugin --> <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat8-maven-plugin</artifactId>
            <version>3.0-r1655215</version>
            <executions>
                <execution>
                    <id>tomcat-run</id>
                    <goals>
                        <!-- 最终打包成可执行的jar包 -->
                        <goal>exec-war-only</goal>
                    </goals>
                    <phase>package</phase>
                    <configuration>
                        <!-- ServletContext 路径 -->
                        <path>/</path>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        </plugins>
    </build>
    <pluginRepositories>
        <pluginRepository>
            <!-- tomcat8-maven-plugin 所在仓库 -->
            <id>Alfresco</id>
            <name>Alfresco Repository</name> <url>https://artifacts.alfresco.com/nexus/content/repositories/public/</url> <snapshots>
            <enabled>false</enabled>
        </snapshots>
        </pluginRepository>
    </pluginRepositories>
  

相关文章

  • 渐行渐远的Servlet

    Servlet简介 Servlet 是一种基于 Java 技术的 Web 组件,用于生成动态内容,由容器管理。类似...

  • 渐行渐远,渐远渐行

    生命中渐渐消失的人 容颜为老却轻易地变模糊 不敢说太多的心情 这世界太喧闹 淹没在黑夜风雨里 跌跌撞撞行走的我 丢...

  • 渐行渐远的渐行渐远

    今夜夏雨未醒 唯春雨绵绵 看着春天渐渐远去 竟不知该说点什么好 只有沉默 在沉默中望着窗外 春雨绵绵 她渐行渐远 ...

  • 渐行 渐远 见行 渐远 践行 见远

  • 渐行渐远

    我是日记星球267号星宝宝,我正在参加日记星球第十四期21天蜕变之旅,这是我的第148篇原创日记。 老姨把孙女送幼...

  • 渐行渐远

    世界上所有的亲情关系好像都是渐行渐远的,我们有着一定的血缘关系,却不得不为了生计到处奔波,剩下的就多了一份想念在里...

  • 渐行渐远

    从何时起,感觉年的脚步加快了?小时候的那个美好的年仿佛还在昨天,今年的年又要过完。一年又一年,拉长了谁的目光?...

  • 渐行渐远

    我不知道 你害怕黑夜 因为有你的陪伴 我倒是很喜爱有月亮和星星的夜晚 后来,我才知晓 你害怕夜晚 不是我矫情 那月...

  • 渐行渐远

    今日被约茶 人非故人,我亦非我。 畅意人生的追求,曾有的亲密无间。 支离破碎。 渐行渐远。

  • 渐行渐远

    文/雨天 芬和花的初次见面是在花修完哺乳假返回生产车间上班的那天。 芬见到花点点头,微微一笑。 花见到芬:“多漂亮...

网友评论

      本文标题:渐行渐远的Servlet

      本文链接:https://www.haomeiwen.com/subject/dcmdlqtx.html