您的位置:首页 > 编程语言 > Java开发

SpringMVC源码分析--容器初始化(四)FrameworkServlet

2017-03-01 13:52 405 查看
本文为转载,地址:http://blog.csdn.NET/qq924862077/

在上一篇博客SpringMVC源码分析--容器初始化(三)HttpServletBean我们介绍了HttpServletBean的init函数,其主要作用是初始化了一下SpringMVC配置文件的地址contextConfigLocation的配置属性,然后其调用的子类FrameworkServlet的initServletBean方法。

其实FrameworkServlet是springMVC初始化IOC容器的核心,通过读取配置的contextConfigLocation配置的springMVC配置文件的地址来读取各种初始化信息和Bean注入信息,来完成springMVC IOC 容器的初始化。接下来我们通过源码一步一步进行分析。

首先我们看initServletBean函数方法,其主要的操作就是this.webApplicationContext = initWebApplicationContext()完成webApplicationContext的初始化,webApplicationContext 即为springMVC的IOC容器,其实现类是XMLWebApplicationContext,

这样我们发现,初始化工作在initWebApplicationContext函数方法中。

[java] view
plain copy

print?





//创建springMVC的IOC容器

@Override

protected final void initServletBean() throws ServletException {

getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");

if (this.logger.isInfoEnabled()) {

this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");

}

long startTime = System.currentTimeMillis();

try {

//创建springMVC的IOC容器

this.webApplicationContext = initWebApplicationContext();

//没有任何具体实现

initFrameworkServlet();

}

catch (ServletException ex) {

this.logger.error("Context initialization failed", ex);

throw ex;

}

catch (RuntimeException ex) {

this.logger.error("Context initialization failed", ex);

throw ex;

}

if (this.logger.isInfoEnabled()) {

long elapsedTime = System.currentTimeMillis() - startTime;

this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +

elapsedTime + " ms");

}

}

initWebApplicationContext函数方法是整个springMVC IOC实现的实现过程,函数代码段如下,

WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext())是从ServletContext中获取IOC容器,因为我们知道spring web在初始化时会将初始化的webApplicationContex保存到ServletContext中,这样我们就可以获取到spring
web容器了,并且把它作为父容器。

if (this.webApplicationContext != null) 当容器已经存在时,我们就不需要重新创建,只需要刷新一下,将springMVC配置文件中的属性加载到webApplicationContext中就可以了,当不存在时我们就需要一步一步的创建webApplicationContext了。

wac = findWebApplicationContext()在ServletContext中查找WebApplicationContext,说不定它已经被存放到ServletContext中去了。

如果没有我们就需要创建wac = createWebApplicationContext(rootContext),这个步骤我们会接下来分析,创建完之后我们调用onRefresh(wac),这个方法在子类DispatcherServlet中实现,去初始化一些其他操作,现在已经完成了webApplicationContext的初始化工作了接下来就需要把webApplicationContext存放到ServletContext中去了getServletContext().setAttribute(attrName,
wac),最后调用return wac完成springMVC IOC容器的初始化。

[java] view
plain copy

print?





/**

*初始化和发布web应用上下文,封装了建立Spring容器上下文的整个过程

*

*/

protected WebApplicationContext initWebApplicationContext() {

//获取由ContextLoaderListener初始化并注册在ServletContext中的根上下文,一般是Spring的IOC容器记为rootContext

WebApplicationContext rootContext =

WebApplicationContextUtils.getWebApplicationContext(getServletContext());

WebApplicationContext wac = null;

//如果webApplicationContext已经不为空,表示这个Servlet类是通过编程式注册到容器中的(Servlet 3.0 +中的ServletContext.addServlet()),

//上下文也由编程式传入。若这个传入的上下文还没有被初始化,将rootContext上下文设置为它的父上下文,然后将其初始化,否则直接使用。

if (this.webApplicationContext != null) {

// A context instance was injected at construction time -> use it

wac = this.webApplicationContext;

if (wac instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// The context instance was injected without an explicit parent -> set

// the root application context (if any; may be null) as the parent

cwac.setParent(rootContext);

}

configureAndRefreshWebApplicationContext(cwac);

}

}

}

//判断wac是否为空判断是否已经完成上面的上下文的设置

