一、Servlet容器启动时会扫描当前应用中每一个jar包中的在META-INF/services/javax.servlet.ServletContainerInitializer文件(该文件没有后缀名)中配置的ServletContainerInitializer的实现类,javax.servlet.ServletContainerInitializer文件的内容就是ServletContainerInitializer实现类的全类名,启动时会运行这些实现类的onStartUp方法,可以通过@HandlesTypes传入一些感兴趣的类型,在onStartUp方法中做一些操作。一个jar包中只能有一个javax.servlet.ServletContainerInitializer配置文件,一个javax.servlet.ServletContainerInitializer配置文件中只能配置一个ServletContainerInitializer实现类。
ServletContainerInitializer实现类:
@HandlesTypes({HelloServiceInterface.class})
public class MyServletContainerInitializer implements ServletContainerInitializer{@Overridepublic void onStartup(Set<Class<?>> set, ServletContext context) throws ServletException {System.out.println("感兴趣的类:");for (Class<?> clazz : set) {System.out.println(">>>>>>" + clazz);}}}
onStartUp方法的入参:
set是@HandlesTypes中传入的接口或者类的所有子接口或者子类(不包含该接口或该类本身);context是web项目的servlet上下文,一个web项目对应一个ServletContext,通过ServletContext可以来注册web组件,比如第三方的filter组件(由于第三方的组件并不是我们写的,我们无法通过@WebServlet、@WebFilter、@WebListener来标注使其拦截相应的请求,这个时候就需要在ServletContainerInitializer中通过ServletContext来注册了)
javax.servlet.ServletContainerInitializer配置文件内容:
com.bdm.servlet.MyServletContainerInitializer
javax.servlet.ServletContainerInitializer配置文件的目录:
此时在项目启动时可以看到后台日志中打印出:
二、使用ServletContext注册web组件
UserServlet.java:
public class UserServlet extends HttpServlet{private static final long serialVersionUID = -5343785314009218808L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("tomcat...");}
}
UserFilter.java:
public class UserFilter implements Filter{@Overridepublic void destroy() {// TODO Auto-generated method stub}@Overridepublic void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain)throws IOException, ServletException {System.out.println("UserFilter...doFilter...");chain.doFilter(arg0, arg1);}@Overridepublic void init(FilterConfig arg0) throws ServletException {// TODO Auto-generated method stub}}
UserListener.java:只要实现了ServletContextListener接口就可以监听到ServletContext(Servlet容器)的创建和销毁
public class UserListener implements ServletContextListener {@Overridepublic void contextDestroyed(ServletContextEvent event) {System.out.println("UserListener...contextDestroyed...");}@Overridepublic void contextInitialized(ServletContextEvent event) {System.out.println("UserListener...contextInitialized...");}}
注册web组件:
@HandlesTypes({HelloServiceInterface.class})
public class MyServletContainerInitializer implements ServletContainerInitializer{@Overridepublic void onStartup(Set<Class<?>> set, ServletContext context) throws ServletException {ServletRegistration.Dynamic userServlet = context.addServlet("userServlet", new UserServlet());userServlet.addMapping("/user");FilterRegistration.Dynamic filter = context.addFilter("userFilter", UserFilter.class);filter.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "userServlet");filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");context.addListener(UserListener.class);}}
context.addServlet()注册servlet组件,context.addFilter()注册filter组件,这两个组件都需要配置映射路径,其中filter还可以配置拦截哪些servlet;context.addListener()注册listener,listener在tomcat启动时就会调用其中的逻辑;
servlet、filter、listener这些组件的注册必须在tomcat容器启动的时候,有两处可以进行这些组件的注册,一个就是上面的例子(通过ServletContainerInitializer中的ServletContext来注册),还有一个地方可以注册,就是在ServletContextListener的实现类中获取到ServletContext,然后通过ServletContext注册其他的listener、filter、servlet:
@WebListener
public class UserListener implements ServletContextListener {@Overridepublic void contextDestroyed(ServletContextEvent event) {System.out.println("UserListener...contextDestroyed...");}@Overridepublic void contextInitialized(ServletContextEvent event) {ServletContext servletContext = event.getServletContext();Dynamic addServlet = servletContext.addServlet("userServlet", UserServlet.class);addServlet.addMapping("/user");javax.servlet.FilterRegistration.Dynamic addFilter = servletContext.addFilter("userFilter", UserFilter.class);addFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");}}
此处的UserLisener需要使用@WebListener注解的方式注册,而不可以在ServletContainerInitializer中注册,不知道什么原因?