Spring技术Spring源码分析

八、SpringBoot启动配置原理

2019-04-24  本文已影响0人  木石前盟Caychen

重要的事件回调机制:

前两者需要配置在META-INF/spring.factories中

后两者只需要放在ioc容器中

启动流程:

7.1、创建SpringApplication对象

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

首先根据主类创建SpringApplication对象

public SpringApplication(Object... sources) {
    //初始化对象
    initialize(sources);
}

7.2、进行初始化工作

SpringApplication#initialize

private void initialize(Object[] sources) {
    if (sources != null && sources.length > 0) {
        //保存主配置类
        this.sources.addAll(Arrays.asList(sources));
    }
    //判断是否是web应用,源码#7.2.1
    this.webEnvironment = deduceWebEnvironment();   
    
    //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来,源码#7.2.2
    setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
    
    //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener,同上
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
    //从多个主配置类中找到有main方法的主类,源码#7.2.3
    this.mainApplicationClass = deduceMainApplicationClass();
}

#7.2.1:SpringApplication#deduceWebEnvironment

private static final String[] WEB_ENVIRONMENT_CLASSES = new String[]{"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;
}

从WEB_ENVIRONMENT_CLASSES集合中遍历元素判断当前环境中是否有web应用的两个重要的依赖。

#7.2.2:SpringApplication#getSpringFactoriesInstances

从类路径下的所有jar包里的META-INF/spring.factories文件中获取所有type类型的类

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 classLoader = Thread.currentThread().getContextClassLoader();
    
    //使用ClassLoader根据type来获取所有的value值并返回name组成的集合,源码#7.2.2.1
   Set<String> names = new LinkedHashSet<String>(
        SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    
    //根据name值利用反射机制得到name所在的类实例,源码#7.2.2.2
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
        classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

#7.2.2.1:SpringFactoriesLoader#loadFactoryNames

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

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();

    try {
        //从类路径下所有jar包中查找META-INF/spring.factories文件路径
        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 = (URL)urls.nextElement();
            
            //依次遍历所有的文件路径,从文件中获取key为classname对应value,并以逗号分隔加入到集合中
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        
        //返回类型集合
        return result;
    } catch (IOException var8) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                    "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

#7.2.2.2:SpringApplication#createSpringFactoriesInstances

private <T> List<T> createSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
            Set<String> names) {
    List<T> instances = new ArrayList<T>(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;
}

#7.2.3:SpringApplication#deduceMainApplicationClass

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;
}

以上代码完成SpringApplication对象创建。

所有的initializer集合,如图所示:

所有的initializer.png

所有的listener集合,如图所示:

以上两个示意图中的集合数据不一定一模一样,要看具体依赖 ,依赖其他模块,可能就不一样了。

7.3、运行run方法

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    FailureAnalyzers analyzers = null;
    configureHeadlessProperty();
    
    //获取SpringApplicationRunListeners,从类路径下找到META-INF/spring.factories配置的所有SpringApplicationRunListener,源码#7.3.1
    SpringApplicationRunListeners listeners = getRunListeners(args);
    
    //回调所有的SpringApplicationRunListener的starting方法,源码#7.3.2
    listeners.starting();
    
    try {
        //封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
        
        //准备环境:首先创建环境对象,创建完成后回调每个SpringApplicationRunListener对象的environmentPrepared方法,源码#7.3.3
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                                                                 applicationArguments);
        
        //打印Banner,源码#7.3.4
        Banner printedBanner = printBanner(environment);
        
        //创建ApplicationContext,决定创建web的ioc容器还是普通的ioc容器,具体原理看原来文章(此处略)
        context = createApplicationContext();
        
        analyzers = new FailureAnalyzers(context);
        
        //准备上下文,将environment保存到ioc容器中,源码#7.3.5
        //prepareContext方法内部:
        //首先applyInitializers(context);用来回调之前保存的所有的ApplicationContextInitializer的initialize方法
        //然后listeners.contextPrepared(context);用来回调所有的SpringApplicationRunListener的contextPrepared方法
        //最后listeners.contextLoaded(context);再回调所有的SpringApplicationRunListener的contextLoaded方法
        prepareContext(context, environment, listeners, applicationArguments,
                       printedBanner);
        
        //刷新ioc容器:首先创建ioc容器并初始化,如果是web应用还会创建嵌入式的Servlet容器,具体原理看原来文章(此处略)
        refreshContext(context);
        
        //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner类,源码#7.3.6
        //并先回调ApplicationRunner的run方法,再回调CommandLineRunner的run方法
        afterRefresh(context, applicationArguments);
        
        //执行所有的SpringApplicationRunListener的finished方法,源码#7.3.7
        listeners.finished(context, null);
        
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        
        //整个SpringBoot应用启动完成后返回ioc容器
        return context;
    }
    catch (Throwable ex) {
        handleRunFailure(context, listeners, analyzers, ex);
        throw new IllegalStateException(ex);
    }
}