if (wac == null) {

// No context instance was injected at construction time -> see if one

// has been registered in the servlet context. If one exists, it is assumed

// that the parent context (if any) has already been set and that the

// user has performed any initialization such as setting the context id

//如果为空,说明该Servlet不是由编程式注册到容器中的,在ServletContext中查找上下文,查找得到

//说明上下文已经以别的方式初始化并注册在contextAttribute下,直接使用

wac = findWebApplicationContext();

}

if (wac == null) {

// No context instance is defined for this servlet -> create a local one

//此时还为空,调用以下方法创建一个全新的以rootContext为父上下文的上下文,作为SpringMVC配置元素的上下文

//大多数情况下我们所使用的上下文就是这个新建的上下文

wac = createWebApplicationContext(rootContext);

}

if (!this.refreshEventReceived) {

// Either the context is not a ConfigurableApplicationContext with refresh

// support or the context injected at construction time had already been

// refreshed -> trigger initial onRefresh manually here.

//在DispatcherServlet中复写,会初始化一系列属性

onRefresh(wac);

}

if (this.publishContext) {

// Publish the context as a servlet context attribute.

//将这个上下文发布到ServletContext中,也就是将上下文以一个和Servlet类在web.xml中注册名字有关的值为键

//设置为ServletContext的一个属性

String attrName = getServletContextAttributeName();

getServletContext().setAttribute(attrName, wac);

if (this.logger.isDebugEnabled()) {

this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +

"' as ServletContext attribute with name [" + attrName + "]");

}

}

return wac;

}

上面我们介绍了springMVC IOC容器的初始化操作,但很多具体操作是在其他函数中完成的,接下来我们一一分析,

findWebApplicationContext函数是从ServletContext中查找webApplicationContext,springMVC初始化完成之后我们会看到它会将webApplicationContext保存到ServletContext中,这样我们可以在ServletContext中获取到它。

[java] view
plain copy

print?





//从当前容器中查找SpringMVC的IOC容器

protected WebApplicationContext findWebApplicationContext() {

String attrName = getContextAttribute();

if (attrName == null) {

return null;

}

WebApplicationContext wac =

WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);

if (wac == null) {

throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");

}

return wac;

}

