web.xml怎么消失的之越陷越深(一)

个人笔记,因有道需要会员,就用CSDN了,本人菜鸟,欢迎批评。
web.xml最简单配置

    <!--1.1-->
    <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>  
    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>classpath:spring/applicationContext.xml</param-value>  
    </context-param> 
    <!--1.2-->
    <servlet>  
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
            <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/dispatcher-servlet.xml</param-value>-->  
            <param-value>classpath*:dispatcher-servlet.xml</param-value>
        </init-param>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>DispatcherServlet</servlet-name> 
        <url-pattern>/</url-pattern> 
    </servlet-mapping>  
    ...
  • 配置文件1.1处
    listener标签添加了一个ContextLoaderListener,该职责在于提供WEB应用程序加载顶层的WebApplicationContext,像我们使用的数据源(dataSource),数据访问对象(Dao),数据服务对象(service)都注册在其中,即父容器。默认配置文件路径为/WEB-INF/applicationContext.xml,当然可以自定义配置文件路径,则采用标签
  • 配置文件1.2处
    DispatcherServlet则是用来加载springMVC在请求过程中涉及到的各个组件,例如:HandlerMapping,Controller,HandlerAdpater,ViewResolver等,默认加载文件路径为/WEB-INF/servlet-name-serblet.xml,servlet-name即为配置的,当然也可以自己定义,通过来指定。

认识WebApplicationInitializer,先来看一段代码

<!--这里也可以继承WebApplicationInitializer它的子类AbstractDispatcherServletInitializer-->
public class MyWebAppInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext container) {
       XmlWebApplicationContext appContext = new XmlWebApplicationContext();
       appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
 
       ServletRegistration.Dynamic dispatcher =
         container.addServlet("dispatcher", new DispatcherServlet(appContext));
       dispatcher.setLoadOnStartup(1);
       dispatcher.addMapping("/");
     }
}

上面这一段代码就可以将web.xml替换掉了,但是dispatcher-config.xml仍然是基于xml配置的,这里可以使用AnnotationConfigWebApplicationContext替换XmlWebApplicationContext来达到目的。

<!--也可以通过继承AbstractAnnotationConfigDispatcherServletInitializer-->
public class MyWebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
      // Create the 'root' Spring application context
      AnnotationConfigWebApplicationContext rootContext =
        new AnnotationConfigWebApplicationContext();
      rootContext.register(AppConfig.class);
      // Manage the lifecycle of the root application context
      container.addListener(new ContextLoaderListener(rootContext));
      // Create the dispatcher servlet's Spring application context
      AnnotationConfigWebApplicationContext dispatcherContext =
        new AnnotationConfigWebApplicationContext();
      dispatcherContext.register(DispatcherConfig.class);
      // Register and map the dispatcher servlet
      ServletRegistration.Dynamic dispatcher =
        container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
      dispatcher.setLoadOnStartup(1);
      dispatcher.addMapping("/");
    }
 }

虽然可以使用代码替换xml配置,但是这两者不是互斥的,可以同时使用,xml配置一个servlet,代码配置另外一个,只是有一点必须要保证,就是servler的版本是3.0或者更高,但是这样做没有必要。

实现细节:

在servelt3.0环境中,容器会在类路径中查找实现ServletContainerInitializer接口的类,如果发现了,就用它来配置servlet容器。spring提供了一个这个接口的实现类为SpringServletContainerInitializer,我们看一下这块代码,可以发现配置初始化是交给WebApplicationInitializer来完成的。

public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = new LinkedList<>();

		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)
								ReflectionUtils.accessibleConstructor(waiClass).newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}
		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}
		servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
		AnnotationAwareOrderComparator.sort(initializers);
		for (WebApplicationInitializer initializer : initializers) {
			// 初始化
			initializer.onStartup(servletContext);
		}
	}

我们来看一下AbstractAnnotationConfigDispatcherServletInitializer类继承结构
在这里插入图片描述
这里我追踪一下调用链路看一下
AbstractAnnotationConfigDispatcherServletInitializer并没有复写onStartUp()方法,所以我们查看它的父类AbstractDispatcherServletInitializer

super.onStartup会调用AbstractContextLoaderInitializer.onStartup的方法
在这里插入图片描述
代码思路很简单,我们如果自定义ApplicationContextInitializer只需要继承AbstractAnnotationConfigDispatcherServletInitializer,然后实现getRootConfigClasses,getServletConfigClasses以及getServletMappings即可, 这样就完全将web.xml以及dispatcher-servlet.xml全部替换掉了。

demo

public Class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
	protected String[] getServletMappings(){
		return new String[]{"/"};
	}
	
	protected Class<?>[] getRootConfigClasses(){
		return new String[]{RootConfig.class};
	}
	
	protected Class<?>[] getServletConfigClasses(){
		return new String[]{WebConfig.class};
	}
}

@Configuration
@ComponentScan(basePackages={""},excludeFilters={@Filter(type=FilterType.ANNOTATION,value=EnableWebMvc.class)})
public Class RootConfig{
	//TODO
}

@Configuration
@EnableWebMvc
@ComponentScan("")
public Class WebConfig{
	//TODO
}

同时它也开放了一些方法留给子类覆盖实现,包括:

  1. protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers()
  2. protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers()
  3. protected Filter[] getServletFilters()
  4. protected void customizeRegistration(ServletRegistration.Dynamic registration)
    第一个和第二个得到的ApplicationContextInitializer我后面再看源码学写下,第3个获取我们自定义的Filter,第4个我们可以进行重载对DispatcherServlet进行额外的配置。比如文件上传时设置临时路径,我们可以这么做:
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
	registration.setMultipartConfig(new MultipartConfigElement(""));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值