• SpringBoot的启动流程分析(1)


    通过分析我们可以找到 org.springframework.boot.SpringApplication 中如下,

        public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
            return new SpringApplication(sources).run(args);
        }

    可以看出,SpringBoot的启动分两步 1:实例化一个SpringApplication对象 2:run

    初始化的方法如下:

    private void initialize(Object[] sources) {
            if (sources != null && sources.length > 0) {
                this.sources.addAll(Arrays.asList(sources));
            }
            this.webEnvironment = deduceWebEnvironment();    //设置当前为web环境
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }
    deduceWebEnvironment()方法会判断包路径下是否存在 "javax.servlet.Servlet" 和 "org.springframework.web.context.ConfigurableWebApplicationContext",如果存在,则设置当前环境为Web环境,源码如下
    private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
                "org.springframework.web.context.ConfigurableWebApplicationContext" };
    
        private boolean deduceWebEnvironment() {
            for (String className : WEB_ENVIRONMENT_CLASSES) {
                if (!ClassUtils.isPresent(className, null)) {
                    return false;
                }
            }
            return true;
        }
    setInitializers()方法用来设置SpringApplication启动时需要的类
    setListeners()用来设置SpringApplication启动时需要的监听器,
    这两个方法都用到了
    getSpringFactoriesInstances()方法,那我们来分析一下这个方法的相关源码
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
        private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
            return getSpringFactoriesInstances(type, new Class<?>[] {});
        }
    
        private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
                Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // Use names and ensure unique to protect against duplicates
            Set<String> names = new LinkedHashSet<String>(
                    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                    classLoader, args, names);
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }
    
        public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            try {
                Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                List<String> result = new ArrayList<String>();
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
                return result;
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                        "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
        }

    通过上面的代码我们可以看出,getSpringFactoriesInstances() 方法会从 "META-INF/spring.factories" 这个文件中读取需要的类型实例化后注入到SpringApplication中,我们截取springboot中"META-INF/spring.factories" 中 ApplicationContextInitializer.class和 

    ApplicationListener.class类型的类如下

    # Application Context Initializers
    org.springframework.context.ApplicationContextInitializer=
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
    org.springframework.boot.context.ContextIdApplicationContextInitializer,
    org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
    org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
    # Application Listeners
    org.springframework.context.ApplicationListener=
    org.springframework.boot.ClearCachesApplicationListener,
    org.springframework.boot.builder.ParentContextCloserApplicationListener,
    org.springframework.boot.context.FileEncodingApplicationListener,
    org.springframework.boot.context.config.AnsiOutputApplicationListener,
    org.springframework.boot.context.config.ConfigFileApplicationListener,
    org.springframework.boot.context.config.DelegatingApplicationListener,
    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,
    org.springframework.boot.logging.ClasspathLoggingApplicationListener,
    org.springframework.boot.logging.LoggingApplicationListener
    deduceMainApplicationClass()将启动类设置为我们自己定义的启动类,它是用过读取程序的栈,并分析栈的方法是否为main来判断的,源码如下
        private Class<?> deduceMainApplicationClass() {
            try {
                StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
                for (StackTraceElement stackTraceElement : stackTrace) {
                    if ("main".equals(stackTraceElement.getMethodName())) {
                        return Class.forName(stackTraceElement.getClassName());
                    }
                }
            }
            catch (ClassNotFoundException ex) {
                // Swallow and continue
            }
            return null;
        }

    那么以上就是SpringApplication初始化完成的事情,限于篇幅,我们在下一章介绍run的过程

     
     
  • 相关阅读:
    Spring Cloud Gateway 使用
    Spring Cloud Stream 整合 RabbitMQ
    机器学习知识总结---1、回归和分类是可以相互转换的
    23个适合Java开发者的大数据工具和框架
    serilog Getting Started
    NLog.Targets.ElasticSearch
    RollingFileAppender bufferSize is not working? Here is an alternative
    go微服务示例(k8s istio grpc swagger postgres增量更新sql等功能)
    undefined: grpc.SupportPackageIsVersion6 和 undefined: grpc.ClientConnInterface 解决办法
    micrometer埋点(Spring boot 2.X metrics)
  • 原文地址:https://www.cnblogs.com/wanghaoyang/p/10600157.html
Copyright © 2020-2023  润新知