循循渐进的GenericServlet

在做web开发时,创建自己的servlet时,通常需要实现javax.servlet.Servlet接口,并覆写Servlet所有的方法,例如:
import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class DemoServlet implements Servlet{

	public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	public ServletConfig getServletConfig() {
		// TODO Auto-generated method stub
		return null;
	}

	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		
	}

	public String getServletInfo() {
		// TODO Auto-generated method stub
		return null;
	}

	public void destroy() {
		// TODO Auto-generated method stub
		
	}
}
但是,如果需要自定义很多个servlet,而每个servlet都必须覆写javax.servlet.Servlet的五个方法,况且有些方法只是简单的覆盖了一下,根本没用实际用到,这样在开发servlet时就显得很繁琐,是不是可以简化开发呢?于是想到,定义一个GenericServlet类,这个类实现javax.servlet.Servlet接口,而自定义的servlet自需要继承抽象类即可。由于每个自定义的servlet需要处理service(ServletRequest , ServletResponse)的逻辑不一样,所以就让GenericServlet为抽象类,把service(ServletRequest , ServletResponse)抽象出来。如下:
import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract class GenericServlet implements Servlet {

	public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub

	}

	public ServletConfig getServletConfig() {
		// TODO Auto-generated method stub
		return null;
	}

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

	public String getServletInfo() {
		// TODO Auto-generated method stub
		return null;
	}

	public void destroy() {
		// TODO Auto-generated method stub

	}

}
而对于刚才DemoServlet,便可以如下定义:
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class DemoServlet extends GenericServlet {

	@Override
	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("DemoServlet 的 service() 逻辑处理。");
	}

}
但是可能自定的DemoServlet在实例化后需要额外做一些自己的init。于是需要这样做:
import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class DemoServlet extends GenericServlet {
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub
		System.out.println("DemoServlet 的 init() 逻辑处理。");
	}

	@Override
	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("DemoServlet 的 service() 逻辑处理。");
	}

}
现在又有新的功能,需要DemoServlet能获取ServletConfig的参数信息,类似javax.servlet. ServletConfig接口的getServletName()、getServletContext()等方法,于是采用这样的方式:
import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class DemoServlet extends GenericServlet {
	private ServletConfig config;

	@Override
	public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub
		this.config = config;
		System.out.println("DemoServlet 的 init() 逻辑处理。");
	}

	@Override
	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("DemoServlet 的 service() 逻辑处理。");
	}

	public String getInitParameter(String name) {
		return config.getInitParameter(name);
	}

	public Enumeration getInitParameterNames() {
		return config.getInitParameterNames();
	}

	public ServletContext getServletContext() {
		return config.getServletContext();
	}

	public String getServletName() {
		return config.getServletName();
	}
}
更显然一点:
public class DemoServlet extends GenericServlet implements ServletConfig{
就是覆写了ServletConfig的方法,那么如果自定义很多servlet,开发又显得复杂起来了,于是想到让GenericServlet也实现ServletConfig接口,与是就有了如下的改进:
import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract class GenericServlet implements Servlet, ServletConfig {

	private ServletConfig config;

	public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub
		this.config = config;
	}

	public ServletConfig getServletConfig() {
		// TODO Auto-generated method stub
		return this.config;
	}

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

	public String getServletInfo() {
		// TODO Auto-generated method stub
		return null;
	}

	public void destroy() {
		// TODO Auto-generated method stub

	}

	public String getServletName() {
		// TODO Auto-generated method stub
		return getServletConfig().getServletName();
	}

	public ServletContext getServletContext() {
		// TODO Auto-generated method stub
		return getServletConfig().getServletContext();
	}

	public String getInitParameter(String name) {
		// TODO Auto-generated method stub
		return getServletConfig().getInitParameter(name);
	}

	public Enumeration getInitParameterNames() {
		// TODO Auto-generated method stub
		return getServletConfig().getInitParameterNames();
	}

}
这样,就ok了。但是作为GenericServlet的子类DemoServlet,如果要覆写init(ServletConfig config),必须要这样做:
@Override
public void init(ServletConfig config) throws ServletException {
	// TODO Auto-generated method stub
	super.init(config);
	System.out.println("DemoServlet 的 init() 逻辑处理。");
}

不然,GenericServlet就无法缓存config,就会出NullPointerException。这样,又会让编程人员在编码时需要额外注意这一个坑,有木有好的解决方法呢?答案是肯定的。
针对GenericServlet采取这样的方式:
public void init(ServletConfig config) throws ServletException {
	// TODO Auto-generated method stub
	this.config = config;
	init();
}

public void init(){
	
}
如果子类需要做自己的init,只需要覆写init()就可以:
@Override
public void init() {
	// TODO Auto-generated method stub
	System.out.println("DemoServlet 的 init() 逻辑处理。");
}

只是一个值得学习的设计思路。


下面附上javax.servlet.GenericServlet的源码,以便好好琢磨琢磨:

package javax.servlet;

import java.io.IOException;
import java.util.Enumeration;



public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {

    private transient ServletConfig config;
    
    public GenericServlet() { }
    
    public void destroy() {
    }
    
    public String getInitParameter(String name) {
	return getServletConfig().getInitParameter(name);
    }
    
    public Enumeration getInitParameterNames() {
	return getServletConfig().getInitParameterNames();
    }      
    
    public ServletConfig getServletConfig() {
	return config;
    }   

    public ServletContext getServletContext() {
	return getServletConfig().getServletContext();
    }
 
    public String getServletInfo() {
	return "";
    }

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

    }
         
    public void log(String msg) {
	getServletContext().log(getServletName() + ": "+ msg);
    }
      
    public void log(String message, Throwable t) {
	getServletContext().log(getServletName() + ": " + message, t);
    }

    public abstract void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
    
    public String getServletName() {
        return config.getServletName();
    }
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值