1.1 实现WebApplicationInitializer接口
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// 初始化spring 容器
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// 初始化我们的DispatcherServlet ,并通过servletCxt传入到容器中
// servletCxt 为web上下文对象
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
如上述代码,我们只需要实现WebApplicationInitializer接口,实现onStartup方法,这时容器会自动加载这个类,自动调用这个方法!
为什么容器会加载这个类的这个方法呢? 因为spring实现了servlet3.0的一个新规范,SPI中指出,在指定项目根路径下的META-INF/services 包下指定javax.servlet.ServletContainerInitializer配置文件,配置文件件如下图:
配置文件中指向项目中的类文件,这个类文件中需要实现 ServletContainerInitializer接口,这个接口由servlet提供,当你提供的类实现onStartup方法时,web容器就会自动加载。类文件如下图:
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
…
}
细心的读者可能会对@HandlesTypes注解感到奇怪,这个注解的作用是什么呢?这个注解的作用是将需要的参数注入到实现ServletContainerInitializerde的onStartup方法中,以参数的形式传入。即如上述代码中所示:只要实现WebApplicationInitializer接口,在实现类中编写所需要的属性,在容器调用时spring mvc会将所有的实现类传入到onStartup方法的Set集合中,方法执行时遍历所有的set集合,之后调用其中的onStartup方法。
综上就解释了为什么我们在sping mvc中为什么实现WebApplicationInitializer接口,即能在web容器中初始化。