IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot 启动类 源码解析 (一 .new SpringApplication 解析) -> 正文阅读

[Java知识库]SpringBoot 启动类 源码解析 (一 .new SpringApplication 解析)


 // * 方法为重要的方法 不加 * 的可以不看 意义不大

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class CmasApplication
{
    public static void main(String[] args)
    {
        // 点击run方法进入
        SpringApplication.run(CmasApplication.class, args);
    }
}

public class SpringApplication {

    // run 方法
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }

    //  通过 run 方法进入 1. new了 一个 SpringApplication 对象  2.调用 run 方法
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        // 点击 进入  new SpringApplication 的方法 
        return new SpringApplication(primarySources).run(args);
    }

    
    // new SpringApplication 的方法
    public SpringApplication(Class<?>... primarySources) {
        // 进入 this 方法
        this(null, primarySources);
    }

    // this 方法
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // resourceLoader 资源加载器
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // primarySources 就是当前启动类 CmasApplication
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 该方法表示 当前的web应用类型是否是web项目,debugger返回为 servlet 类型   点击进入 deduceFromClasspath 
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // * 设置初始化器 从方法名推断 会 set 一个 初始化器的集合 进入 getSpringFactoriesInstances 方法
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // * 设置监听器 会 set 一个 监听器的集合
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 推断主启动类  也就是我们的 CmasApplication
        this.mainApplicationClass = deduceMainApplicationClass();
    }

    // 获取工厂实例
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }
    // 获取工厂实例
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        // 获取类加载器 (不重要)从类加载器可以知道加载到的所有class文件
        ClassLoader classLoader = getClassLoader();
        // 根据类型 加载工厂名称放到集合里(也就是全路径的类名称)参数类型 type = ApplicationContextInitializer.class 可以推断是获取上下文相关的初始化器
        // debugger 可以看到 返回8个初始化器(org.springframework.boot.devtools.restart.RestartScopeInitializer...) 
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // * 通过名称创建 对应的实例 放到集合里 最终返回8个实例对象
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        // 对实例进行排序,有Order 按照order 排序 没有就按照原本的顺序进行排序  我 debugger 后,结果不是这样,很尴尬 这个排序没懂
        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 <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");
        try {
            ReflectionUtils.makeAccessible(ctor);
            if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
                return KotlinDelegate.instantiateClass(ctor, args);
            }
            else {
                Class<?>[] parameterTypes = ctor.getParameterTypes();
                Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
                Object[] argsWithDefaultValues = new Object[args.length];
                for (int i = 0 ; i < args.length; i++) {
                    if (args[i] == null) {
                        Class<?> parameterType = parameterTypes[i];
                        argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
                    }
                    else {
                        argsWithDefaultValues[i] = args[i];
                    }
                }
                // 通过构造器 返回实例对象
                return ctor.newInstance(argsWithDefaultValues);
            }
        }
        catch (InstantiationException ex) {
            throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
        }
        catch (IllegalArgumentException ex) {
            throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
        }
        catch (InvocationTargetException ex) {
            throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
        }
    }

    private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                // 从堆栈信息查看该文件是否半酣 main 方法
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }


}

 public final class SpringFactoriesLoader {

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";


    // 根据类型获取工厂名 也就是全路径的类名 factoryType = ApplicationContextInitializer.class
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        // 进入方法  META-INF/spring.factories 路径下的所有文件 并通过 getOrDefault 方法进行过滤 (containsKey(key) 文件中的key是否包含 factoryTypeName)
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            // classLoader 里面可以获取到已经加载的所有class 类文件 从类文件根据文件名获取 所有 META-INF/spring.factories 路径下的所有文件
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
}


public enum WebApplicationType {

    /**
     * 该应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器
     */
    NONE,

    /**
     * 该应用程序应该作为基于 servlet 的 Web 应用程序运行,并且应该启动一个嵌入式 servlet Web 服务器
     */
    SERVLET,

    /**
     * 该应用程序应作为响应式 Web 应用程序运行,并应启动 * 嵌入式响应式 Web 服务器
     */
    REACTIVE;

    //  web 项目包含的 类 
    private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
            "org.springframework.web.context.ConfigurableWebApplicationContext" };

    // 进入 deduceFromClasspath
    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;
        }
        // SERVLET_INDICATOR_CLASSES 是个数组 判断 ClassUtils 是否包含 该数组元素 不包含咋返回 NONE
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        // 包含一个 则返回 SERVLET
        return WebApplicationType.SERVLET;
    }
}


总结一下:
1.创建自身实例对象
2.推断是否为web项目
3.设置所有初始化器 设置监听器 (中途 在调用 loadSpringFactories时读取了类路径下所有META-INF/spring.factories下内容,并全部缓存到了SpringFactoriesLoader的cache缓存中)
4.推断主启动类

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:07:36  更:2022-03-16 22:10:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:37:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码