本文为转载,地址: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函数方法中。
- //创建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");
- }
- }
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容器的初始化。
- /**
- *初始化和发布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;
- }
findWebApplicationContext函数是从ServletContext中查找webApplicationContext,springMVC初始化完成之后我们会看到它会将webApplicationContext保存到ServletContext中,这样我们可以在ServletContext中获取到它。
- //从当前容器中查找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;
- }
接下来的操作就是对wac设置相关属性
wac.setEnvironment(getEnvironment())设置环境
wac.setParent(parent)设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起
wac.setConfigLocation(getContextConfigLocation())设置web.xml中的springMVC的配置文件,各种bean的注入
configureAndRefreshWebApplicationContext(wac),这个函数是关键,是解析springMVC配置文件完成初始化的过程。
return wac返回已经初始化的webApplicationContext
- //创建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;
最终调用wac.refresh(),通过AbstractApplicationContext来完成对springMVC xml配置文件的解析初始化操作,这边我们就不再深入探究,在spring IOC容器初始化时我们再详细介绍。
- /*配置或者刷新应用上下文*/
- 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();
- }
FrameworkServlet完整源码解析:
- //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);
- }
- }
- }
- }