#7.3.1:SpringApplication#getRunListeners

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

从类路径下找到所有META-INF/spring.factories文件中配置的所有SpringApplicationRunListener类,并保存到SpringApplicationRunListeners对象的listeners对象集合中

#7.3.2:SpringApplicationRunListeners#starting

public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

调用所有SpringApplicationRunListener对象的starting方法。

#7.3.3:SpringApplication#prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    //获取或者创建环境,源码#7.3.3.1
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    //配置环境对象,比如当前的profiles,源码#7.3.3.2
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    //调用每个SpringApplicationRunListener对象的environmentPrepared方法,源码#7.3.3.3
    listeners.environmentPrepared(environment);
    if (!this.webEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())
            .convertToStandardEnvironmentIfNecessary(environment);
    }

    //返回环境对象
    return environment;
}

#7.3.3.1:SpringApplication#getOrCreateEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {
   if (this.environment != null) {
       return this.environment;
   }
    if (this.webEnvironment) {
        return new StandardServletEnvironment();
    }
    return new StandardEnvironment();
}

在上面7.2章节中deduceWebEnvironment()方法返回是否是web环境标识,如果是web环境,webEnvironment则为true,否则为false。在此getOrCreateEnvironment()方法中根据webEnvironment的值创建环境对象,如果webEnvironment为true,则创建StandardServletEnvironment类型的环境对象,否则创建StandardEnvironment类型的环境对象。

#7.3.3.2:SpringApplication#configureEnvironment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    this.configurePropertySources(environment, args);
    
    //配置当前环境的profiles,默认为default
    this.configureProfiles(environment, args);
}

#7.3.3.3:SpringApplicationRunListeners#environmentPrepared

public void environmentPrepared(ConfigurableEnvironment environment) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.environmentPrepared(environment);
    }
}

调用所有SpringApplicationRunListener对象的environmentPrepared方法。

#7.3.4:SpringApplication#printBanner

private Banner printBanner(ConfigurableEnvironment environment) {
    //判断当前bannerMode是否为OFF
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    } else {
        ResourceLoader resourceLoader = (this.resourceLoader != null ? this.resourceLoader
                : new DefaultResourceLoader(getClassLoader()));
        
        //获取BannerPrinter打印对象
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
                resourceLoader, this.banner);
        
        //根据BannerMode的值,来打印Banner,源码#7.3.4.1
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }
}

#7.3.4.1:SpringApplicationBannerPrinter#print

public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    //获取Banner对象
    Banner banner = getBanner(environment, this.fallbackBanner);
    
    //依次调用Banners集合中的Banner对象的printBanner来开始打印Banner,源码#7.3.4.1.1
    banner.printBanner(environment, sourceClass, out);
    return new PrintedBanner(banner, sourceClass);
}

