SpringBoot源码分析二(启动流程原理)

SpringBoot源码分析二(启动流程原理),第1张

SpringBoot源码分析二(启动流程原理) Spring Boot源码分析二(启动流程原理)

文章目录

Spring Boot源码分析二(启动流程原理)

入口

**SpringApplication**的构造器设置应用类型设置初始化器设置监听器(Listener) SpringApplication.run方法

获取并启动监听器环境构建创建容器Spring容器前置处理

调用初始化器**加载启动指定类**通知监听器,容器已准备就绪 刷新上下文Spring容器后置处理发出结束执行的事件执行Runners

入口
@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

**SpringApplication.run(MyApplication.class, args);**跟进去

public static ConfigurableApplicationContext run(Class primarySource, String... args) {
		return run(new Class[] { primarySource }, args);
	}

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

首先会 new 一个SpringApplication的实例,并将启动类作为参数传进去,执行他的run方法。

SpringApplication的构造器

设置应用类型

主要通过类加载器判断 REACTIVE 相关的Class是否存在,如果不存在,则web环境即为 SERVLET 类型。这里设置好web环境类型,在后面根据类型初始化对应环境。

spring-boot-starter-web 的pom会引入Tomcat和spring-webmvc,如下


      org.springframework.boot
      spring-boot-starter-tomcat
      2.6.2
      compile
    
	
      org.springframework
      spring-webmvc
      5.3.14
      compile
    

spring-webmvc中存在DispatcherServlet这个类,也就是我们以前SpringMvc的核心Servlet,通过类加载能加载DispatcherServlet这个类,那么我们的应用类型自然就是WebApplicationType.SERVLET

设置初始化器
// 设置初始化器(Initializer),最后会调用这些初始化器
setInitializers((Collection)
getSpringFactoriesInstances(ApplicationContextInitializer.class));

这个方法会尝试从类路径的meta-INF/spring.factories处读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot-autoconfigure这个包为例,它的meta-INF/spring.factories部分定义如下所示:

这两个类名会被读取出来,然后放入到Set集合中,准备开始下面的实例化 *** 作:

// parameterTypes: 上一步得到的names集合
private  List createSpringFactoriesInstances(Class type,
        Class[] parameterTypes, ClassLoader classLoader, Object[] args,
        Set names) {
    List instances = new ArrayList(names.size());
    for (String name : names) {
        try {
            Class instanceClass = ClassUtils.forName(name, classLoader);
            //确认被加载类是ApplicationContextInitializer的子类
            Assert.isAssignable(type, instanceClass);
            Constructor constructor = instanceClass.getDeclaredConstructor(parameterTypes);
            //反射实例化对象
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            //加入List集合中
            instances.add(instance);
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException(
                    "Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}

确认被加载的类确实是org.springframework.context.ApplicationContextInitializer的子类,然后就是得到构造器进行初始化,最后放入到实例列表中。

因此,所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,这个接口是这样定义的:

public interface ApplicationContextInitializer {

    void initialize(C applicationContext);

}

在Spring上下文被刷新之前进行初始化的 *** 作。典型地比如在Web应用中,注册Property Sources或者是激活Profiles。Property Sources比较好理解,就是配置文件。Profiles是Spring为了在不同环境下(如DEV,TEST,PRODUCTION等),加载不同的配置项而抽象出来的一个实体。

设置监听器(Listener)

下面开始设置监听器:

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

我们还是跟进代码看看getSpringFactoriesInstances

// 这里的入参type是:org.springframework.context.ApplicationListener.class
private  Collection getSpringFactoriesInstances(Class type) {
    return getSpringFactoriesInstances(type, new Class[] {});
}

private  Collection getSpringFactoriesInstances(Class type,
        Class[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set names = new linkedHashSet(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

可以发现,这个加载相应的类名,然后完成实例化的过程和上面在设置初始化器时如出一辙,同样,还是以spring-boot-autoconfigure这个包中的spring.factories为例,看看相应的Key-Value:

org.springframework.context.ApplicationListener=
org.springframework.boot.autoconfigure.BackgroundPreinitializer

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.context.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.context.logging.LoggingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

这10个监听器会贯穿springBoot整个生命周期。至此,对于SpringApplication实例的初始化过程就结束了。

SpringApplication.run方法

完成了SpringApplication实例化,开始调用 run 方法。

第一步:获取并启动监听器第二步:根据SpringApplicationRunListeners以及参数来准备环境第三步:创建上下文第四步:预处理上下文第五步:刷新上下文第六步:再刷新上下文第七步:发出结束执行的事件第八步:执行Runners 获取并启动监听器

获取监听器

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class[] types = new Class[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}

这里仍然利用了getSpringFactoriesInstances方法来获取实例,大家可以看看前面的这个方法分析,从meta-INF/spring.factories中读取Key为org.springframework.boot.SpringApplicationRunListener的Values:

org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener

getSpringFactoriesInstances中反射获取实例时会触发EventPublishingRunListener的构造函数,我们来看看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();
        Iterator var3 = application.getListeners().iterator();

        while(var3.hasNext()) {
            ApplicationListener listener = (ApplicationListener)var3.next();
            //将上面设置到SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中
            this.initialMulticaster.addApplicationListener(listener);
        }

    }
    //略...
}

我们看到**EventPublishingRunListener里面有一个广播器,EventPublishingRunListener 的构造方法将SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中,**我们来看看是如何添加到广播器:

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
    //广播器的父类中存放保存监听器的内部内
    private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false);

    @Override
    public void addApplicationListener(ApplicationListener listener) {
        synchronized (this.retrievalMutex) {
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
            //内部类对象
            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

    private class ListenerRetriever {
        //保存所有的监听器
        public final Set> applicationListeners = new linkedHashSet();
        public final Set applicationListenerBeans = new linkedHashSet();
        private final boolean preFiltered;

        public ListenerRetriever(boolean preFiltered) {
            this.preFiltered = preFiltered;
        }

        public Collection> getApplicationListeners() {
            linkedList> allListeners = new linkedList();
            Iterator var2 = this.applicationListeners.iterator();

            while(var2.hasNext()) {
                ApplicationListener listener = (ApplicationListener)var2.next();
                allListeners.add(listener);
            }

            if (!this.applicationListenerBeans.isEmpty()) {
                BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();
                Iterator var8 = this.applicationListenerBeans.iterator();

                while(var8.hasNext()) {
                    String listenerBeanName = (String)var8.next();

                    try {
                        ApplicationListener listenerx = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (this.preFiltered || !allListeners.contains(listenerx)) {
                            allListeners.add(listenerx);
                        }
                    } catch (NoSuchBeanDefinitionException var6) {
                        ;
                    }
                }
            }

            AnnotationAwareOrderComparator.sort(allListeners);
            return allListeners;
        }
    }
    //略...
}

上述方法定义在SimpleApplicationEventMulticaster父类AbstractApplicationEventMulticaster中。关键代码为this.defaultRetriever.applicationListeners.add(listener);,这是一个内部类,用来保存所有的监听器。也就是在这一步,将spring.factories中的监听器传递到SimpleApplicationEventMulticaster中。我们现在知道EventPublishingRunListener中有一个广播器SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster广播器中又存放所有的监听器。

启动监听器

我们上面一步通过getRunListeners方法获取的监听器为EventPublishingRunListener,从名字可以看出是启动事件发布监听器,主要用来发布启动事件。

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    private final SpringApplication application;
    private final String[] args;
    private final SimpleApplicationEventMulticaster initialMulticaster;

我们先来看看SpringApplicationRunListener这个接口

package org.springframework.boot;
public interface SpringApplicationRunListener {

    // 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
    void starting();
    // 当environment构建完成,ApplicationContext创建之前,该方法被调用
    void environmentPrepared(ConfigurableEnvironment environment);
    // 当ApplicationContext构建完成时,该方法被调用
    void contextPrepared(ConfigurableApplicationContext context);
    // 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
    void contextLoaded(ConfigurableApplicationContext context);
    // 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
    void started(ConfigurableApplicationContext context);
    // 在run()方法执行完成前该方法被调用
    void running(ConfigurableApplicationContext context);
    // 当应用运行出错时该方法被调用
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

SpringApplicationRunListener接口在Spring Boot 启动初始化的过程中各种状态时执行,我们也可以添加自己的监听器,在SpringBoot初始化时监听事件执行自定义逻辑,我们先来看看SpringBoot启动时第一个启动事件listeners.starting():

@Override
public void starting() {
    //关键代码,先创建application启动事件`ApplicationStartingEvent`
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

这里先创建了一个启动事件ApplicationStartingEvent,我们继续跟进SimpleApplicationEventMulticaster,有个核心方法:

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    //通过事件类型ApplicationStartingEvent获取对应的监听器
    for (final ApplicationListener listener : getApplicationListeners(event, type)) {
        //获取线程池,如果为空则同步处理。这里线程池为空,还未没初始化。
        Executor executor = getTaskExecutor();
        if (executor != null) {
            //异步发送事件
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            //同步发送事件
            invokeListener(listener, event);
        }
    }
}

这里会根据事件类型ApplicationStartingEvent获取对应的监听器,在容器启动之后执行响应的动作。

环境构建
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

跟进去:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		// 获取对应的 ConfigurableEnvironment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		// 配置
    	configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
		listeners.environmentPrepared(bootstrapContext, environment);
		DefaultPropertiesPropertySource.moveToEnd(environment);
		Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
				"Environment prefix cannot be set via properties.");
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = convertEnvironment(environment);
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
创建容器
context = createApplicationContext();

这里是根据webApplicationType 进行判断的,该类型为SERVLET类型,会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext 。webApplicationType之前在构造器中有获取过。

Spring容器前置处理
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

调用初始化器

这里用到了在创建SpringApplication实例时设置的初始化器了,依次对它们进行遍历,并调用initialize方法。当然,我们也可以自定义初始化器,并实现initialize方法,然后放入 meta-INF/spring.factories 配置文件中 key 为org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器 就会被调用,使我们项目初始化的一种方式。

加载启动指定类

这里也就是获取 this.primarySources 属性,也就是我们的启动类 MyApplication.class,接着看 load(context, sources.toArray(new Object[0])); 方法。

后续会出一篇文章详细介绍启动类是如何加载,以及自动化配置开启的详细流程。

通知监听器,容器已准备就绪
listeners.contextLoaded(context);

这里主要针对一些日志等监听器的响应处理。

刷新上下文
refreshContext(context);

这行到这里,SpringBoot相关的处理工作已经结束,接下的工作就交给了Spring。

refresh 方法是实现ioc 和 aop的关键,后续也会出文章进行详细分析。

Spring容器后置处理
afterRefresh(context, applicationArguments);

扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其他后置处理。

发出结束执行的事件
listeners.started(context, timetakenToStartup);

获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传进去了,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext 的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的11个监听器发布启动事件。

执行Runners
callRunners(context, applicationArguments);

spring boot提供的2个供用户自己拓展的接口:ApplicationRunner和CommandLineRunner。实现其run方法,并注入到Spring容器中,在SpringBoot启动完成后,会执行所有的runner的run方法。可以在容器启动完毕后(上下文刷新后)执行,做一些类似数据初始化的 *** 作。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List runners = new ArrayList();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//从上下文中获取ApplicationRunner类型的bean
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//从上下文中获取CommandLineRunner类型的bean
        AnnotationAwareOrderComparator.sort(runners);//排序
        for (Object runner : new linkedHashSet(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);//执行
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }
 

两个区别在于入参不同,可以根据自己的实际情况进行选择。

public interface CommandLineRunner {
     void run(String... args) throws Exception;
}
 
public interface ApplicationRunner {
     void run(ApplicationArguments args) throws Exception;
 
}

CommandLineRunner中执行参数是原始的java启动类main方法的String[] args字符串数组参数;ApplicationRunner中的参数经过处理提供一些方法例如: List getOptionValues(String name);

        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}
两个区别在于入参不同,可以根据自己的实际情况进行选择。

```java
public interface CommandLineRunner {
     void run(String... args) throws Exception;
}
 
public interface ApplicationRunner {
     void run(ApplicationArguments args) throws Exception;
 
}

CommandLineRunner中执行参数是原始的java启动类main方法的String[] args字符串数组参数;ApplicationRunner中的参数经过处理提供一些方法例如: List getOptionValues(String name);

根据名称获取值list,java 启动命令中 --foo=bar --foo=baz,则根据foo参数名返回list["bar", "baz"]

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5707515.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)