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