美文网首页
SpringApplication启动流程一

SpringApplication启动流程一

作者: 程序员札记 | 来源:发表于2023-04-22 13:01 被阅读0次

    研究源码的目的其实是为了更好的使用,和更好的扩展,当然是为了实际项目服务,解决问题,不是为了看而看,只有真正了解了原理,你才可以用的得心应手,出了问题也不怕,万变不离其宗。

    初始化基本流程


    image.png

    SpringApplication.run

    我们从最简单的例子开始,就这些东西,我们看看SpringApplication.run到底做了什么事。


    image.png

    内部还有run:


    image.png

    这次是关键:


    image.png

    #SpringApplication构造方法


    image.png

    首先创建一个集合存放我们传进去的类,然后推断应用程序的类型,是SERVLET,还是REACTIVE,然后获取很多jar包下的META-INF/spring.factories中的org.springframework.context.ApplicationContextInitializer属性的值和org.springframework.context.ApplicationListener属性的值,其实他们是接口,他们的值就是其实就是实现类,也就是说要获取这些接口的实现类,来做一些初始化工作,当然里面会做一些筛选,去重。然后推断出main方法的类,他用了一种很巧妙的方式,抛出一个异常,然后再方法栈里找有main方法的那个类,具体的细节后面会说。

        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
            setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }
    

    WebApplicationType的deduceFromClasspath推断Web应用程序类型

    要对照这些类看:


    image.png

    这个逻辑我就不讲了,就是排他的,要么REACTIVE,要么SERVLET,要么就普通的。具体是根据Class.forName反射的,而且如果一次不行,还会进行内部类的反射,否没有的话才捕获异常,返回false。可以看到如果同时有REACTIVE和SERVLET的相关类,会判定是SERVLET。

    static WebApplicationType deduceFromClasspath() {
            if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                    && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
                return WebApplicationType.REACTIVE;
            }
            for (String className : SERVLET_INDICATOR_CLASSES) {
                if (!ClassUtils.isPresent(className, null)) {
                    return WebApplicationType.NONE;
                }
            }
            return WebApplicationType.SERVLET;
        }
    

    ClassUtils的isPresent是否存在类型

    5.2.5的版本这个类有更新,来看下怎么判断有没有某个类型:

        public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
            try {
                forName(className, classLoader);
                return true;
            }
            catch (IllegalAccessError err) {
                throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
                        className + "]: " + err.getMessage(), err);
            }
            catch (Throwable ex) {
                // Typically ClassNotFoundException or NoClassDefFoundError...
                return false;//没有就返回false
            }
        }
    

    ClassUtils的forName
    留下了主要的代码,Class.forName了两次,一次是一般类,一次是内部类,都没有就抛异常。

    public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
                throws ClassNotFoundException, LinkageError {
    
            ...
            ClassLoader clToUse = classLoader;
            if (clToUse == null) {
                clToUse = getDefaultClassLoader();
            }
            try {
                return Class.forName(name, false, clToUse);
            }
            catch (ClassNotFoundException ex) {
                int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
                if (lastDotIndex != -1) {
                    String innerClassName =
                            name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
                    try {
                        return Class.forName(innerClassName, false, clToUse);
                    }
                    catch (ClassNotFoundException ex2) {
                        // Swallow - let original exception get through
                    }
                }
                throw ex;
            }
        }
    
    

    相关文章

      网友评论

          本文标题:SpringApplication启动流程一

          本文链接:https://www.haomeiwen.com/subject/gjysjdtx.html