一. FrameworkServlet
Spring的Web框架的基础servlet。提供了一个Spring应用程序上下文的集成,以一种基于JavaBean的方式。
这个类提供了如下功能:
1. 为每个servlet管理WebApplicationContext实例。Servlet的配置由servlet的命名空间的beans决定。在处理请求的时候,无论请求有没有被成功处理,都会发布事件。
2. 子类必须实现doService方法去处理请求。因为这个直接集成HttpServletBean,而不是HttpServlet,bean属性自动映射到它里面。子类可以重写initFrameworkServlet方法用于自定义初始化。
3. 在servlet的“init-param”中找到 “contextClass”参数 ,作为默认的上下文类。默认的是XmlWebApplicationContext。一个自定义的context class需要实现ConfigurableWebApplicationContext。
4. 接受一个可选择的"contextInitializerClasses" 在 “init-param”中,去指定一个或者多个ApplicationContextInitializer类。Web Application Context委派这些初始化器,允许有额外的编程式的配置。
5. 将"contextConfigLocation"的"init-param"传递给上下文实例,使用逗号和空格分离不同的文件路径。如果没有明确指定,上下文的实现类会从servlet的命名空间建立一个默认的位置。
6. 默认的命名空间是 ‘servlet-name’-servlet,(/WEB-INF/'servlet-name'-servlet.xml)。命名空间可以在servlet的"init-param"中去指定。
7. 在3.1中,FrameworkServlet可以用一个web application context注入,而不是内部创建。
现在来看下FrameworkServlet这个类。
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
首先它是个抽象类,然后有一个ApplicationContextAware接口。
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
public interface Aware {
}
然后看下它的成员变量,如下:
/**
* web application context的命名空间前缀
*
*/
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
/**
* FrameworkServlet默认的上下文类
*/
public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
/**
* WebApplicationContext的ServletContext属性的前缀
*/
public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";
/**
* init-param的分隔符
*/
private static final String INIT_PARAM_DELIMITERS = ",; \t\n";
/** ServletContext attribute to find the WebApplicationContext in. */
@Nullable
private String contextAttribute;
/** WebApplicationContext implementation class to create. */
private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
/** WebApplicationContext id to assign. */
@Nullable
private String contextId;
/** Namespace for this servlet. */
@Nullable
private String namespace;
/** Explicit context config location. */
@Nullable
private String contextConfigLocation;
/** Actual ApplicationContextInitializer instances to apply to the context. */
private final List<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =
new ArrayList<>();
/** Comma-delimited ApplicationContextInitializer class names set through init param. */
@Nullable
private String contextInitializerClasses;
/** Should we publish the context as a ServletContext attribute?. */
private boolean publishContext = true;
/** Should we publish a ServletRequestHandledEvent at the end of each request?. */
private boolean publishEvents = true;
/** Expose LocaleContext and RequestAttributes as inheritable for child threads?. */
private boolean threadContextInheritable = false;
/** Should we dispatch an HTTP OPTIONS request to {@link #doService}?. */
private boolean dispatchOptionsRequest = false;
/** Should we dispatch an HTTP TRACE request to {@link #doService}?. */
private boolean dispatchTraceRequest = false;
/** Whether to log potentially sensitive info (request params at DEBUG + headers at TRACE). */
private boolean enableLoggingRequestDetails = false;
/** 这个servlet的WebApplicationContext */
@Nullable
private WebApplicationContext webApplicationContext;
/** If the WebApplicationContext was injected via {@link #setApplicationContext}. */
private boolean webApplicationContextInjected = false;
/** onRefresh是否已经被调用 */
private volatile boolean refreshEventReceived = false;
/** 管理同步onRefresh执行. */
private final Object onRefreshMonitor = new Object();
然后构造器:
public FrameworkServlet() {
}
public FrameworkServlet(WebApplicationContext webApplicationContext) {
this.webApplicationContext = webApplicationContext;
}
最后看下它的方法(setter、getter方法这里不讨论)
/**
* 在任何bean属性设置后被调用。创建webapplicationcontext
*/
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}