亲宝软件园·资讯

展开

MVC模式与Servlet执行流程

AirSkys 人气:3

Servlet生命周期

五个部分,从加载到卸载,如同人类的出生到死亡

  1. 加载:Servlet容器自动处理
  2. 初始化:init方法 该方法会在Servlet被加载并实例化后执行
  3. 服务:service抽象方法:具体实现是doGet(),doPost()方法
  4. 销毁:destroy(),Servlet被系统回收时执行
  5. 卸载:Servlet容器自动处理

init():

  • 默认第一次访问Servlet时会被执行(只执行这一次,可以修改为Tomcat启动时自动执行:
  • 2.5:web.xml中<servlet>字段添加<load-on-startup>1(代表第1个Servlet)..
  • 3.0:@WebServlet(value = "/Servlet3",loadOnStartup = 1)

service():->doGet() doPost:调用几次,则执行几次
destroy():关闭tomcat服务时

Servlet API

由两个大类四个软件包组成::

即Servlet API可以适用于任何通信协议。但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
我们学习的Servlet,是位于javax.servlet.http包中的类和接口,是基础HTTP协议。

Servlet继承关系

ServletConfig:接口
ServletContext getServletContext():获取Servlet上下文对象 application
String getInitParameter(String name):在当前Servlet范围内,获取名为name的参数值(初始化参数)
a.ServletContext中的常见方法(application):
getContextPath():相对路径
getRealPath():绝对路径
setAttribute()、getAttribute()
---->
String getInitParameter(String name);在当前Web容器范围内,获取名为name的参数值(初始化参数)
初始化全局参数

    <context-param>
        <param-name>globalParam</param-name>
        <param-value>global value...</param-value>
    </context-param>

初始化Servlet参数

  • Servlet2.5
    <servlet>
        <servlet-name>my</servlet-name>
        <servlet-class>com.hacker.servlet.MyServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    <!--配置当前Servlet初始化参数 -->
        <init-param>
            <param-name>servletparamname</param-name>
            <param-value>servletparamvalue...</param-value>
        </init-param>
    </servlet>
  • Servlet3.0
@WebServlet(value = "/Servlet3",loadOnStartup = 1,initParams = {@WebInitParam(name="servletparamname30",value = "servletparamvalue30")})

注意:此注解只隶属于某一个具体的Servlet,因此无法为整个Web容器设置初始化参数(如果要通过3.0方式设置,仍需在web.xml中设置)
获取全局参数
ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。
通过在ServletConfig中调用getServletContext方法,也可以获得ServletContext对象。

    @Override
    public void init() throws ServletException {
        System.out.println("init...");
        //获取整个Web容器的初始化参数
        String str=super.getServletContext().getInitParameter("globalParam");
        System.out.println("当前Web容器的初始化的参数为"+str);
    }

获取当前Servlet参数
当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象
其中几个方法如下:

    @Override
    public void init() throws ServletException {
        System.out.println("init...");
        //获取当前Servlet的初始化参数
        String str=super.getInitParameter("servletparamname");
        System.out.println("当前Servlet的初始化参数为"+str);
    }

请求与响应

当我们在在请求Servlet容器具体的执行流程的细节是什么呢?一起来看一看
首先我们知道请求的过程最终传给了名为service的方法,那service方式到底是怎么执行的,我们先来简单的了解下
首先查看入口类继承的HTTPServlet类


点进去发现继承至GenericServlet,继续跟进

GenericServlet实现了一个Servlet接口

接口中定义了service方法,并且有两个参数ServletRequest和ServletResponse代表请求和响应,那么我们自定义的Servlet肯定不是实现的这个service方法,因为我们重写的service方法形参为HttpServletRequest和HttpServletResponse

现在就来找找到底是重写的那个service方法,首先来看GenericServlet类

在GenericServlet类中发现实现了service的抽象方法,传入参数为ServletRequest,明显也不是,继续跟进HTTPServlet类

在HTTPServlet类中发现两个service方法,很明显第二个service方法参数也是ServletRequest,所以第二个service方法为实现方法,下面来看看具体实现

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }

        this.service(request, response);
    }

可以看到该实现方法将Servlet强转为了HttpServlet,

HttpServlet继承自Servlet,将父类变为了子类,把通用的响应,转换为了特需的HTTP响应,之所以能够这样强制的转换,是因为在调用Servlet的Service方法时,Servlet容器总会传入一个HttpServletRequest对象和HttpServletResponse对象,预备使用HTTP。因此,转换类型当然不会出错了。
PS:Java中父类想要转换为子类,父类的实例必须指向子类的应用,形如

    public static void main(String[] args) {
        //Car为父类,BigCar为子类
        Car car=new BigCar();//这里car父类对象的引用为BigCar子类 父类是子类构造出来的实例
        BigCar bc=(BigCar)car;//所以这里可以将父类对象car强转为子类对象BigCar
        bc.setName("ssss");//这里就可以调用子类的方法
        test(new BigCar());
    }
    public static void test(Car car) {
        BigCar bigCar = (BigCar) car;
        if (bigCar instanceof Car) {
            System.out.println("1");
        }
    }

最后调用了当前类中的重载方法service

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

在该方法中,将请求类型进行了划分,判定请求类型调用不同的方法,所以我们重写的service方法实际上是接收了所有类型的请求,那么可以针对不同请求重写相应的方法,来简化我们的操作。
一般装饰者就是在主体组件扩展到具体的实现类时,会引入一个中间层,把装饰者的公布部分引入进来,在引入具体的实现时,只需要实现自己特定的部分就行了。公共的就放在上面,中间层中。

MVC案例

学了这么多,现在就来动手实现一个MVC简单登录案例

加载全部内容

相关教程
猜你喜欢
用户评论