private Banner getBanner(Environment environment, Banner definedBanner) {
    Banners banners = new Banners();
    
    //从image图片格式中获取banner对象,如果有则保存到banners集合中
    banners.addIfNotNull(getImageBanner(environment));
    
    //从text文本格式中获取banner对象,如果有则保存到banners集合中
    banners.addIfNotNull(getTextBanner(environment));
    
    //banners集合个数只有0,1,2三种情况,然后判断banners集合是否为空,如果不为空,则返回之前获取到的Banners集合对象
    if (banners.hasAtLeastOneBanner()) {
        return banners;
    }
    if (this.fallbackBanner != null) {
        return this.fallbackBanner;
    }
    return DEFAULT_BANNER;
}

static final String BANNER_LOCATION_PROPERTY = "banner.location";
static final String DEFAULT_BANNER_LOCATION = "banner.txt";

private Banner getTextBanner(Environment environment) {
    //首先从环境对象中获取banner.location的值,如果存在直接返回该值,否则使用默认的banner.txt文件作为location的值
    String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
                DEFAULT_BANNER_LOCATION);
    
    //根据location的值获取Resource对象
    Resource resource = this.resourceLoader.getResource(location);
    
    //判断Resource是否存在,如果存在返回ResourceBanner,否则返回null
    if (resource.exists()) {
        return new ResourceBanner(resource);
    }
    return null;
}

static final String[] IMAGE_EXTENSION = new String[]{"gif", "jpg", "png"};
static final String BANNER_IMAGE_LOCATION_PROPERTY = "banner.image.location";

private Banner getImageBanner(Environment environment) {
    //首先从环境对象中获取banner.image.location的值,如果存在直接返回该值
    String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
    
    //判断是否有值
    if (StringUtils.hasLength(location)) {
        //如果banner.image.location有值,则根据该值返回Resource对象,并判断是否存在,如果存在则返回ImageBanner,否则返回null
        Resource resource = this.resourceLoader.getResource(location);
        return (resource.exists() ? new ImageBanner(resource) : null);
    }
    //如果banner.image.location没有值或者未设置,则依次判断banner.gif,banner.jpg,banner.png三种文件是否存在,如果某个文件存在,则直接返回该文件的ImageBanner对象,否则返回null
    for (String ext : IMAGE_EXTENSION) {
        Resource resource = this.resourceLoader.getResource("banner." + ext);
        if (resource.exists()) {
            return new ImageBanner(resource);
        }
    }
    return null;
}

#7.3.4.1.1:SpringApplicationBannerPrinter#printBanner

@Override
public void printBanner(Environment environment, Class<?> sourceClass,
                        PrintStream out) {
    for (Banner banner : this.banners) {
        //依次调用每个banner对象的pringBanner方法
        banner.printBanner(environment, sourceClass, out);
    }
}

ResourceBanner#printBanner

@Override
public void printBanner(Environment environment, Class<?> sourceClass,
                        PrintStream out) {
    try {
        String banner = StreamUtils.copyToString(this.resource.getInputStream(),
                                                 environment.getProperty("banner.charset", Charset.class,
                                                                         Charset.forName("UTF-8")));

        for (PropertyResolver resolver : getPropertyResolvers(environment,
                                                              sourceClass)) {
            banner = resolver.resolvePlaceholders(banner);
        }
        out.println(banner);
    }
    catch (Exception ex) {
        //other code...
    }
}

ImageBanner#printBanner

@Override
public void printBanner(Environment environment, Class<?> sourceClass,
                        PrintStream out) {
    String headless = System.getProperty("java.awt.headless");
    try {
        System.setProperty("java.awt.headless", "true");
        printBanner(environment, out);
    }
    //catch...finally...
}

#7.3.5:SpringApplication#prepareContext

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
    context.setEnvironment(environment);
    postProcessApplicationContext(context);
    
    //回调所有的initializer对象的initialize方法,源码#7.3.5.1
    applyInitializers(context);
    
    //回调所有的listener对象的contextPrepared方法,源码#7.3.5.2
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }

    //other code...
    
    //回调所有的listener对象的contextLoaded方法,源码#7.3.5.3
    listeners.contextLoaded(context);
}

