zoukankan      html  css  js  c++  java
  • servlet反射、生命周期、接口

    什么是Servlet

    Servlet是JavaWeb的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:

    l  接收请求数据;

    l  处理请求;

    l  完成响应。

      例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。

    实现Servlet的方式(由我们自己来写!)

    实现Servlet有三种方式:

    l  实现javax.servlet.Servlet接口;

    l  继承javax.servlet.GenericServlet类;

    l  继承javax.servlet.http.HttpServlet类;

      通常我们会去继承HttpServlet类来完成我们的Servlet,但学习Servlet还要从javax.servlet.Servlet接口开始学习。

    Servlet.java

    public interface Servlet [c1] {

        public void init(ServletConfig config) throws ServletException;

        public ServletConfig getServletConfig();

        public void service(ServletRequest req, ServletResponse res)

                throws ServletException, IOException;

        public String getServletInfo();

        public void destroy();

    }


    Servlet中的方法大多数不由我们来调用,而是由Tomcat来调用。并且Servlet的对象也不由我们来创建,由Tomcat来创建!

    public class AServlet implements Servlet {
    	/*
    	 * 它也是生命周期方法
    	 * 它会在Servlet被销毁之前调用,并且它只会被调用一次!
    	 */
    	@Override
    	public void destroy() {
    		System.out.println("destory()...");
    	}
    
    	/*
    	 * 可以用来获取Servlet的配置信息
    	 */
    	@Override
    	public ServletConfig getServletConfig() {
    		System.out.println("getServletConfig()...");
    		return null;
    	}
    
    	/*
    	 * 获取Servlet的信息
    	 */
    	@Override
    	public String getServletInfo() {
    		System.out.println("getServletInfo()...");
    		return "我是一个快乐的Servlet";
    	}
    
    	/*
    	 * 它是生命周期方法
    	 * 它会在Servlet对象创建之后马上执行,并只执行一次!(出生之后)
    	 * 
    	 */
    	@Override
    	public void init(ServletConfig servletConfig) throws ServletException {
    		System.out.println("init()...");
    		
    		/*
    		 * 获取初始化参数
    		 */
    		System.out.println(servletConfig.getInitParameter("p1"));
    		System.out.println(servletConfig.getInitParameter("p2"));
    		
    		/*
    		 * 获取所有初始化参数的名称
    		 */
    		Enumeration e = servletConfig.getInitParameterNames();
    		while(e.hasMoreElements()) {
    			System.out.println(e.nextElement());
    		}
    	}
    
    	/*
    	 * 它是生命周期方法
    	 * 它会被调用多次!!!
    	 * 每次处理请求都是在调用这个方法!
    	 */
    	@Override
    	public void service(ServletRequest request, ServletResponse response)
    			throws ServletException, IOException {
    		System.out.println("service()...");
    	}
    }
    

      

    生命周期方法:

    l  void init(ServletConfig):出生之后(1次);

    l  void service(ServletRequest request, ServletResponse response):每次处理请求时都会被调用;

    l  void destroy():临死之前(1次);

    特性:

    l  单例,一个类只有一个对象;当然可能存在多个Servlet类!

    l  线程不案例的,所以它的效率是高的!

    Servlet类由我们来写,但对象由服务器来创建,并且由服务器来调用相应的方法。

    GenericServlet

    1 GenericServlet概述

    GenericServlet是Servlet接口的实现类,我们可以通过继承GenericServlet来编写自己的Servlet。下面是GenericServlet类的源代码:

    GenericServlet.java

    public abstract class GenericServlet implements Servlet, ServletConfig,

            java.io.Serializable {

        private static final long serialVersionUID = 1L;

        private transient ServletConfig config;

        public GenericServlet() {}

        @Override

        public void destroy() {}

        @Override

        public String getInitParameter(String name) {

            return getServletConfig().getInitParameter(name);

        }

        @Override

        public Enumeration<String> getInitParameterNames() {

            return getServletConfig().getInitParameterNames();

        }

        @Override

        public ServletConfig getServletConfig() {

            return config;

        }

        @Override

        public ServletContext getServletContext() {

            return getServletConfig().getServletContext();

        }

        @Override

        public String getServletInfo() {

            return "";

        }

        @Override

        public void init[崔1] (ServletConfig config) throws ServletException {

            this.config = config;

            this.init();

        }

        public void init[崔2] () throws ServletException {}

        public void log(String msg) {

            getServletContext().log(getServletName() + ": " + msg);

        }

        public void log(String message, Throwable t) {

            getServletContext().log(getServletName() + ": " + message, t);

        }

        @Override

        public abstract void service(ServletRequest req, ServletResponse res)

                throws ServletException, IOException;

        @Override

        public String getServletName() {

            return config.getServletName();

        }

    }

     

    2 GenericServlet的init()方法

    在GenericServlet中,定义了一个ServletConfig config实例变量,并在init(ServletConfig)方法中把参数ServletConfig赋给了实例变量。然后在该类的很多方法中使用了实例变量config。

    如果子类覆盖了GenericServlet的init(StringConfig)方法,那么this.config=config这一条语句就会被覆盖了,也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。如果真的希望完成一些初始化操作,那么去覆盖GenericServlet提供的init()方法,它是没有参数的init()方法,它会在init(ServletConfig)方法中被调用。

    3 实现了ServletConfig接口

      GenericServlet还实现了ServletConfig接口,所以可以直接调用getInitParameter()、getServletContext()等ServletConfig的方法。


     [崔1]实现了Servlet的init(ServletConfig)方法,把参数config赋给了本类的成员config,然后再调用本类自己的无参的init()方法。

     [崔2]这个方法是GenericServlet自己的方法,而不是从Servlet继承下来的。当我们自定义Servlet时,如果想完成初始化作用就不要再重复init(ServletConfig)方法了,而是应该去重写init()方法。因为在GenericServlet中的init(ServletConfig)方法中保存了ServletConfig对象,如果覆盖了保存ServletConfig的代码,那么就不能再使用ServletConfig了。

    HttpServlet

    1 HttpServlet概述

    HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以通常我们都会通过继承HttpServlet来完成自定义的Servlet。

    2 HttpServlet覆盖了service()方法

    HttpServlet类中提供了service(HttpServletRequest,HttpServletResponse)方法,这个方法是HttpServlet自己的方法,不是从Servlet继承来的。在HttpServlet的service(ServletRequest,ServletResponse)方法中会把ServletRequest和ServletResponse强转成HttpServletRequest和HttpServletResponse,然后调用service(HttpServletRequest,HttpServletResponse)方法,这说明子类可以去覆盖service(HttpServletRequest,HttpServletResponse)方法即可,这就不用自己去强转请求和响应对象了。

    其实子类也不用去覆盖service(HttpServletRequest,HttpServletResponse)方法,因为HttpServlet还要做另一步简化操作,下面会介绍。

    HttpServlet.java

    public abstract class HttpServlet extends GenericServlet {

        protected void service(HttpServletRequest req, HttpServletResponse resp)

            throws ServletException, IOException {

            ……

    }

        @Override

        public void service(ServletRequest req, ServletResponse res)

            throws ServletException, IOException {

     

            HttpServletRequest  request;

            HttpServletResponse response;

     

            try {

                request = (HttpServletRequest) req;

                response = (HttpServletResponse) res;

    [崔1]         } catch (ClassCastException e) {

                throw new ServletException("non-HTTP request or response");

            }

            service(request, response);[崔2] 

    }

    ……

    }

     

    3 doGet()和doPost()

    在HttpServlet的service(HttpServletRequest,HttpServletResponse)方法会去判断当前请求是GET还是POST,如果是GET请求,那么会去调用本类的doGet()方法,如果是POST请求会去调用doPost()方法,这说明我们在子类中去覆盖doGet()或doPost()方法即可。

    public class AServlet extends HttpServlet {

        public void doGet(HttpServletRequest request, HttpServletResponse response)

               throws ServletException, IOException {

           System.out.println("hello doGet()...");

        }

    }

    public class BServlet extends HttpServlet {

        public void doPost(HttpServletRequest request, HttpServletResponse response)

               throws ServletException, IOException {

           System.out.println("hello doPost()...");

        }

    }


     [崔1]强转

     [崔2]调用上面service()方法

    Servlet细节

    l  不要在Servlet中创建成员!创建局部变量即可!

    l  可以创建无状态成员!

    l  可以创建有状态的成员,但状态必须为只读的!

    1 Servlet与线程安全

    因为一个类型的Servlet只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求,那么Servlet是否为线程安全的呢?答案是:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!

    所以我们不应该在Servlet中便宜创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。

    2 让服务器在启动时就创建Servlet

    默认情况下,服务器会在某个Servlet第一次收到请求时创建它。也可以在web.xml中对Servlet进行配置,使服务器启动时就创建Servlet。

        <servlet>

           <servlet-name>hello1</servlet-name>

           <servlet-class>cn.itcast.servlet.Hello1Servlet</servlet-class>

           <load-on-startup>0</load-on-startup>[c1] 

        </servlet>

        <servlet-mapping>

           <servlet-name>hello1</servlet-name>

           <url-pattern>/hello1</url-pattern>

        </servlet-mapping>

        <servlet>

           <servlet-name>hello2</servlet-name>

           <servlet-class>cn.itcast.servlet.Hello2Servlet</servlet-class>

           <load-on-startup>1</load-on-startup>

        </servlet>

        <servlet-mapping>

           <servlet-name>hello2</servlet-name>

           <url-pattern>/hello2</url-pattern>

        </servlet-mapping>

        <servlet>

           <servlet-name>hello3</servlet-name>

           <servlet-class>cn.itcast.servlet.Hello3Servlet</servlet-class>

           <load-on-startup>2</load-on-startup>

        </servlet>

        <servlet-mapping>

           <servlet-name>hello3</servlet-name>

           <url-pattern>/hello3</url-pattern>

        </servlet-mapping>

    在<servlet>元素中配置<load-on-startup>元素可以让服务器在启动时就创建该Servlet,其中<load-on-startup>元素的值必须是大于等于的整数,它的使用是服务器启动时创建Servlet的顺序。上例中,根据<load-on-startup>的值可以得知服务器创建Servlet的顺序为Hello1Servlet、Hello2Servlet、Hello3Servlet。


     [c1]在<servlet>中配置<load-on-startup>,其中给出一个非负整数!

  • 相关阅读:
    zookeeper.KeeperException$UnimplementedException: KeeperErrorCode = Unimplemented for {root.path}
    IDEA对新建java线程池的建议
    Hbase配置WEB UI界面
    Tomcat清理日志文件无法立即释放磁盘空间
    Tomcat多应用启动报错:org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [].
    Soliworks 2016建模细节总结(1)
    关于自学C语言开始时应该注意的问题分享—未完待续......
    Word或者WPS里证件照的背景底色和像素调整
    Linux命令大全(非常全,史上最全)
    Android项目结构介绍
  • 原文地址:https://www.cnblogs.com/eadela/p/11310027.html
Copyright © 2011-2022 走看看