SpringMVC的web配置——JDK中SPI机制的应用
本文与其说是总结MVC的web配置,不如更精准的描述是web配置是约定的某一个标准的应用。这个标准本质是Servlet3.0以上标准的一个小知识点。
一般入门的web项目,使用集成开发工具都会自建一个web.xml的文件。该文件中配置servlet/filter/listener等相关信息。如下图:
Spring提供接口WebApplicationInitializer,通过自定义实现该接口配置web.xml里的相关信息。查看该接口源码:
同时该接口源码注释中提供了多个示例,下图是示例之一:
,这个servletContext可以直接理解为常用的容器tomcat的一个实例。如果使用其他的符合servlet标准的容器,也可以理解为其他容器的一个实例。
为什么单拧这个出来呢?这就涉及一个标准~Servlet3.0以上版本的标准吧。实际上Servlet3.0以上的标准为运行时可插拔,为SpringBoot自动配置MVC后并自动在容器中运行提供了可能。具体实现通过ServletContainerInitializer操作。
1)ServletContainerInitializer类通过jar services API查找。容器启动时,会创建一个ServletContainerInitializer实例。
2)自定义的应用提供的ServletContainerInitializer实现类必须绑定在jar包的META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer的文件中,并根据这个文件指定ServletContainerInitializer的实现。这个规则其实就是SPI机制的约定之一(参考Dubbo SPI机制之一JDK中的SPI)。
3)除了ServletContainerInitializer外,还提供一个注解@HandlesTypes。在ServletContainerInitializer实现上的HandlesTypes注解用于表示感兴趣的一些类,他们可以指定@HandlesTypes的value中的注解(类型、方法或自动级别的),或者是其类型的超类继承/实现之一。
当应用正在启动时,ServletContainerInitializer的OnStartup方法将被调用。ServletContainerInitializer's的OnStartup得到一个类的Set,其或者继承/实现initializer表示感兴趣的类,或者它是使用指定在@HandlesTypes注解中的任意类注解的。
以上通过具体操作的解释如下:
1、编写自定义一个类实现ServletContainerInitializer
其方法名就是onStartup,调用自定义实现WebApplicationInitializer的类或子类的方法onStartup。
2、通过@HandlesTypes传递web配置信息,编写实现WebApplicationInitializer的类即可。(可以是其他类或子类,但是此处是针对SpringMVC,必须实现WebApplicationInitializer)
即onStartup中参数Set是实现WebApplicationInitializer接口的一些列类。
具体的一个实现如下:
3、文件编写META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer
文件内容为实现ServletContainerInitializer的类全限定名。
启动tomcat容器时,tomcat自动扫描该项目jar下的所有META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer的文件,执行文件MySpringServletContainerInitializer类的onStartup方法,并通过反射自动调用MyWebApplicationInitializer的onStartup方法。
javax.servlet.ServletContainerInitializer作为纽带将容器与WebApplicationInitializer关联起来。下面验证SpringBoot中SpringMVC自动配置是否符合此逻辑:
1、SpringBoot添加web依赖
2、查看加载的jar中是否存在META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer
3、查看SpringServletContainerInitializer类具体实现
4、查看WebApplicationInitializer的实现