#7.3.5.1:SpringApplication#applyInitializers

protected void applyInitializers(ConfigurableApplicationContext context) {
    //依次遍历所有的ApplicationContextInitializer对象,调用其initialize方法
    for (ApplicationContextInitializer initializer : getInitializers()) {
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
            initializer.getClass(), ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        initializer.initialize(context);
    }
}

#7.3.5.2:SpringApplicationRunListeners#contextPrepared

public void contextPrepared(ConfigurableApplicationContext context) {
    //依次遍历所有的SpringApplicationRunListener对象,调用其contextPrepared方法
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.contextPrepared(context);
    }
}

#7.3.5.3 : SpringApplicationRunListeners#contextLoaded

public void contextPrepared(ConfigurableApplicationContext context) {
    //依次遍历所有的SpringApplicationRunListener对象,调用其contextPrepared方法
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.contextPrepared(context);
    }
}

#7.3.6:SpringApplication#afterRefresh

protected void afterRefresh(ConfigurableApplicationContext context,
            ApplicationArguments args) {
    //调用所有的xxxRunner的run方法
    callRunners(context, args);
}

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<Object>();
    //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner类
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    
    //先回调所有ApplicationRunner对象的run方法,在回调所有CommandLineRunner对象的run方法
    for (Object runner : new LinkedHashSet<Object>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

#7.3.7:SpringApplicationRunListeners#finished

public void finished(ConfigurableApplicationContext context, Throwable exception) {
    //依次遍历所有的SpringApplicationRunListener对象,调用其finished方法
    for (SpringApplicationRunListener listener : this.listeners) {
        callFinishedListener(listener, context, exception);
    }
}

private void callFinishedListener(SpringApplicationRunListener listener,
            ConfigurableApplicationContext context, Throwable exception) {
    try {
        listener.finished(context, exception);
    }
    catch (Throwable ex) {
        //other code...
    }
}

这样整个SpringBoot应用启动就完成并返回ioc容器。

7.4、测试原理用例

分别编写四个事件回调类的子类:

ApplicationContextInitializer子类:HelloApplicationContextInitializer

public class HelloApplicationContextInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("HelloApplicationContextInitializer...initialize...");
    }
}

SpringApplicationRunListener子类:HelloSpringApplicationRunListener

public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {

    //SpringApplicationRunListener子类必须有一个有参构造函数,参数分别是SpringApplication和String[]
    public HelloSpringApplicationRunListener(SpringApplication springApplication, String[] args){
        System.out.println("HelloSpringApplicationRunListener...constructor...");
    }
    
    @Override
    public void starting() {
        System.out.println("HelloSpringApplicationRunListener...starting...");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("HelloSpringApplicationRunListener...environmentPrepared...");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("HelloSpringApplicationRunListener...contextPrepared...");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("HelloSpringApplicationRunListener...contextLoaded...");
    }

    @Override
    public void finished(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("HelloSpringApplicationRunListener...finished...");
    }
}

ApplicationRunner子类:HelloApplicationRunner

@Component
public class HelloApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("HelloApplicationRunner...run...");
    }
}

CommandLineRunner子类:HelloCommandLineRunner

@Component
public class HelloCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("HelloCommandLineRunner...run...");
    }
}

启动服务器之后,查看控制台输出的信息(忽略Spring Boot打印信息):

HelloSpringApplicationRunListener...constructor...
HelloSpringApplicationRunListener...starting...
HelloSpringApplicationRunListener...environmentPrepared...
HelloApplicationContextInitializer...initialize...
HelloSpringApplicationRunListener...contextPrepared...
HelloSpringApplicationRunListener...contextLoaded...
HelloApplicationRunner...run...
HelloCommandLineRunner...run...
HelloSpringApplicationRunListener...finished...

其结果跟源码分析过程一致。

上一篇下一篇

猜你喜欢

热点阅读