Back to Javatutorial

SpringBoot启动流程(一):准备SpringApplication

docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(一):准备SpringApplication.md

1.0.09.8 KB
Original Source

̽ springboot ģʹõ demo λ?gitee/funcy.

1. ?Demo01Application#main(...)

springboot ʽdz򵥣һУ

@SpringBootApplication
public class Demo01Application {

    public static void main(String[] args) {
        // һоspringboot
        SpringApplication.run(Demo01Application.class, args);
    }
}

ȻǾͽʲô

public class SpringApplication {
    ...
    // primarySource Ǵ Demo01Application.class
    // args  main() IJ
    public static ConfigurableApplicationContext run(
            Class<?> primarySource, String... args) {
        //  primarySource װ飬 run(...) 
        return run(new Class<?>[] { primarySource }, args);
    }

    // primarySources Ǵ Demo01Application.class װɵ飬
    // args  main() IJ
    public static ConfigurableApplicationContext run(
            Class<?>[] primarySources, String[] args) {
        // ↑ʼ
        return new SpringApplication(primarySources).run(args);
    }
    ...
}

ͨһ׷ȥ?SpringApplication#run(Class<?>[], String[])?ؼ£

return new SpringApplication(primarySources).run(args);

ҪԲ֣

  • SpringApplication#SpringApplication(Class<?>...)
  • ʵSpringApplication#run(String...)

springboot ˣǾ

2. ?SpringApplication``SpringApplication#SpringApplication(Class<?>...)

public class SpringApplication {
    public SpringApplication(Class<?>... primarySources) {
        // 
        this(null, primarySources);
    }

    /**
     * յõĹ췽
     * resourceLoader Ϊ null
     * primarySources Ϊ Demo01Application.class
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 1\. resourceLoaderõԱֵΪnull
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // 2\. primarySourcesõԱֵΪ Demo01Application.class
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 3\. ǰ web ӦͣREACTIVENONESERVLET
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 4\. óʼgetSpringFactoriesInstances META-INF/spring.factories лȡ
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // 5\. ügetSpringFactoriesInstances META-INF/spring.factories лȡ
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 6\. ذmain()class
        this.mainApplicationClass = deduceMainApplicationClass();
    }
}

»DZȽģݶڴעˣЩҪչǾ

2.1 ȡǰ web ӦͣWebApplicationType.deduceFromClasspath()

WebApplicationType.deduceFromClasspath()?ƶϵǰĿʲô͵ģ£

public enum WebApplicationType {
    //  web Ӧ
    NONE,

    // servlet ͵ web Ӧ
    SERVLET,

    // reactive ͵ web Ӧ
    REACTIVE;

    ...

    private static final String[] SERVLET_INDICATOR_CLASSES = { 
            "javax.servlet.Servlet",
            "org.springframework.web.context.ConfigurableWebApplicationContext" };

    private static final String WEBMVC_INDICATOR_CLASS 
            = "org.springframework.web.servlet.DispatcherServlet";

    private static final String WEBFLUX_INDICATOR_CLASS 
            = "org.springframework.web.reactive.DispatcherHandler";

    private static final String JERSEY_INDICATOR_CLASS 
            = "org.glassfish.jersey.servlet.ServletContainer";

    static WebApplicationType deduceFromClasspath() {
        // classpath н WEBFLUX 
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
                && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        // classpath  SERVLET 
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        // Ĭ web Ϊ SERVLET
        // Ҳ˵ͬʱ WEBFLUX  SERVLET ࣬շص SERVLET
        return WebApplicationType.SERVLET;
    }

    ...
}

Կspringboot ĿͣNONE( web Ӧ)SERVLET(servlet?͵ web Ӧ)REACTIVE(reactive?͵ web Ӧ)WebApplicationType.deduceFromClasspath()?ִ£

  1. ?classpath?н?WEBFLUX?࣬ǰĿ?reactive?͵ web Ӧãأ
  2. ?classpath?в?SERVLET?࣬ǰĿ web Ӧãأ
  3. 㣬ǰĿ?servlet?͵ web Ӧá

demo ?spring-boot-starter-web?˵ǰĿ?servlet?͵ web Ӧá

2.2 óʼsetInitializers(...)

£

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

дΪ:

  • ȡ?ApplicationContextInitializer``getSpringFactoriesInstances(ApplicationContextInitializer.class)
  • óʼsetInitializers(...)

ȡ?ApplicationContextInitializer?̣£

public class SpringApplication {
    ...

    // type Ϊ ApplicationContextInitializer.class
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

    /**
     * type Ϊ ApplicationContextInitializer.class
     * parameterTypes Ϊ ew Class<?>[] {}
     * args Ϊ null
     */
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, 
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        //  META-INF/spring.factories 
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // ʵʹõķ
        List<T> instances = createSpringFactoriesInstances(
                type, parameterTypes, classLoader, args, names);
        // 򣬱Ƚϵ @Order ע⣬ʵֵ Orderd ӿ
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
    ...
}

