转载

SpringMVC-初始化

springMVC是讲spring应用到web开发中。因此要明白springmvc我们得先看看spring和web这两部分。

spring

spring是一个IoC容器,帮助我们处理类的依赖,web开发中应该也有许多的类,他们的控制由spring来反转。

web

web中的servlet

先来看看最原始的,不使用任何框架的情况下,我们是怎么处理请求的。java的web开发,实际上是处理servlet。web服务器比如Tomcat是一个servlet容器。我们并不直接和client的request打交道。client的request都先由servlet容器处理,然后生成request和response交给我们处理,我们从request中解析数据,将处理的结果写入response中,这就是大概的流程,可以参照下面的图片。

SpringMVC-初始化

SpringMVC-初始化

SpringMVC-初始化

SpringMVC-初始化

SpringMVC-初始化

SpringMVC-初始化

下面是一个简单的例子:

<?xml version="1.0" encoding="UTF-8"?>
<web-appxmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>home</servlet-name>
        <servlet-class>com.gx.HomeServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>home</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
public class HomeServletextends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.print("<html> <body> <h1> hello home </h1> </body> </html>");
    }
}

我们定义了一个servlet叫做home,home绑定了url : /。当我们访问 http://localhost:8080时,servlet容器就从web.xml中找到这个映射,再找到对应的servlet交给HomeServlet处理,HomeServlet向response中写入一个html。

web中的servletcontex

servletcontext是什么呢?每个web应用都有一个servletcontext和 至少一个servlet。servletcontex用于访问web应用参数、访问服务器信息、全局共享一些信息等。比如:可能所有servlet都会用到的一些对象,我们可以将其设置为servletcontext的属性。

如何将spring应用到web上

spring是IoC容器,将各种类的控制反转。而web开发中的类,我觉的大致分为两类:

  1. servletcontext相关的用于全局的一些类
  2. servlet相关的,只和这个servlet相关的类

好了再看看springmvc。他主要有两个WebApplicationContex。以我目前的理解,他们其实正是和上面两个方面的类对应。

我们有一些全局共享的类,我们将他们的控制交给root applicationcontext来管理。

另一些只有和servlet相关的类:Controller等,我们将其交给某个DispatchServlet创建的webapplicationcontext来管理。

再来看看dispatchservlet,为什么要有他呢,目前我的理解是为了简化web开发,因为按照最原始的方式开发,我们每增加一个接口就添加一个servlet,这样就需要频繁的配置web.xml。为了解决这个问题,创建一个前端控制器DispatchServlet,他统一接收然后分发给controller。而注解的方式来映射请求和controller,更简单一点。

ok,将他们结合起来,就是在适当的时机创建适当的WebApplicationContex,在用ApplicationContext来管理Beans。这样就将spring应用到了web开发中。

适当的时机

那应该什么时候创建WebApplicationContext呢?

RootApplicationContext

RootApplicationContex是一个带有公共色彩的IoC。我们很容易想到生成一个IoC,将他放到全局的servletcontext,那么这个IoC不就可以全局为我们使用了么。

既然他需要依赖全局的servletcontext,那么就容易联想到应该在全局的servletcontext初始化完成后,就创建这个IoC,然后再将他作为属性添加到servletcontext中。

那么怎么监听servletcontext初始化完成呢?当然是在web.xml中配置一个listener,并指定一个实现了servletcontextlistener的类来监听啦。springmvc也确实是这么做的,他提供一个ContextLoaderListener,这个类实现了servletcontextlistener接口,因此servletcontext初始化完成后会通知ContextLoaderListener,ContextLoaderListener会在这个回调中去初始化Root WebApplicationContext,然后作为属性添加到servletcontext中。

明白了上面的流程,我们就知道了,如果我希望创建一个Root ApplicationContext来管理一些公用的Beans,那么需要在wen.xml中配置一个Listener:

<listener>
     <listener-class>
            org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

不过只配置这个还不够,我们还需要指定这个IoC需要管理的Beans。默认springmvc是创建一个xmlWebApplicationContext,因此需要一个xml的路径,这个路径默认是:WEB-INF/application.xml。不过你可以在web.xml中改变:

<context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>WEB-INF/application.xml</param-value>
 </context-param>

创建WebApplication的参数还有几个,下面介绍下:

<init-param>
    默认是xmlWebApplicationContext,不过我们可以通过contextClass来改变,比如下面指定为AnnotationConfigWebApplicationContext,由于他需要一个Config class,所以我们的contextConfigLocation就不再是指定xml而是指定某个类。
       <param-name>contextClass</param-name>
       <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
</init-param>
<init-param>
    在WebApplicationContext生成前,还允许我们对他进行些设置,我们可以通过这个参数来指定一个实现了ApplicationContextInitializer接口的类来做些额外的初始化。
     <param-name>contextInitializerClasses</param-name>
     <param-value>xxx</param-value>
 </init-param>

最后我们可能会想,如果我并没有全局公共的类,因此也不需要一个Root IoC,可以么?是可以的,我们可以不用生成他,方法也就是不配置listener。

WebApplocationContext

这个既然描述的是管理某个Servlet的Bean的IoC,那么他的创建时机也就是这个servlet初始化的时候。springmvc提供了DispatchServlet来作为前端控制器,并生成一个IoC。

DispatchServlet–>FrameworkServlet–>HttpServletBean–>HttpServlet。这是继承关系。

HttpServletBean负责将初始化参数设置到该组件上(contextClass,contextConfigLocation等)。并提供一个initServletBean交给子类实现。

FramworkServlet重写了这个方法。通过contextclass找到对应的class初始化。然后config他。然后如果提供了contextInitializerClasses,那么调用initializer方法。提供onRefresh方法供重载。

DispatchServlet重写了onRefresh,实现了对DispatchServlet的初始化:

initMultipartResolver(context);  

initLocaleResolver(context);   

initThemeResolver(context);   

initHandlerMappings(context);   

initHandlerAdapters(context);   

initHandlerExceptionResolvers(context);   

initRequestToViewNameTranslator(context);   

initViewResolvers(context);   

initFlashMapManager(context);

通过WebApplicationInitializer代替web.xml

Servlet3.0+之后可以通过代码来配置。主要是因为servlet容器会查找实现了ServletContainerInitailizer接口的类,如果能发现的话就会用它来配置容器。SpringMvc为这个接口提供了实现类:SpringServletContainerInitializer.这个类又会去找实现了WebApplicationInitializer的类。

import org.springframework.web.WebApplicationInitializer;

public class MyWebApplicationInitializerimplements WebApplicationInitializer{
	//没有创建root ApplicaitonContext
    @Override
    public void onStartup(ServletContext container){
        XmlWebApplicationContext appContext = new XmlWebApplicationContext();
        appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

当然spring 也提供了一些实现类:

//用它来提供RootConfig.class和AppConfig.class
public class MyWebAppInitializerextends 
    AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { MyWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

如果你更喜欢xml,可以参照:

public class MyWebAppInitializerextends AbstractDispatcherServletInitializer{

    @Override
    protected WebApplicationContext createRootApplicationContext(){
        return null;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext(){
        XmlWebApplicationContext cxt = new XmlWebApplicationContext();
        cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
        return cxt;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}
原文  http://xing-ou.github.io/2018/06/22/SpringMVC-初始化/
正文到此结束
Loading...