Servlet3通过SPI进行注册组件
# Servlet3通过SPI进行注册组件
# 什么是SPI
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
这一机制为很多框架扩展提供了可能,比如在JDBC的加载驱动方式也是采用了这种方式,只需要导入对应驱动jar包则可以自动注册驱动。 本文提到的Servlet3.0也提供了这一机制,只需要在META-INF/services下面创建javax.servlet.ServletContainerInitializer这一文件,并在里面填入需要在Tomcat启动的时候加载的类的全限定类名即可,如果有多个,一行一个。
# 快速体验
# 总体流程
- 首先引入Servlet-Api
- 创建一个类实现ServletContainerInitializer接口,并重写onStartup方法
- 在src/META-INF下面创建上述文件,并在其中填入创建的类的全限定类名
- 配置tomcat并启动项目即可
# 代码实例
maven创建工程引入Servet-Api并改打包方式为war
创建MyServletContainerInitializer实现ServletContainerInitializer
package com.unclezs.initializer;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.Set;
/**
* @author uncle
* @date 2020/3/20 20:51
*/
public class MyServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
System.out.println("容器初始化了")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 在src下面创建META-INF/service/javax.servlet.ServletContainerInitializer
- 配置Tomcat启动查看效果
# 细节说明
可以看到,当我们实现了ServletContainerInitializer接口的话,在onStartUp方法中传入了
public void onStartup(Set<Class<?>> c, ServletContext ctx){}
其中的ServletContext我们已经熟悉,为Servlet的上下文,可以做web.xml里面可以做的事情
这个Set集合传入的class则需要配合一个@HandlesTypes注解了
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HandlesTypes {
Class<?>[] value();
}
2
3
4
5
容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递过来。 所以如果我们需要做一些额外的定制的话可以写一个这样的接口,SpringMVC的WebApplicationInitializer就是这么一个接口。
# SpringMVC中使用这个机制
打开Spring-Web这个jar包一看
可以看到就是利用在Servlet3.0更新的SPI机制,其中WebApplicationInitializer这个接口,就是我们用来配置无web.xml搭建springmvc项目的时候用到的类。
贴一下无web.xml配置一个最小SpringMVC项目
package com.unclezs.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
/**
* @author uncle
* @date 2019.12.31
*/
public class WebInit implements WebApplicationInitializer {
public void onStartup(javax.servlet.ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.scan("com.unclezs");
ServletRegistration.Dynamic mvc = servletContext.addServlet("springmvc", new DispatcherServlet(ctx));
mvc.addMapping("/");
mvc.setLoadOnStartup(1);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
配置好Tomcat直接启动就可可以了,是不是贼清爽~