在上面介绍中我们并没有真正介绍到webApplicationContext初始化的完整过程,其完整实现是在createWebApplicationContext函数中,其首先会实例化一个IOC容器,这只是一个空容器,并没有相关属性wac =(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

接下来的操作就是对wac设置相关属性

wac.setEnvironment(getEnvironment())设置环境

wac.setParent(parent)设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起

wac.setConfigLocation(getContextConfigLocation())设置web.xml中的springMVC的配置文件,各种bean的注入

configureAndRefreshWebApplicationContext(wac),这个函数是关键,是解析springMVC配置文件完成初始化的过程。

return wac返回已经初始化的webApplicationContext

[java] view
plain copy

print?





//创建springMVC的IOC容器,

rotected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {

//获取类XMLWebApplicationContext

Class<?> contextClass = getContextClass();

if (this.logger.isDebugEnabled()) {

this.logger.debug("Servlet with name '" + getServletName() +

"' will try to create custom WebApplicationContext context of class '" +

contextClass.getName() + "'" + ", using parent context [" + parent + "]");

}

if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {

throw new ApplicationContextException(

"Fatal initialization error in servlet with name '" + getServletName() +

"': custom WebApplicationContext class [" + contextClass.getName() +

"] is not of type ConfigurableWebApplicationContext");

}

//实例化一个IOC容器

ConfigurableWebApplicationContext wac =

(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

//设置IOC容器相关的属性,这样springMVC的IOC容器就创建好了

wac.setEnvironment(getEnvironment());

//设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起

wac.setParent(parent);

//设置web.xml中的springMVC的配置文件,各种bean的注入

wac.setConfigLocation(getContextConfigLocation());

//初始化springMVC各种的相关配置,各种注入的Controller,配置文件等

configureAndRefreshWebApplicationContext(wac);

return wac;

上面我们介绍到configureAndRefreshWebApplicationContext函数是完成springMVC配置文件初始化过程的函数,其实它也是比较简单的,也是设置springMVC IOC容器的相关属性,

最终调用wac.refresh(),通过AbstractApplicationContext来完成对springMVC xml配置文件的解析初始化操作,这边我们就不再深入探究,在spring IOC容器初始化时我们再详细介绍。

[java] view
plain copy

print?





/*配置或者刷新应用上下文*/

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

if (ObjectUtils.identityToString(wac).equals(wac.getId())) {

// The application context id is still set to its original default value

// -> assign a more useful id based on available information

if (this.contextId != null) {

wac.setId(this.contextId);

}

else {

// Generate default id...

wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +

ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());

}

}

//设置springMVC IOC容器的相关属性

wac.setServletContext(getServletContext());

wac.setServletConfig(getServletConfig());

wac.setNamespace(getNamespace());

wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

// The wac environment's #initPropertySources will be called in any case when the context

// is refreshed; do it eagerly here to ensure servlet property sources are in place for

// use in any post-processing or initialization that occurs below prior to #refresh

ConfigurableEnvironment env = wac.getEnvironment();

if (env instanceof ConfigurableWebEnvironment) {

((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());

}

postProcessWebApplicationContext(wac);

applyInitializers(wac);

//初始化springMVC各种的相关配置,各种注入的Controller,配置文件等

wac.refresh();

}

通过以上函数的操作就完成了springMVC IOC容器的初始化操作,并且把spring web初始化的IOC容器作为父容器,这样springMVC就可以获得父容器中注入的各种Bean,同时初始化的IOC容器webApplicationContext也会被存放到ServletContex中,这样在整个的web容器中都可以得到并使用IOC容器中的各种属性。

FrameworkServlet完整源码解析:

[java] view
plain copy

print?





//FrameworkServlet类的设计目的就是用来建立一个和Servlet关联的Spring容器上下文

//并将其注册到ServletContext中,跳脱开SpringMVC体系,我们也能通过继承FrameworkServlet类

//得到与Spring容器整合的好处,FrameworkServlet和HttpServletBean一样,是一个可以独立使用的类

@SuppressWarnings("serial")

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

//servlet命名空间前缀

public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";

//FrameworkServlet类的上下文

public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;

public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";

private static final String INIT_PARAM_DELIMITERS = ",; \t\n";

private static final boolean responseGetStatusAvailable =

ClassUtils.hasMethod(HttpServletResponse.class, "getStatus");

private String contextAttribute;

private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;

private String contextId;

private String namespace;

// web.xml中配置的contextConfigLocation属性,就是springMVC的配置文件

private String contextConfigLocation;

/** Actual ApplicationContextInitializer instances to apply to the context */

private final List<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =

new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();

/** Comma-delimited ApplicationContextInitializer class names set through init param */

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;

/** WebApplicationContext for this servlet */

private WebApplicationContext webApplicationContext;

/** If the WebApplicationContext was injected via {@link #setApplicationContext} */

private boolean webApplicationContextInjected = false;

/** Flag used to detect whether onRefresh has already been called */

private boolean refreshEventReceived = false;

public FrameworkServlet() {

}

public FrameworkServlet(WebApplicationContext webApplicationContext) {

this.webApplicationContext = webApplicationContext;

}

public void setContextAttribute(String contextAttribute) {

this.contextAttribute = contextAttribute;

}

public String getContextAttribute() {

return this.contextAttribute;

}

public void setContextClass(Class<?> contextClass) {

this.contextClass = contextClass;

}

public Class<?> getContextClass() {

return this.contextClass;

}

public void setContextId(String contextId) {

this.contextId = contextId;

}

public String getContextId() {

return this.contextId;

}

public void setNamespace(String namespace) {

this.namespace = namespace;

}

public String getNamespace() {

return (this.namespace != null ? this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);

}

//web.xml中配置文件的地址

public void setContextConfigLocation(String contextConfigLocation) {

this.contextConfigLocation = contextConfigLocation;

}

public String getContextConfigLocation() {

return this.contextConfigLocation;

}

@SuppressWarnings("unchecked")

public void setContextInitializers(ApplicationContextInitializer<?>... initializers) {

if (initializers != null) {

for (ApplicationContextInitializer<?> initializer : initializers) {

this.contextInitializers.add((ApplicationContextInitializer<ConfigurableApplicationContext>) initializer);

}

}

}

public void setContextInitializerClasses(String contextInitializerClasses) {

this.contextInitializerClasses = contextInitializerClasses;

}

public void setPublishContext(boolean publishContext) {

this.publishContext = publishContext;

}

public void setPublishEvents(boolean publishEvents) {

this.publishEvents = publishEvents;

}

public void setThreadContextInheritable(boolean threadContextInheritable) {

this.threadContextInheritable = threadContextInheritable;

}

public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {

this.dispatchOptionsRequest = dispatchOptionsRequest;

}

public void setDispatchTraceRequest(boolean dispatchTraceRequest) {

this.dispatchTraceRequest = dispatchTraceRequest;

}

@Override

public void setApplicationContext(ApplicationContext applicationContext) {

if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {

this.webApplicationContext = (WebApplicationContext) applicationContext;

this.webApplicationContextInjected = true;

}

}

//创建springMVC的IOC容器

@Override

protected final void initServletBean() throws ServletException {

getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");

if (this.logger.isInfoEnabled()) {

this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");

}

long startTime = System.currentTimeMillis();

try {

//创建springMVC的IOC容器

this.webApplicationContext = initWebApplicationContext();

//没有任何具体实现

initFrameworkServlet();

}

catch (ServletException ex) {

this.logger.error("Context initialization failed", ex);

throw ex;

}

catch (RuntimeException ex) {

this.logger.error("Context initialization failed", ex);

throw ex;

}

if (this.logger.isInfoEnabled()) {

long elapsedTime = System.currentTimeMillis() - startTime;

this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +

elapsedTime + " ms");

}

}

/**

*初始化和发布web应用上下文,封装了建立Spring容器上下文的整个过程

*

*/

protected WebApplicationContext initWebApplicationContext() {

//获取由ContextLoaderListener初始化并注册在ServletContext中的根上下文,一般是Spring的IOC容器记为rootContext

WebApplicationContext rootContext =

WebApplicationContextUtils.getWebApplicationContext(getServletContext());

WebApplicationContext wac = null;

//如果webApplicationContext已经不为空,表示这个Servlet类是通过编程式注册到容器中的(Servlet 3.0 +中的ServletContext.addServlet()),

//上下文也由编程式传入。若这个传入的上下文还没有被初始化,将rootContext上下文设置为它的父上下文,然后将其初始化,否则直接使用。

if (this.webApplicationContext != null) {

// A context instance was injected at construction time -> use it

wac = this.webApplicationContext;

if (wac instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// The context instance was injected without an explicit parent -> set

// the root application context (if any; may be null) as the parent

cwac.setParent(rootContext);

}

configureAndRefreshWebApplicationContext(cwac);

}

}

}

