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。这样,又会让编程人员在编码时需要额外注意这一个坑,有木有好的解决方法呢?答案是肯定的。
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(); } }