Servlet3.0——整合SpringMVC

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rubulai/article/details/80978326

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

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.bdm</groupId>
	<artifactId>springmvc-anno</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.6</version>
				<configuration>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

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

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>5.0.7.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>4.0.1</version>
		<!-- 由于tomcat已经有了servlet-api,因此设置为provided,表示目标环境已经有该jar包,在打war包时不会将此包打入,避免冲突 -->
		<scope>provided</scope>
	</dependency>
</dependencies>

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

内容为:

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<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> 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接口的抽象实现类,所以只需要实现这些抽象类即可

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的配置信息

猜你喜欢

转载自blog.csdn.net/rubulai/article/details/80978326