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

我们编写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实现方式可能不同,但都遵守那些规范。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值