您的位置:首页 > 运维架构 > Tomcat

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

2012-10-09 22:50 351 查看
我们编写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实现方式可能不同,但都遵守那些规范。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: