• springboot源码(四)


    springboot入口run方法细节分析

     上一篇主要说了一下SpringApplication的构造方法和 run 方法里面都做了哪些事情,这一篇具体分析一下里面的主要方法。

    1、//将spring.factories中key为ApplicationContextInitializer对应的类型实例化后放到成员变量initializers里
       this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

    分析一下该方法:

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = getClassLoader();
            // type=ApplicationContextInitializer  加载spring.factories中key为ApplicationContextInitializer,将全类路径名存放到names中
            Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 根据names中的全类路径名创建实例 List
    <T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); 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; }

    2、//将spring.factories中key为ApplicationListener的对应类型实例化后放到SpringApplication的成员变量listener里
       this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

    分析一下:

    大致过程跟setInitializers()方法是一样的,就是把spring.factories中的ApplicationListener的对应类型的实例化放到SpringApplication的成员变量listeners中。

    3、//反推main方法所在的类对象,并记录在mainApplicationClass中
          this.mainApplicationClass = this.deduceMainApplicationClass();

    分析一下如何反推回main方法所在的class对象的:

    StackTrace:

          我们在学习函数调用时,就知道了每个函数都拥有自己的栈空间。

          一个函数被调用时,就创建一个新的栈空间,那么通过函数的嵌套调用最后就形成了一个函数调用堆栈。

         所以,StackTrace就是记录了程序方法执行的链路。

    debug形式查看函数调用栈:

    private Class<?> deduceMainApplicationClass() {
            try {
    //获取当前方法执行的堆栈信息 StackTraceElement[] stackTrace
    = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) {
    //判断是否是main方法,如果是返回main方法对应的class对象
    if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }

    4、分析run方法中的比较重要的方法

     //加载SpringApplicationRunListener得到事件发布器EventPublishingRunListener,会把SpingringApplication中的成员变量listener放到listeners中
     SpringApplicationRunListeners listeners = this.getRunListeners(args);
    private SpringApplicationRunListeners getRunListeners(String[] args) {
    //声明了一个参数类型数组,其中有一个是SpringApplication类型 Class
    <?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    //将参数数组types作为参数传递给很熟悉的getSpringFactoriesInstances()方法
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = getClassLoader();
            // 加载spring.factories中SpringApplicationRunListener类型:EventPublishingRunListener(事件发布器)
            Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //创建EventPublishingRunlistener实例 List
    <T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); 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);
    //EventPublishingRunlistener的构造器参数分别为SpringApplication和String[],所以EventPublishingRunListener事件发布器就加载到所有SpringApplication中listeners变量中的全部ApplicationListener 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; }
    //EventPublishingRunlistener类源码
    public
    class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { private final SpringApplication application; private final String[] args; private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } }

    到这,基本上就知道了run方法都大致干了些什么勾当。下一篇分析springboot监听器的设计。


  • 相关阅读:
    C#中的委托是什么?事件是不是一种委托?
    SQL重点复习
    数据库生成脚本
    用Winfrom动态生成SQL的insert语句
    如何实现远程连接SQL Server 2008 Express
    跨页面传送
    win7 防火墙开启ping
    关于*.class和*.jar的几个基本认识
    使用cobertura确定测试代码的覆盖率
    Java学习笔记之I/O
  • 原文地址:https://www.cnblogs.com/bentuzi/p/16069857.html
Copyright © 2020-2023  润新知