Springboot之---强大的Servlet(四)

简介: 如今回头看下Servlet不仅如此强大,还具有很强烈的参考意义,能在现如今流行的大部分框架中找到它的影子。下面文章不止与探索Servlet,可能在其中穿插其他的关联知识点,旨在能从此次的学习中获取更多的知识点参考资料总结,转化为自己的理解输出,在文中我尽量以截图+复制全限定类名的方式记录,以便感兴趣的再次查找。

    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";

 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();
        //GET
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            //There's no need to override this method. 没有必要~
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }


    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {

    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_post_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
}

注:在javaHttpServlet中,与Tomcat中的dopost方法如出一辙

真正的调用链(妥妥的责任链模式)是
流程

Tomcat与SpringMVC的结合点:
(1)所有配置了路由信息的处理方法最终都是通过反射的方式进行调用的;
(2)在Java8中,反射方法调用最终落脚于NativeMethodAccessorImpl类的native方法:
private static native Object invoke0(Method var0, Object var1, Object[] var2);
在此处与JVM底层交互,实现跨代码衔接执行;
(3)观察到的比较重要的设计模式:职责链模式(ApplicationFilterChain)、委派模式(DelegatingFilterProxy)、
工厂模式、策略模式、代理模式(FilterChainProxy)、外观模式、适配器模式(HandlerAdapter);
(4)Tomcat与SpringMVC的结合点:ApplicationFilterChain与DispatcherServlet(继承于FrameworkServlet);
(5)在集成了Tomcat的SpringBoot项目中,先启动的不是Tomcat,而是Spring,Spring的工厂(默认DefaultListableBeanFactory)
读取注解完成各类Bean(WebApplicationContext、securityFilterChainRegistration、dispatcherServletRegistration、各类FilterInitializer与Filter)
的初始化,放入IoC容器,然后做路由Mapping,创建FilterChain,开启JMX等;
(6)Servlet、Filter是单实例多线程的,成员变量线程不安全,方法内局部变量线程安全;SingleThreadModel采用同步/实例池的方式来确保不会有两个线程同时执行servlet的service方法,但已被弃用,需自行确保成员变量线程安全;
————————————————
版权声明:本文为CSDN博主「wanxu12345678910」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wanxu12345678910/article/details/83352371

ContextLoaderServlet与下文中的ContextLoaderListener功能完全相同


<servlet>
         <servlet-name>context</servlet-name>
         <servlet-class>
           org.springframework.web.context.ContextLoaderServlet
         </servlet-class>
         <load-on-startup>1</load-on-startup>
</servlet> 

HttpServletResponse响应码

流程

监听器: 实现接口、标记

比如MQ,观察者模式,所有的时间监听都会继承 extend java.util.EventListener接口,但里面什么都没有
,称之为mark接口,经典实现:ContextLoaderListener、RequestContextListener(重要)

/**
 * A tagging interface that all event listener interfaces must extend.
 * @since 1.1
 */
public interface EventListener {
}

流程

/**
 * Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
 * Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
 *
 * <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
 * application context via the {@link #ContextLoaderListener(WebApplicationContext)}
 * constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
 * See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 17.02.2003
 * @see #setContextInitializers
 * @see org.springframework.web.WebApplicationInitializer
 */
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {


}

见名知意既然包含contextLoader必然跟上线文息息相关,在初始化容器时加载配置~


@Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        //将请求对象放入ThreadLocal中
        LocaleContextHolder.setLocale(request.getLocale());
        RequestContextHolder.setRequestAttributes(attributes);
    }

重要:Servlet在同一个线程中,当初始化时放到对象里,当请求销毁时,自动将Threadlocal对象销毁,防止了内存泄漏的问题
当有请求到达时,会从线程池中取出一个线程来执行任务,执行完毕后再将线程回收至线程池,这样当前请求不可能拿到上一个请求保存在ThreadLocal对象里的值
流程


