[Tomcat6.0源码]Servlet API之ServletConfig、ServletContext

来源:互联网 发布:在党规党纪面前知敬畏 编辑:程序博客网 时间:2024/05/18 05:56

我们编写Servlet类的时候,都继承自HttpServlet。而HttpServlet又继承了GenericServlet类,实现了Servlet、ServletConfig接口。

(图片来自http://getmc.blog.bokee.net/bloggermodule/blog_viewblog.do?id=57343)

在写doPost()、doGet()的时候,ServletConfig、ServletContext等内置对象比较常用:

1.GenericServlet.getServletConfig()返回ServletConfig对象:

    public ServletConfig getServletConfig() {return config;    }

而这个config是Servlet初始化时候设置的,StandardWrapper.loadServlet():

servlet.init(facade);

这个facade是在StandardWrapper属性中new出来的:

    protected StandardWrapperFacade facade =        new StandardWrapperFacade(this);

StandardWrapperFacade是实现了ServletConfig接口。它是对StandardWrapper类的封装:

public final class StandardWrapperFacade    implements ServletConfig {    // ----------------------------------------------------------- Constructors    /**     * Create a new facede around a StandardWrapper.     */    public StandardWrapperFacade(StandardWrapper config) {        super();        this.config = (ServletConfig) config;    }    // ----------------------------------------------------- Instance Variables    /**     * Wrapped config.     */    private ServletConfig config = null;    /**     * Wrapped context (facade).     */    private ServletContext context = null;    // -------------------------------------------------- ServletConfig Methods    public String getServletName() {        return config.getServletName();    }    public ServletContext getServletContext() {        if (context == null) {            context = config.getServletContext();            if ((context != null) && (context instanceof ApplicationContext))                context = ((ApplicationContext) context).getFacade();        }        return (context);    }    public String getInitParameter(String name) {        return config.getInitParameter(name);    }    public Enumeration getInitParameterNames() {        return config.getInitParameterNames();    }}

StandardWrapper的属性方法很多,有些是不能让tomcat用户直接访问的。而有些是可以对他们开放的。所以就有了这么个Facade。

getInitParameter()调用的是StandardWrapper.getInitParameter():

    public String getInitParameter(String name) {        return (findInitParameter(name));    }

StandardWrapper.findInitParameter():

    public String findInitParameter(String name) {        try {            parametersLock.readLock().lock();            return ((String) parameters.get(name));        } finally {            parametersLock.readLock().unlock();        }    }

StandardWrapper.parameters是HashMap类型,来自StandardWrapper.addInitParameter():

    public void addInitParameter(String name, String value) {        try {            parametersLock.writeLock().lock();            parameters.put(name, value);        } finally {            parametersLock.writeLock().unlock();        }        fireContainerEvent("addInitParameter", name);    }

这个方法的调用是在StandardContext解析web.xml的时候(WebRuleSet里配置的)

        digester.addCallMethod(prefix + "web-app/filter/init-param",                               "addInitParameter", 2);        digester.addCallParam(prefix + "web-app/filter/init-param/param-name",                              0);        digester.addCallParam(prefix + "web-app/filter/init-param/param-value",                              1);


另外,结构图中有两个方法:GenericServlet.getInitParameter(),调用的还是StandardWrapperFacade.getInitParameter();

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

GenericServlet.getInitParameterNames()调用的是StandardWrapperFacade.getInitParameterNames()。

 

2.ServletContext来自GenericServlet.getServletContext(),调用的是StandardWrapperFacade.getServletContext():

    public ServletContext getServletContext() {        if (context == null) {            context = config.getServletContext();            if ((context != null) && (context instanceof ApplicationContext))                context = ((ApplicationContext) context).getFacade();        }        return (context);    }

StandardWrapperFacade中的config是StandardWrapper对象。将调用StandardWrapper.getServletContext():

    public ServletContext getServletContext() {        if (parent == null)            return (null);        else if (!(parent instanceof Context))            return (null);        else            return (((Context) parent).getServletContext());    }

StandardContext.getServletContext():

    public ServletContext getServletContext() {        if (context == null) {            context = new ApplicationContext(getBasePath(), this);            if (altDDName != null)                context.setAttribute(Globals.ALT_DD_ATTR,altDDName);        }        return (context.getFacade());    }

context.getFacade()即ApplicationContext.getFacade():

    protected ServletContext getFacade() {        return (this.facade);    }

facade来自ApplicationContext的属性:

    private ServletContext facade = new ApplicationContextFacade(this);

ServletContext有个方法getInitParameter():

    public String getInitParameter(String name) {        if (SecurityUtil.isPackageProtectionEnabled()) {            return (String) doPrivileged("getInitParameter",                                          new Object[]{name});        } else {            return context.getInitParameter(name);        }    }
context.getInitParameter()调用的是ApplicationContext.getInitParameter():

    public String getInitParameter(final String name) {        return parameters.get(name);    }

parameters是ConcurrentHashMap类型的对象,在ApplicationContext属性中new出来的,往里边设值是用setInitParameter()方法:

    public boolean setInitParameter(String name, String value) {        if (parameters.containsKey(name)) {            return false;        }                parameters.put(name, value);        return true;    }

里边的值是StandardContext.start()时调用mergeParameters()方法,逐个往里边放值:

    private void mergeParameters() {        Map<String,String> mergedParams = new HashMap<String,String>();                String names[] = findParameters();        for (int i = 0; i < names.length; i++) {            mergedParams.put(names[i], findParameter(names[i]));        }        ApplicationParameter params[] = findApplicationParameters();        for (int i = 0; i < params.length; i++) {            if (params[i].getOverride()) {                if (mergedParams.get(params[i].getName()) == null) {                    mergedParams.put(params[i].getName(),                            params[i].getValue());                }            } else {                mergedParams.put(params[i].getName(), params[i].getValue());            }        }                for (Map.Entry<String,String> entry : mergedParams.entrySet()) {            context.setInitParameter(entry.getKey(), entry.getValue());        }    }
findParameters()是将HashMap类型的parameters转成String数组。parameters是来自WebRuleSet中配置的规则:

        digester.addCallMethod(prefix + "web-app/context-param",                               "addParameter", 2);        digester.addCallParam(prefix + "web-app/context-param/param-name", 0);        digester.addCallParam(prefix + "web-app/context-param/param-value", 1);
findApplicationParameters()返回的是ApplicationParameter类型的数组applicationParameters。applicationParameters来自Catalina解析server.xml

        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
ContextRuleSet:

        digester.addObjectCreate(prefix + "Context/Parameter",                                 "org.apache.catalina.deploy.ApplicationParameter");        digester.addSetProperties(prefix + "Context/Parameter");        digester.addSetNext(prefix + "Context/Parameter",                            "addApplicationParameter",                            "org.apache.catalina.deploy.ApplicationParameter");

捋捋:

ServletConfig和ServletContext对象都有setAttribute和getAttribute方法。

论作用域,ServletConfig是封装了一些StandardWrapper方法的StandardWrapperFacade对象,StandardWrapper又是对servlet的封装。所以保存ServletConfig中的参数,在在该servlet生命周期内有用,其他servlet访问不到这里的数据。

ServletContext是ApplicationContextFacade对象,他是对ApplicationContext的封装,而ApplicationContext又是对StandardContext的封装。同一个应用的servlet都可以访问这个ServletContext的参数。


另外,Servlet API只是一个规范,相关的方法名及实现的功能是大家定的,而里边具体怎么实现,就由个个厂家自己发挥了。jboss、weblogic、tomcat实现方式可能不同,但都遵守那些规范。