• Spring Boot源码(二):SPI去除web.xml


    SPI广泛用于dubbo,spring boot,spring cloud alibaba等

    关于SPI,可见SPI-Service Provider Interface

    继续上篇文章

     上面三句代码的意思是创建IOC容器,下面是向容器中注入DispatcherServlet。

     而ContextLoaderListener这个类的作用就是启动IOC容器,所以它们作用一致。

    现在来看spring web怎么写的。

     官方项目就是用的SPI来创建实例,我们聚焦于SpringServletContainerInitializer

    /**
    *类的描述:spring应用一启动(tomcat启动的时候)就会去扫描当前应用下导入jar包的META-INF/services的javax.servlet.ServletContainerInitializer的内容,
    *就是SpringServletContainerInitializer,此类中通过@HandlesTypes把WebApplicationInitializer的所有实现类作为onStartup方法的入参,
    *该方法对其中不是抽象类或接口的进行实例化
    */
    @HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { /** * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer} * implementations present on the application classpath. * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)}, * Servlet 3.0+ containers will automatically scan the classpath for implementations * of Spring's {@code WebApplicationInitializer} interface and provide the set of all * such types to the {@code webAppInitializerClasses} parameter of this method. * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath, * this method is effectively a no-op. An INFO-level log message will be issued notifying * the user that the {@code ServletContainerInitializer} has indeed been invoked but that * no {@code WebApplicationInitializer} implementations were found. * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected, * they will be instantiated (and <em>sorted</em> if the @{@link * org.springframework.core.annotation.Order @Order} annotation is present or * the {@link org.springframework.core.Ordered Ordered} interface has been * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)} * method will be invoked on each instance, delegating the {@code ServletContext} such * that each instance may register and configure servlets such as Spring's * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener}, * or any other Servlet API componentry such as filters. * @param webAppInitializerClasses all implementations of * {@link WebApplicationInitializer} found on the application classpath * @param servletContext the servlet context to be initialized * @see WebApplicationInitializer#onStartup(ServletContext) * @see AnnotationAwareOrderComparator */ @Override public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List<WebApplicationInitializer> initializers = new LinkedList<>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } } }

    里面只有一个onStartup方法,而容器启动时会调用此方法。

    我们着重看下@HandlesTypes 注解,官方解释:

    /**
    <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
    * Servlet 3.0+ containers will automatically scan the classpath for implementations
    * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
    * such types to the {@code webAppInitializerClasses} parameter of this method.
    */

    @HandlesTypes 注解会把WebApplicationInitializer的所有子类(可用快捷键Ctrl+Alt+B)放到Set集合中:

     然后循环判断此类不为抽象类不为接口,并且是实现了WebApplicationInitializer接口的,然后实例化对象添加到initializers中:

     然后对其进行排序:

     这个排序就是通过@Order来判断先后顺序的(或者实现Order接口)。

    然后分别循环子类的OnStartup方法。

  • 相关阅读:
    我的插件架构
    .net 处理图片亮度
    封装自己的对称加密模块
    漏洞无处不在之窃取你的QQ信息
    写自己的自动升级模块
    抓到一只网马,发文顺便鄙视下360
    .net 3.5的Socket异步完成端口
    检测本机是否登录了指定QQ账号
    C++/CLR写的Data Blocks
    修改的Vista风格多功能日历Demo
  • 原文地址:https://www.cnblogs.com/SunSAS/p/12268700.html
Copyright © 2020-2023  润新知