@Override
    public void requestDestroyed(ServletRequestEvent requestEvent) {
        ServletRequestAttributes attributes = null;
        Object reqAttr = requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE);
        if (reqAttr instanceof ServletRequestAttributes) {
            attributes = (ServletRequestAttributes) reqAttr;
        }
        RequestAttributes threadAttributes = RequestContextHolder.getRequestAttributes();
        if (threadAttributes != null) {
            // We're assumably within the original request thread...
            LocaleContextHolder.resetLocaleContext();
            RequestContextHolder.resetRequestAttributes();
            if (attributes == null && threadAttributes instanceof ServletRequestAttributes) {
                attributes = (ServletRequestAttributes) threadAttributes;
            }
        }
        if (attributes != null) {
            attributes.requestCompleted();
        }
    }

流程

/**
 * Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
 * Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
 *
 * <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
 * application context via the {@link #ContextLoaderListener(WebApplicationContext)}
 * constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
 * See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 17.02.2003
 * @see #setContextInitializers
 * @see org.springframework.web.WebApplicationInitializer
 */
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

}

插播一句:在书写过程中发现某URL响应变慢,在分析SQL时,用到了in查询,执行分析计划用到了索引

目录
相关文章
|
1月前
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
149 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
4月前
|
XML Java 应用服务中间件
springboot定制嵌入式的servlet
SpringBoot允许定制嵌入式Servlet容器,如修改配置或更换默认的Tomcat。配置可通过`application.properties`设置`server.port`和`server.tomcat.*`属性。此外,可创建`EmbeddedServletContainerCustomizer` Bean来自定义容器,例如改变端口。要替换默认的Tomcat,需排除`spring-boot-starter-tomcat`依赖,并引入`spring-boot-starter-jetty`。
|
5月前
|
Java 应用服务中间件 容器
手写SpringBoot(二)之动态切换Servlet容器
我们在切换serlvet容器的时候,会将SpringBoot默认的tomcat jar包给排除掉,换上我们需要的jar包,比如jetty。
39 0
|
Java 应用服务中间件 容器
25 SpringBoot使用外置的Servlet容器
25 SpringBoot使用外置的Servlet容器
52 0
|
6月前
|
Java 应用服务中间件 Maven
框架的优点(SpringBoot VS Servlet)
框架的优点(SpringBoot VS Servlet)
|
6月前
|
前端开发 Java 容器
SpringBoot中注册Servlet、Filter和Listener(代码和注解两种方式)
SpringBoot中注册Servlet、Filter和Listener(代码和注解两种方式)
126 0
|
前端开发 Java 应用服务中间件
24 SpringBoot配置嵌入式Servlet容器
24 SpringBoot配置嵌入式Servlet容器
80 0
24 SpringBoot配置嵌入式Servlet容器
|
Java API Spring
在spring boot中添加servlet filter *Listener
在spring boot中添加servlet filter *Listener
在spring boot中添加servlet filter *Listener
|
消息中间件 负载均衡 Java
Springboot之---强大的Servlet(十 一)
如今回头看下Servlet不仅如此强大,还具有很强烈的参考意义,能在现如今流行的大部分框架中找到它的影子。下面文章不止与探索Servlet,可能在其中穿插其他的关联知识点,旨在能从此次的学习中获取更多的知识点参考资料总结,转化为自己的理解输出,在文中我尽量以截图+复制全限定类名的方式记录,以便感兴趣的再次查找。
114 0
|
消息中间件 SQL 缓存
Springboot之---强大的Servlet(十)
如今回头看下Servlet不仅如此强大,还具有很强烈的参考意义,能在现如今流行的大部分框架中找到它的影子。下面文章不止与探索Servlet,可能在其中穿插其他的关联知识点,旨在能从此次的学习中获取更多的知识点参考资料总结,转化为自己的理解输出,在文中我尽量以截图+复制全限定类名的方式记录,以便感兴趣的再次查找。
144 0