//判断wac是否为空判断是否已经完成上面的上下文的设置

if (wac == null) {

// No context instance was injected at construction time -> see if one

// has been registered in the servlet context. If one exists, it is assumed

// that the parent context (if any) has already been set and that the

// user has performed any initialization such as setting the context id

//如果为空,说明该Servlet不是由编程式注册到容器中的,在ServletContext中查找上下文,查找得到

//说明上下文已经以别的方式初始化并注册在contextAttribute下,直接使用

wac = findWebApplicationContext();

}

if (wac == null) {

// No context instance is defined for this servlet -> create a local one

//此时还为空,调用以下方法创建一个全新的以rootContext为父上下文的上下文,作为SpringMVC配置元素的上下文

//大多数情况下我们所使用的上下文就是这个新建的上下文

wac = createWebApplicationContext(rootContext);

}

if (!this.refreshEventReceived) {

// Either the context is not a ConfigurableApplicationContext with refresh

// support or the context injected at construction time had already been

// refreshed -> trigger initial onRefresh manually here.

//在DispatcherServlet中复写,会初始化一系列属性

onRefresh(wac);

}

if (this.publishContext) {

// Publish the context as a servlet context attribute.

//将这个上下文发布到ServletContext中,也就是将上下文以一个和Servlet类在web.xml中注册名字有关的值为键

//设置为ServletContext的一个属性

String attrName = getServletContextAttributeName();

getServletContext().setAttribute(attrName, wac);

if (this.logger.isDebugEnabled()) {

this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +

"' as ServletContext attribute with name [" + attrName + "]");

}

}

return wac;

}

//从当前容器中查找SpringMVC的IOC容器

protected WebApplicationContext findWebApplicationContext() {

String attrName = getContextAttribute();

if (attrName == null) {

return null;

}

WebApplicationContext wac =

WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);

if (wac == null) {

throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");

}

return wac;

}

