SpringMVC java 配置 DispatcherServlet

springMVC是通过DispatcherServlet将请求的URL映射到对应的控制器方法上,传统的配置DispatcherServlet的方式是配置在web.xml文件中。但是在servlet3.0的环境中,servlet容器会在类路径中查找javax.servlet.ServletContainerInitializer接口的类,如果能发现,就会用来配置servlet容器。Spring提供了这个接口的实现名为SpringServletContainerInitializer
package org.springframework.web;

import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;


@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {


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

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

		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer) 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;
		}

		AnnotationAwareOrderComparator.sort(initializers);
		servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);

		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

}

这个类会查找实现WebApplicationInitializer的类并将容器配置任务交给它们。

AbstractAnnotationConfigDispatcherServletInitializer继承的父类
实现WebApplicationInitializer,在spring3.2版本以后。



import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;


public class MyWebAppInitializer extends 
    AbstractAnnotationConfigDispatcherServletInitializer{

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

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

	@Override
	protected String[] getServletMappings() {
		return new String[] {"/"};          //将DispatcherServlet映射到"/"
	}
	
}



因此我们只要继承AbstractAnnotationConfigDispatcherServletInitializer重写它的三个方法就可以配置DispatcherServlet和Spring应用上下文,而不需要在web.xml中配置。
getRootConfigClasses()方法返回带有@Configuration注解类会用来配置ContextLoaderListener创建应用上下文的Bean。getServletConfigClasses返回带有@Configuration注解的类会用来创建DispatcherServlet上下文中的bean,这两个上下文是父子关系。

下面我们看一下RootConfig和WebConfig

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;

@ImportResource({"classpath:applicationContext.xml"})
//为了注入Environment,需要在RootConfig时加载配置文件
@PropertySource(value="classpath:application.properties")
@ComponentScan(basePackages={"com.asclepius.slhdt.serv"},excludeFilters ={ @Filter(type = FilterType.ASPECTJ, pattern = "com.asclepius.slhdt.serv.modules.*.controller.*Controller"), //排除所有控制器
		@Filter(type = FilterType.REGEX, pattern = "com.asclepius.slhdt.serv.config.*")})
public class RootConfig {


}




@EnableWebMvc
@ComponentScan("com.asclepius.slhdt.serv.modules.*.controller")
public class WebConfig extends WebMvcConfigurerAdapter {

	
	// Thymeleaf view Resolver
	@Bean
	public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
		ThymeleafViewResolver viewResolver = 
				new ThymeleafViewResolver();
		viewResolver.setTemplateEngine(templateEngine);
		viewResolver.setCharacterEncoding("UTF-8");
		return viewResolver;
	}
	
	
	// Template resolver
	@Bean
	public TemplateResolver templateResolver() {
		TemplateResolver templateResolver = 
				new ServletContextTemplateResolver();
		templateResolver.setPrefix("/WEB-INF/templates/");
		templateResolver.setSuffix(".html");
		templateResolver.setTemplateMode("HTML5");
		templateResolver.setCharacterEncoding("UTF-8");
		templateResolver.setOrder(1);
		return templateResolver;
	}
	
	
	public void configureDefaultServletHandling(
			DefaultServletHandlerConfigurer configurer) {
		// 静态资源可访问
		configurer.enable();
	}
	
}



webconfig继承了WebMvcConfigurerAdapter 重写了configureDefaultServletHandling()方法,是为了使对静态资源的请求转发到servlet容器上,而不是控制器。注意webconfig与rootconfig扫描装备的bean不应该有重复,否则会产生两个同类的bean。webconfig只要扫描装配控制器,视图解析器等相关的bean,让dispatcherServlet映射,rootconfig则要扫描装配一般的bean。

猜你喜欢

转载自chenshangge.iteye.com/blog/2297586