Tomcat不使用web.xml加载Springmvc

文章目录

  • servlet3新特性演示
    • 依赖如下
    • 实现ServletContainerInitializer
    • 启动配置
    • tomcat7:run启动
  • 启动springmvc
    • 启动配置类
    • spring对上面配置类的处理
    • 重点

servlet3新特性演示

依赖如下

<dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.2.2.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.2.2.RELEASEversion>
        dependency>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
        dependency>

    dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.mavengroupId>
                <artifactId>tomcat7-maven-pluginartifactId>
                <version>2.2version>
            plugin>
        plugins>
    build>

实现ServletContainerInitializer

Servlet3新规范:
Tomcat启动时会扫描classpath:META-INF.services.javax.servlet.ServletContainerInitializer文件
里面写的接口的所有实现类,执行onStartup()方法
注意:
@HandlesTypes注解的参数是一个接口,可以将他所有的实现类存到onStartup方法的参数Set> c中
这是由tomcat实现的

/**
 * @author zc
 * @version 1.0
 * @date 2020/1/12 2:12 下午
 * @desc
 */
@HandlesTypes(Test.class)
public class MyTestInit implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        System.out.println("===========mytest-------------");
        for (Class<?> aClass : c) {
            System.out.println(aClass);
        }
    }
}
/**
 * @author zc
 * @version 1.0
 * @date 2020/1/12 2:20 下午
 * @desc
 */
public interface Test {
}
/**
 * @author zc
 * @version 1.0
 * @date 2020/1/12 2:24 下午
 * @desc
 */
public class TestImpl implements Test {
}

启动配置

Tomcat不使用web.xml加载Springmvc_第1张图片

javax.servlet.ServletContainerInitializer里面的内容

com.demo.MyTestInit

tomcat7:run启动

通过tomcat7:run启动项目
image.png

可以看到启动结果
Tomcat不使用web.xml加载Springmvc_第2张图片

启动springmvc

启动配置类

参考官方文档
实现WebApplicationInitializer这个接口就可以取代web.xml所做的事情

@Configuration
@ComponentScan("com.demo")
public class AppConfig {

}
/**
 * @author zc
 * @version 1.0
 * @date 2020/1/12 1:04 下午
 * @desc
 */
public class MyWebAppInit implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        System.out.println("+++++++++++++++++++++");

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.addMapping("/");
        registration.setLoadOnStartup(1);
    }
}

spring对上面配置类的处理

可以看看WebApplicationInitializer的源码
里面什么都没有

public interface WebApplicationInitializer {

	/**
	 * Configure the given {@link ServletContext} with any servlets, filters, listeners
	 * context-params and attributes necessary for initializing this web application. See
	 * examples {@linkplain WebApplicationInitializer above}.
	 * @param servletContext the {@code ServletContext} to initialize
	 * @throws ServletException if any call against the given {@code ServletContext}
	 * throws a {@code ServletException}
	 */
	void onStartup(ServletContext servletContext) throws ServletException;

}

参考servlet3新特性,来看看spring是怎么做的
找到如下文件
Tomcat不使用web.xml加载Springmvc_第3张图片

里面只有一行内容:org.springframework.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);
		}
	}

}

重点

  1. @HandlesTypes(WebApplicationInitializer.class)

这个注解上面讲了,可以将WebApplicationInitializer所有的实现类放到onStartup的入参中

  1. 上面代码33-35行
for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}

他会循环执行WebApplicationInitializer所有实现类的onStartup()

而我们上面MyWebAppInit,就进行了spring环境的初始化

你可能感兴趣的:(spring)