//创建springMVC的IOC容器,

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {

//获取类XMLWebApplicationContext

Class<?> contextClass = getContextClass();

if (this.logger.isDebugEnabled()) {

this.logger.debug("Servlet with name '" + getServletName() +

"' will try to create custom WebApplicationContext context of class '" +

contextClass.getName() + "'" + ", using parent context [" + parent + "]");

}

if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {

throw new ApplicationContextException(

"Fatal initialization error in servlet with name '" + getServletName() +

"': custom WebApplicationContext class [" + contextClass.getName() +

"] is not of type ConfigurableWebApplicationContext");

}

//实例化一个IOC容器

ConfigurableWebApplicationContext wac =

(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

//设置IOC容器相关的属性,这样springMVC的IOC容器就创建好了

wac.setEnvironment(getEnvironment());

//设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起

wac.setParent(parent);

//设置web.xml中的springMVC的配置文件,各种bean的注入

wac.setConfigLocation(getContextConfigLocation());

//初始化springMVC各种的相关配置,各种注入的Controller,配置文件等

configureAndRefreshWebApplicationContext(wac);

return wac;

}

/*配置或者刷新应用上下文*/

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

if (ObjectUtils.identityToString(wac).equals(wac.getId())) {

// The application context id is still set to its original default value

// -> assign a more useful id based on available information

if (this.contextId != null) {

wac.setId(this.contextId);

}

else {

// Generate default id...

wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +

ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());

}

}

//设置springMVC IOC容器的相关属性

wac.setServletContext(getServletContext());

wac.setServletConfig(getServletConfig());

wac.setNamespace(getNamespace());

wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

// The wac environment's #initPropertySources will be called in any case when the context

// is refreshed; do it eagerly here to ensure servlet property sources are in place for

// use in any post-processing or initialization that occurs below prior to #refresh

ConfigurableEnvironment env = wac.getEnvironment();

if (env instanceof ConfigurableWebEnvironment) {

((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());

}

postProcessWebApplicationContext(wac);

applyInitializers(wac);

//初始化springMVC各种的相关配置,各种注入的Controller,配置文件等

wac.refresh();

}

protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {

return createWebApplicationContext((ApplicationContext) parent);

}

protected void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac) {

}

protected void applyInitializers(ConfigurableApplicationContext wac) {

String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);

if (globalClassNames != null) {

for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {

this.contextInitializers.add(loadInitializer(className, wac));

}

}

if (this.contextInitializerClasses != null) {

for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {

this.contextInitializers.add(loadInitializer(className, wac));

}

}

AnnotationAwareOrderComparator.sort(this.contextInitializers);

for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {

initializer.initialize(wac);

}

}

@SuppressWarnings("unchecked")

private ApplicationContextInitializer<ConfigurableApplicationContext> loadInitializer(

String className, ConfigurableApplicationContext wac) {

try {

Class<?> initializerClass = ClassUtils.forName(className, wac.getClassLoader());

Class<?> initializerContextClass =

GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);

if (initializerContextClass != null) {

Assert.isAssignable(initializerContextClass, wac.getClass(), String.format(

"Could not add context initializer [%s] since its generic parameter [%s] " +

"is not assignable from the type of application context used by this " +

"framework servlet [%s]: ", initializerClass.getName(), initializerContextClass.getName(),

wac.getClass().getName()));

}

return BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class);

}

catch (Exception ex) {

throw new IllegalArgumentException(String.format("Could not instantiate class [%s] specified " +

"via 'contextInitializerClasses' init-param", className), ex);

}

}

public String getServletContextAttributeName() {

return SERVLET_CONTEXT_PREFIX + getServletName();

}

/**

* Return this servlet's WebApplicationContext.

*/

public final WebApplicationContext getWebApplicationContext() {

return this.webApplicationContext;

}

protected void initFrameworkServlet() throws ServletException {

}

public void refresh() {

WebApplicationContext wac = getWebApplicationContext();

if (!(wac instanceof ConfigurableApplicationContext)) {

throw new IllegalStateException("WebApplicationContext does not support refresh: " + wac);

}

((ConfigurableApplicationContext) wac).refresh();

}

//WebApplicationContext刷新通知

public void onApplicationEvent(ContextRefreshedEvent event) {

this.refreshEventReceived = true;

onRefresh(event.getApplicationContext());

}

protected void onRefresh(ApplicationContext context) {

// For subclasses: do nothing by default.

}

/**

* Close the WebApplicationContext of this servlet.

* @see org.springframework.context.ConfigurableApplicationContext#close()

*/

@Override

public void destroy() {

getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");

// Only call close() on WebApplicationContext if locally managed...

if (this.webApplicationContext instanceof ConfigurableApplicationContext && !this.webApplicationContextInjected) {

((ConfigurableApplicationContext) this.webApplicationContext).close();

}

}

/**

* Override the parent class implementation in order to intercept PATCH

* requests.

*/

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

