专栏首页eadelaservlet反射、生命周期、接口

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>,其中给出一个非负整数!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • web.xml配置  关于web.xml配置中的<url-pattern>

      在${CATALINA_HOME}\conf\web.xml中的内容,相当于写到了每个项目的web.xml中,它是所有web.xml的父文件。

    eadela
  • docker--镜像操作

    Docker 镜像是容器的基础。镜像是一个有序集合,其中包含根文件系统更改和在容器运 行时中使用的相应执行参数。镜像通常 包含堆叠在彼此之上的联合分层文件系统。...

    eadela
  • oracle--用户区别sys和system

    2.如果在同一主机上使用IPC连接到数据库使用操作系统授权,登录任何一个用户都可以拥有as sysdba和as sysoper。

    eadela
  • 如何站在使用者的角度来设计SDK-微信公众号开发SDK(消息处理)设计之抛砖引玉

    0.SDK之必备的基本素质 在项目中免不了要用到各种各样的第三方的sdk,在我现在的工作中就在公司内部积累了各种各样的的公共库(基于.net的,基于silver...

    blackheart
  • Java-策略设计模式

    今天 我们来学习一下策略模式,什么是策略模式呢?比如我们一个功能的实现可以有多个策略去选择,比如:出行方式可以选择:共享单车,拼车,私家车,出租等。如果将这个出...

    android_薛之涛
  • 面试官亲述:如何利用设计模式改善业务代码

    在业务部门的开发中,大多数的我们在完成的业务的各种需求和提供解决方案,很多场景下的我们通过 CRUD 就能解决问题,但是这样的工作对技术人的提升并不多,如何让自...

    程序员白楠楠
  • Java开源框架中的设计模式以及应用场景

    设计模式是软件设计中常见问题的典型解决方案,你可以通过对其进行定制来解决代码中的特定设计问题。

    猿天地
  • 让IoC动态解析自定义配置(提供基于Unity的实现)

    在《通过自定义配置实现插件式设计》中,通过在运行时对配置的动态解析实现了真正的“插件式”设计,其本质就是让配置自行提供对配置类型实例的创建。在这篇文章中,我们将...

    蒋金楠
  • Java面向对象之抽象类,接口

    抽象类: 含有抽象方法的类被声明为抽象类 抽象方法由子类去实现 含有抽象方法的类必须被声明为抽象类 抽象类被子类继承,子类(如果不是抽象类)必须重写抽象类中...

    二十三年蝉
  • 谈谈WCF中的Data Contract(2):WCF Data Contract对Generic的支持

    通过第一部分的介绍,我们可以体会到,WCF 的Data Contract在CLR Type和Neutral Contract之间搭建了一座桥梁,弥合了.NET世...

    蒋金楠

扫码关注云+社区

领取腾讯云代金券