SpringMVC零配置原理

1.  ServletContainerInitializer为Servlet规范提供的接口
    会通过SPI机制加载ServletContainerInitializer的实现类
    规定的SPI路径为META-INF\services\javax.servlet.ServletContainerInitializer
    里面的内容为该接口的实现类
2.  启动的时候,会执行这些初始化类的onStartup方法
3. 在实现类上添加@HandlesTypes(ILuckService.class)注解,在tomcat启动的时候
   会自动将该接口对应的子类,实现类,子接口传递过来,作为onStartup的set参数传递过来
// 容器启动的时候,会将HandlesTypes指定的这个类下面的子类,实现类,子接口传递过来
@HandlesTypes(ILuckService.class)
public class LuckServletContainerInitializer implements ServletContainerInitializer {
   @Override
    public void onStartup(Set<Class<?>> set, ServletContext ctx) throws ServletException {
        set.forEach(temp -> System.out.println(temp.getName()));
        // 手动注册servlet
        ServletRegistration.Dynamic sciServlet = ctx.addServlet("sciServlet", new SciServlet());
        sciServlet.addMapping("/sci/servlet");
        // 注册监听器
        ctx.addListener(SciListener.class);
        // 手动注册Filter
        FilterRegistration.Dynamic sciFilter = ctx.addFilter("sciFilter", SciFilter.class);
        sciFilter.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "sciServlet");
        sciFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
    }
}
4. 而对于Spring,它也提供了一个实现类
   并且SPI文件在spring-web/META-INF/services/javax.servlet.ServletContainerInitializer
   内容为org.springframework.web.SpringServletContainerInitializer
   根据下面源码,知道AbstractDispatcherServletInitializer符合条件,并且会自动注入DispatchServlet
   并且有三个抽象方法{
        // 创建SpringMVC容器
        protected WebApplicationContext createServletApplicationContext();
        // 获取DispatchServlet的映射路径
        protected String[] getServletMappings();
        // 创建父容器
        protected WebApplicationContext createRootApplicationContext();
   },而对与这三个,我们用的不是很多,它还提供一个一个继承于AbstractDispatcherServletInitializer的类
   // 它将父类再一步简化,不需要在创建context对象,而是直接给定配置类,自动创建容器
   // 所以,使用SpringMVC零配置,使用AbstractAnnotationConfigDispatcherServletInitializer是最终方法
   AbstractAnnotationConfigDispatcherServletInitializer{
        protected Class<?>[] getRootConfigClasses();
        protected Class<?>[] getServletConfigClasses();
        protected String[] getServletMappings();
   }
 */
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    // webAppInitializerClasses: 扫描到WebApplicationInitializer的实现类
    @Override
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
        if (webAppInitializerClasses != null) {
            initializers = new ArrayList<>(webAppInitializerClasses.size());
            for (Class<?> waiClass : webAppInitializerClasses) {
                // 排除接口和抽象类
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    // 实例化对象
                   initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                }
            }
        }
        AnnotationAwareOrderComparator.sort(initializers);
        // 执行Spring提供的类对应的initializer方法
        for (WebApplicationInitializer initializer : initializers) {
            // 其中包含了AbstractDispatcherServletInitializer,会自动注册一个DispatchServlet
            initializer.onStartup(servletContext);{
                super.onStartup(servletContext);
                registerDispatcherServlet(servletContext);{
                    String servletName = getServletName();
                    // 创建SpringMVC子容器
                    WebApplicationContext servletAppContext = createServletApplicationContext();
                    // 创建DispatchServlet
                    FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
                    // 设置servlet的配置,和xml中一样的效果
                    dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
                    // 动态注册
                    ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
                    registration.setLoadOnStartup(1);
                    registration.addMapping(getServletMappings());
                    // 设置是否支持异步
                    registration.setAsyncSupported(isAsyncSupported());
                    // 设置过滤器
                    Filter[] filters = getServletFilters();
                    if (!ObjectUtils.isEmpty(filters)) {
                        for (Filter filter : filters) {
                            registerServletFilter(servletContext, filter);
                        }
                    }
                    // 自定义配置
                    customizeRegistration(registration);
                }
            }
        }
    }
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值