String method = request.getMethod();

if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {

processRequest(request, response);

}

else {

super.service(request, response);

}

}

//get请求

@Override

protected final void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

//post请求

@Override

protected final void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

//put请求

@Override

protected final void doPut(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

//delete请求

@Override

protected final void doDelete(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

@Override

protected void doOptions(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {

processRequest(request, response);

if (response.containsHeader("Allow")) {

// Proper OPTIONS response coming from a handler - we're done.

return;

}

}

// Use response wrapper for Servlet 2.5 compatibility where

// the getHeader() method does not exist

super.doOptions(request, new HttpServletResponseWrapper(response) {

@Override

public void setHeader(String name, String value) {

if ("Allow".equals(name)) {

value = (StringUtils.hasLength(value) ? value + ", " : "") + RequestMethod.PATCH.name();

}

super.setHeader(name, value);

}

});

}

@Override

protected void doTrace(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

if (this.dispatchTraceRequest) {

processRequest(request, response);

if ("message/http".equals(response.getContentType())) {

// Proper TRACE response coming from a handler - we're done.

return;

}

}

super.doTrace(request, response);

}

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

long startTime = System.currentTimeMillis();

Throwable failureCause = null;

LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();

LocaleContext localeContext = buildLocaleContext(request);

RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();

ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

initContextHolders(request, localeContext, requestAttributes);

try {

doService(request, response);

}

catch (ServletException ex) {

failureCause = ex;

throw ex;

}

catch (IOException ex) {

failureCause = ex;

throw ex;

}

catch (Throwable ex) {

failureCause = ex;

throw new NestedServletException("Request processing failed", ex);

}

finally {

resetContextHolders(request, previousLocaleContext, previousAttributes);

if (requestAttributes != null) {

requestAttributes.requestCompleted();

}

if (logger.isDebugEnabled()) {

if (failureCause != null) {

this.logger.debug("Could not complete request", failureCause);

}

else {

if (asyncManager.isConcurrentHandlingStarted()) {

logger.debug("Leaving response open for concurrent processing");

}

else {

this.logger.debug("Successfully completed request");

}

}

}

publishRequestHandledEvent(request, response, startTime, failureCause);

}

}

protected LocaleContext buildLocaleContext(HttpServletRequest request) {

return new SimpleLocaleContext(request.getLocale());

}

protected ServletRequestAttributes buildRequestAttributes(

HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {

if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {

return new ServletRequestAttributes(request, response);

}

else {

return null; // preserve the pre-bound RequestAttributes instance

}

}

private void initContextHolders(

HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {

if (localeContext != null) {

LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);

}

if (requestAttributes != null) {

RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);

}

if (logger.isTraceEnabled()) {

logger.trace("Bound request context to thread: " + request);

}

}

private void resetContextHolders(HttpServletRequest request,

LocaleContext prevLocaleContext, RequestAttributes previousAttributes) {

LocaleContextHolder.setLocaleContext(prevLocaleContext, this.threadContextInheritable);

RequestContextHolder.setRequestAttributes(previousAttributes, this.threadContextInheritable);

if (logger.isTraceEnabled()) {

logger.trace("Cleared thread-bound request context: " + request);

}

}

private void publishRequestHandledEvent(

HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {

if (this.publishEvents) {

// Whether or not we succeeded, publish an event.

long processingTime = System.currentTimeMillis() - startTime;

int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);

this.webApplicationContext.publishEvent(

new ServletRequestHandledEvent(this,

request.getRequestURI(), request.getRemoteAddr(),

request.getMethod(), getServletConfig().getServletName(),

WebUtils.getSessionId(request), getUsernameForRequest(request),

processingTime, failureCause, statusCode));

}

}

protected String getUsernameForRequest(HttpServletRequest request) {

Principal userPrincipal = request.getUserPrincipal();

return (userPrincipal != null ? userPrincipal.getName() : null);

}

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)

throws Exception;

//监听WebApplicationContext的刷新情况

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

FrameworkServlet.this.onApplicationEvent(event);

}

}

private class RequestBindingInterceptor extends CallableProcessingInterceptorAdapter {

@Override

public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) {

HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

if (request != null) {

HttpServletResponse response = webRequest.getNativeRequest(HttpServletResponse.class);

initContextHolders(request, buildLocaleContext(request), buildRequestAttributes(request, response, null));

}

}

@Override

public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) {

HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

if (request != null) {

resetContextHolders(request, null, null);

}

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息