Servlet3.0——整合SpringMVC

1、创建一个maven工程,打包方式为war:由于工程中没有web.xml,而以war的形式打包工程时pom.xml文件会检查web.xml文件是否存在,不存在则会报错,此时需要加一个构建插件maven-war-plugin:设置为false即可


	4.0.0
	com.bdm
	springmvc-anno
	0.0.1-SNAPSHOT
	war

	
		
			
				org.apache.maven.plugins
				maven-war-plugin
				2.6
				
					false
				
			
		
	

2、导入所有的依赖:导入spring-webmvc时会导入依赖的spring-context、spring-bean、spring-core等核心包


	
		org.springframework
		spring-webmvc
		5.0.7.RELEASE
	
	
		javax.servlet
		javax.servlet-api
		4.0.1
		
		provided
	

3、在导入的jar包中有这样一个文件:

Servlet3.0——整合SpringMVC_第1张图片

内容为:

org.springframework.web.SpringServletContainerInitializer

web容器在启动的时候,会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer,并可以利用它去注册一些web组件,SpringServletContainerInitializer的代码:

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
	
	@Override
	public void onStartup(@Nullable Set> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List initializers = new LinkedList<>();

		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)
								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);
		}
	}

}

可以看出在SpringServletContainerInitializer中会将WebApplicationInitializer接口的所有实现类(非抽象类)实例化,并依次执行其实例的onStartup(servletContext)方法,因此我们可以通过实现WebApplicationInitializer接口或者继承其子类,并在其子类中注册Spring容器配置类和SpringMVC配置类的方式来达到实现web工程的目的。

4、spring-mvc中自带了一些WebApplicationInitializer接口的抽象实现类,所以只需要实现这些抽象类即可

Servlet3.0——整合SpringMVC_第2张图片

 

1)、AbstractContextLoaderInitializer:创建根容器,createRootApplicationContext()是一个抽象方法,供子类实现

protected void registerContextLoaderListener(ServletContext servletContext) {
	WebApplicationContext rootAppContext = createRootApplicationContext();
	if (rootAppContext != null) {
		ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
		listener.setContextInitializers(getRootApplicationContextInitializers());
		servletContext.addListener(listener);
	}
	else {
		logger.debug("No ContextLoaderListener registered, as " +
				"createRootApplicationContext() did not return an application context");
	}
}
@Nullable
protected abstract WebApplicationContext createRootApplicationContext();

2)、AbstractDispatcherServletInitializer:
①创建一个web的ioc容器:createServletApplicationContext(),抽象方法,供子类实现
②创建DispatcherServlet:createDispatcherServlet()
③将创建的DispatcherServlet添加到ServletContext中

④getServletMappings();

protected void registerDispatcherServlet(ServletContext servletContext) {
	String servletName = getServletName();
	Assert.hasLength(servletName, "getServletName() must not return null or empty");


	WebApplicationContext servletAppContext = createServletApplicationContext();
	Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");


	FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
	Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
	dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());


	ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
	if (registration == null) {
		throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
				"Check if there is another servlet registered under the same name.");
	}


	registration.setLoadOnStartup(1);
	registration.addMapping(getServletMappings());
	registration.setAsyncSupported(isAsyncSupported());


	Filter[] filters = getServletFilters();
	if (!ObjectUtils.isEmpty(filters)) {
		for (Filter filter : filters) {
			registerServletFilter(servletContext, filter);
		}
	}


	customizeRegistration(registration);
}
	
protected abstract WebApplicationContext createServletApplicationContext();

3)、AbstractAnnotationConfigDispatcherServletInitializer:子类通过实现其抽象方法返回注解方式的根容器和Servlet子容器,从而实现注解方式配置DispatcherServlet初始化器(SpringMVC的容器)和根容器(Spring的IOC容器)
创建根容器:createRootApplicationContext(),子实现类通过实现getRootConfigClasses();方法返回一个配置类
创建web的IOC容器: createServletApplicationContext();子实现类通过实现getServletConfigClasses();返回一个web的IOC容器配置类

public abstract class AbstractAnnotationConfigDispatcherServletInitializer
		extends AbstractDispatcherServletInitializer {

	@Override
	@Nullable
	protected WebApplicationContext createRootApplicationContext() {
		Class[] configClasses = getRootConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
			AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
			context.register(configClasses);
			return context;
		}
		else {
			return null;
		}
	}

	@Override
	protected WebApplicationContext createServletApplicationContext() {
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		Class[] configClasses = getServletConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
			context.register(configClasses);
		}
		return context;
	}

	@Nullable
	protected abstract Class[] getRootConfigClasses();

	@Nullable
	protected abstract Class[] getServletConfigClasses();

}

其实是注册了两个互相独立的IOC容器:一个用来装载service、repository等组件,一个用来装载controller组件;以注解方式来启动SpringMVC,只需要继承AbstractAnnotationConfigDispatcherServletInitializer,实现其抽象方法来指定DispatcherServlet的配置信息

你可能感兴趣的:(Servlet3.0)