再看Spring

第一次看Spring的代码,还是学生时候,看的模棱两可。

现在有了实际的工作经验,应该会另有收获。

先浏览下Http: 

http是用TCP来传输数据的一种协议,请求报文和响应报文的结构都分为三部分:首行、头部、主体。请求报文的首行是方法、URL、http版本,响应报文的首行是http版本、状态码、简略描述。

响应报文的状态码含义:

    1xx:信息性状态码 (没有仔细了解),

     2xx:成功,200

     3xx:重定向相关,301重定向成功

    4xx:客户端错误码,404 找不到资源(一般是请求内容错误)

     5xx:服务器错误,(一般是服务器逻辑抛异常)

Tomcat Servlet

 8.5 api   http://tomcat.apache.org/tomcat-8.5-doc/api/index.html   http://tomcat.apache.org/tomcat-8.5-doc/servletapi/index.html

javax.servlet  

 
The javax.servlet package contains a number of classes and interfaces that describe and define the contracts between a servlet class and the runtime environment provided for an instance of such a class by a conforming servlet container.

这个包中的类描述和定义了servlet 和 容器之间的关系。

javax.servlet.http 

 
The javax.servlet.http package contains a number of classes and interfaces that describe and define the contracts between a servlet class running under the HTTP protocol and the runtime environment provided for an instance of such a class by a conforming servlet container.

这个包中 是 ,Servlet 和 容器 在http协议下的实现。

ServletConfig  A servlet configuration object used by a servlet container to pass information to a servlet during initialization.

一个Servlet实例初始化的参数之一是ServletConfig,容器会在初始化servlet的时候把它传进Servlet的初始化函数中(init 函数)。Servlet接口的初始化函数:public void init(ServletConfig config) throws ServletException;

ServletContext  Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.

ServletContext 是 一个servlet实例运行的上下文,实例通过ServletContext来和容器交互。ServletConfig中包含一个ServletContext。ServletContext 中的内容是变化的。

ServletConfig 中 getInitParameterNames 和 getInitParameter 用来访问 init-param标签的内容。getServletName 用来访问 servelt-name标签的内容。

其实很多时候都会在代码中写这样的结构,一个大的模块需要使用很多个小的节点一起来实现功能,这些节点依赖的外部因素分为两类:1,常亮参数 ;2,运行时的环境。在这里分别对应了ServletConfig和ServletContext。比方说手游中的新手引导系统,引导系统分为多个小的行为(点击、对话、拖拽等)。点击行为的具体样式可以配置成常亮,而点击所触发的具体事件则是根据游戏运行时的状态来确定的(一般通过一个引用变量来和容器交互)

抽象类GenericServlet 实现了 Servlet接口 和 ServletConfig接口,它的inti(ServletConfig)函数定义为:

public void init(ServletConfig config) throws ServletException {     this.config = config;     this.init(); }

继承GenericServlet的时候可以直接重写无参的初始化函数   init()  ,容器传递的ServletConfig 可以通过getServletConfig来获得。

GenericServlet 需要重写的抽象方法是

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException

HttpServlet

HttpServlet 是Servlet针对http协议的一种实现。他继承自GenericServlet,其实现的service方法如下:

public void service(ServletRequest req, ServletResponse res)     throws ServletException, IOException {
HttpServletRequest request; HttpServletResponse response;
try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; }
catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response"); }
service(request, response);
}
HttpServlet中service(HttpServletRequest , HttpServletResponse)方法的主要作用是把http请求的方法类型映射到具体的函数上。
protected void service(HttpServletRequest req, HttpServletResponse resp)     throws ServletException, IOException 

 GenericServlet的Init() 和HttpServlet的service(HttpServletRequest , HttpServletResponse)让我联想起了重构中的rename,(纯粹是联想)

Web.xml 中配置Servlet

多个servlet-name 可以使用同一个servlet-class ,init-param各不相同。(init-param相同的话就没有意义了)

一个servlet-name 可以映射多个url-pattern

Spring Api

HttpServletBean继承自HttpServlet。Bean相当于POJO,可以理解为只包含get set 属性的简单类型。

BeanWrapper 设置bean属性的接口,BeanWrapperImpl通过java反射机制来实现BeanWrapper接口。

创建BeanWrapper:

BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);

HttpServletBean 在init()中主要调用了两个函数:initBeanWrapper(bw)  和 initServletBean() ;两个函数的实现都为空。

下面括号中的内容为猜测,还未从代码上验证(initBeanWrapper 给 HttpServletBean提供了按照bean注册的功能,Spring的Ioc容器可能就是通过BeanWrapper来做的)

public final void init() throws ServletException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
        }

        PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
        if (!pvs.isEmpty()) {
            try {
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
                this.initBeanWrapper(bw);
                bw.setPropertyValues(pvs, true);
            } catch (BeansException var4) {
                if (this.logger.isErrorEnabled()) {
                    this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
                }

                throw var4;
            }
        }

        this.initServletBean();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
        }

    }

 FrameworkServlet

FrameworkServlet

This class offers the following functionality: 
•Manages a WebApplicationContext instance per servlet. The servlet's configuration is determined by beans in the servlet's namespace. 
•Publishes events on request processing, whether or not a request is successfully handled. 

 FrameworkServlet提供两个功能: 1,管理一个应用级别的环境(有疑问);2,分发请求事件,它不考虑这个请求是否会被处理。FrameworkServlet把http的多个处理方法集中到processRequest(HttpServletRequest, HttpServletResponse)方法中。

Subclasses must implement doService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) to handle requests. 
Because this extends HttpServletBean rather than HttpServlet directly, bean properties are automatically mapped onto it. 
Subclasses can override initFrameworkServlet() for custom initialization. 

 FrameworkServlet 通过doService方法来处理请求。子类的自定义的初始化内容可以放在initFramworkServlet中。

FrameworkServlet的initServletBean方法中调用了两个函数:initWebApplicationContext(),initFrameworkServlet()。其中initWebApplicationContext 用多种方式创建一个WebApplicationContext,并按条件调用一次onRefresh()

protected final void initServletBean() throws ServletException {
        this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization started");
        }

        long startTime = System.currentTimeMillis();

        try {
            this.webApplicationContext = this.initWebApplicationContext();
            this.initFrameworkServlet();
        } catch (ServletException var5) {
            this.logger.error("Context initialization failed", var5);
            throw var5;
        } catch (RuntimeException var6) {
            this.logger.error("Context initialization failed", var6);
            throw var6;
        }

        if (this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
        }

    }

我们常用的DispatcherServlet在onRefresh函数中调用了initStrategies(ApplicationContext)。也就是在初始化应用环境的时机,初始化了一些组件。

下面括号中内容尚未验证(Spring框架的工作应该就是通过这些组件实现的,了解各个组件的功能就能了解Spring)

 总结下:HttpServletBean提供了bean注入的功能,FrameworkServlet创建了应用级别的环境,并且集中处理请求。DispatcherServlet则初始化了多个策略组件。

原文地址:https://www.cnblogs.com/afraidToForget/p/10067707.html