ϴȽϼ򵥣ȴ?META-INF/spring.factories?ȡݣȻʹ÷ʵٷء

?SpringFactoriesLoader.loadFactoryNames(...)ջ?META-INF/spring.factoriesMETA-INF/spring.factories?Ϊһļkey Ϊ type÷ϸԲο?springboot Զװ֮Զװ

ջжٸ?ApplicationContextInitializer?ؽأͨԣһ 7

7 ?ApplicationContextInitializer˵£

  • ConfigurationWarningsApplicationContextInitializer IOC һЩĴ
  • ContextIdApplicationContextInitializer Spring Ӧĵ ID
  • DelegatingApplicationContextInitializer?application.properties??context.initializer.classes
  • RSocketPortInfoApplicationContextInitializer?RSocketServer?ʵʹõļ˿д뵽?Environment?
  • ServerPortInfoApplicationContextInitializer servlet ʵʹõļ˿д뵽?Environment?
  • SharedMetadataReaderFactoryContextInitializerһ?SpringBoot??ConfigurationClassPostProcessor?õ?CachingMetadataReaderFactory?
  • ConditionEvaluationReportLoggingListener?ConditionEvaluationReport?д־

ȡ?ApplicationContextInitializer?setInitializers(...)?

public class SpringApplication {
    ...
    public void setInitializers(
            Collection<? extends ApplicationContextInitializer<?>> initializers) {
        this.initializers = new ArrayList<>(initializers);
    }
    ...
}

һ׼?setter?ľֻóԱ

2.3 üsetListeners(...)

üĴ£

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

ʽϿͬ?Initializer?һҲȴ?META-INF/spring.factories?м?ApplicationListenerȻӵԱУֱӿܻȡЩ?listener

ԿһԻȡ 11 ?listenerЩ?listener

  • ClearCachesApplicationListenerӦļɺԻ
  • ParentContextCloserApplicationListener˫ӦĵĹر¼ԼӦд
  • CloudFoundryVcapEnvironmentPostProcessor?CloudFoundry?ṩ֧
  • FileEncodingApplicationListenerϵͳļӦûǷһ£ϵͳļӦûı벻ֹͬӦ
  • AnsiOutputApplicationListener?spring.output.ansi.enabled??AnsiOutput
  • ConfigFileApplicationListenerӳЩԼλöȡļ
  • DelegatingApplicationListener¼ת?application.properties?õ?context.listener.classes
  • ClasspathLoggingApplicationListenerԻ¼?ApplicationEnvironmentPreparedEvent?Ӧʧ¼?ApplicationFailedEvent
  • LoggingApplicationListener?LoggingSystemʹ?logging.config?ָûȱʡ
  • LiquibaseServiceLocatorApplicationListenerʹһԺ?SpringBoot?ִ jar Ϲİ汾滻?LiquibaseServiceLocator
  • BackgroundPreinitializerʹһ̨߳̾紥һЩʱijʼ

?SpringApplication#setListeners

public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
    this.listeners = new ArrayList<>(listeners);
}

Ҳһ׼?setter?

2.4 ƶࣺdeduceMainApplicationClass()

ν࣬ǰ?main(String[])Ҳǵǰ spring Ӧõ࣬SpringApplication#deduceMainApplicationClass

private Class<?> deduceMainApplicationClass() {
    try {
        // ȡջ
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        // ջ main
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

Ҫͨ?new RuntimeException().getStackTrace()?ȡջȻõ?main?࣬õĵջ£

Կmain()?Ͱڵջˡ

2.5 ܽ

Ҫǽ?SpringApplication?Ĵ̣ص¼㣺

  1. ƶϵǰ web ӦͣNONE, SERVLET,REACTIVE
  2. óʼApplicationContextInitializer
  3. üApplicationListener
  4. ƶࡣ


ԭӣhttps://my.oschina.net/funcy/blog/4877610?߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע