编程式动态注册Servlet组件
有时我们需要动态注册Servlet组件的能力,而非使用xml与诸如@WebFilter
这种声明式的方式来注册Servlet组件,尤其是使用框架开发时。
Servlet3.0中向ServletContext
中添加了一些方法用于动态添加Servlet组件,这些方法必须在应用程序初始化时被调用,如在实现了ServletContextListener
接口的类的contexInitialized
中或实现了ServletContainerInitializer
接口的类的onStartup
中。由于刚刚学过ServletContextListener
,所以本例中,我们使用另一种没见过的,ServletContainerInitializer
的方式来实验。
创建ServletContainerInitializer
这个Initializer会在容器初始化时被调用,使用SPI方式完成初始化。
创建MyServletContainerInitializer
类,实现ServletContainerInitializer
接口:
public class MyServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
System.out.println("onStartup");
}
}
在resources/META-INF/services
下,创建名为javax.servlet.ServletContainerInitializer
的文件,文件中填写你实现类的全限定名:
top.yudoge.webreview2.MyServletContainerInitializer
开启容器,运行,Initializer已经生效:
编程式添加、配置Servlet
现在在onStartup
方法中,我们有了ServletContext
的实例,其中包含这样一个方法:
/**
* 添加具有给定的名字和类的servlet到ServletContext中
* 添加的servlet可以通过返回的ServletRegistration对象被进一步配置
*/
public ServletRegistration.Dynamic addServlet(
String servletName, String className);
该方法的第一个参数是Servlet名,第二个参数是要添加的Servlet类的全限定名。方法返回一个ServletRegistration.Dynamic
,用于对注册的Servlet进行配置。
这个ServletRegistration.Dynamic
在SpringMVC中想要注册一个Filter时非常常见,我还以为是SpringMVC中的类,结果是servlet提供的功能。
下面使用这个方法动态注册一个Servlet:
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
ServletRegistration.Dynamic sr = ctx.addServlet("instructorServlet", InstructorsServlet.class.getName());
sr.addMapping("/instructors");
sr.setLoadOnStartup(1);
sr.setInitParameter("name", "value");
}
访问这个Servlet:
你还可以使用如下重载方法来注册Servlet:
public ServletRegistration.Dynamic addServlet(
String servletName, Servlet servlet);
public ServletRegistration.Dynamic addServlet(String servletName,
Class <? extends Servlet> servletClass);
区别就是Servlet类的类加载器有可能不同,使用后两种方法时,Servlet的类应该已经被加载过了,第一种方法则不一定。
其它一些方法
- 根据给定类创建Servlet
<T extends Servlet> T createServlet(Class<T> clazz)
- 获取ServletRegistration
ServletRegistration getServletRegistration(String servletName)
- 获取所有ServletRegistration
Map<String, <? extends ServletRegistration> getServletRegistrations()
关于Filter和Listener的编程式注册,和Servlet大同小异