Spring boot 启动原理以及加载Bean(一)

2020-01-08  本文已影响0人  多喝热水丶
// 代码入口 
// 调用SpringApplication.run 方法
public static void main(String[] args) throws IOException { 
   SpringApplication.run(SpringCloudBaseApplication.class, args);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        // 判断加载主类是否为空
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // 加载主类,这里使用Set 可知可以有多个主类实例
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 1.判断是否是web环境(1.WebFlux 2.servlet 3.None)
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 初始化ApplicationContextInitializer的所有实现类
        // ApplicationContextInitializer 会在
        // ConfigurableApplicationContext(容器) refresh() 之前进行一些初始化
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        // 初始化ApplicationListener的监听器 run会触发这些监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //  推断引用主类,通过判断方法名称是否是Main方法判断主类
        this.mainApplicationClass = 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;
    }

// 判断是否是web环境(1.WebFlux 2.servlet 3.None)
static WebApplicationType deduceFromClasspath() {
        //判断当前ClassLoader 中是否存在webFlux类,并且不存在WebServlet
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        // 判断是否是web项目,如果不是则返回None(简单的java程序)
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        // 如果以上条件不成立则返回是Servlet
        return WebApplicationType.SERVLET;
    }

  // 监听器以及初始化类都调用getSpringFactoriesInstances
  // 这个方法用于加载所有的spring.factories 文件中的类
private <T> Collection<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<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 创建加载过的Object实例 
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        // 根据@Order(value) 注解所指定的值进行排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
}
// 代码简单就不多做解释
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
            Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass
                        .getDeclaredConstructor(parameterTypes);
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException(
                        "Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    // 用传入的Class type 作为 Key ,当所有的类加载成功后使用key进行筛选相应的类
    String factoryClassName = factoryClass.getName();
    // loadSpringFactories 加载spring.factories 文件的核心方法 getOrDefault 根据 key 获取相应的value
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 缓存所有加载spring.factories的文件 (由于多次调用 loadSpringFactories) 2.0.x 这一块新增缓存功能
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
// 加载所有的spring.factories 并添加到缓存map中
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        // 如果当前map中有数据则直接返回
        if (result != null) {
            return result;
        }

        try {
            // 所以的URL都将储存在这里
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            // 循环所有URL元素
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                // 根据url 获取相应的资源
                UrlResource resource = new UrlResource(url);
                // 加载文件转换成Properties 对象 (接口路径为key,value 是所有的实现类逗号隔开)
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                //  将所有的value,隔开的 解析为List对象 并且放入 result map对象中
                    List<String> factoryClassNames = Arrays.asList(
                            StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
                    result.addAll((String) entry.getKey(), factoryClassNames);
                }
            }
            // 同时也加入cache对象中以便下次使用
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
public ConfigurableApplicationContext run(String... args) {
         // 计时器,用于最后打印Spring boot 最终的运行时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 初始化容器
        ConfigurableApplicationContext context = null;
        // 错误信息报告集合
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        // 配置属性 设置 java.awt.headless 系统属性为true
        /*如果名字为java.awt.headless的系统属性被设置true,那么headless工具包就会被使用。应用程序可以执行如下操作:
        (1)创建轻量级组件。
        (2)收集关于可用的字体、字体指标和字体设置的信息。
        (3)设置颜色来渲染准备图片。
        (4)创造和获取图像,为渲染准备图片。
        (5)使用java.awt.PrintJob,java.awt.print.*,和javax.print.*类里德打印。 */
        configureHeadlessProperty();
         // 获取运行时监听器 SpringApplicationRunListener  
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 启动监听器
        listeners.starting();
        try {
            // 设置参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            // 环境准备加载配置文件 另起文章->
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            //  设置 spring.beaninfo.ignore 为true 
            configureIgnoreBeanInfo(environment);
            // 打印Spring Boot Banner
            Banner printedBanner = printBanner(environment);
            // 创建上下文对象了 -> 另起文章
            context = createApplicationContext();
           //  获取并打印Spring boot 在运行中的异常信息 ->另起文章
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            // 环境上下文准备 ->核心点 另起文章
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            // 刷新容器扫描加载bean -> 另起文章
            refreshContext(context);
            // 后置处理
            afterRefresh(context, applicationArguments);
            // run方法 运行完毕 停止计时器
            stopWatch.stop();
            if (this.logStartupInfo) {
                // 打印最终启动时间日志
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }
上一篇下一篇

猜你喜欢

热点阅读