Back to Javatutorial

SpringBoot启动流程(三):准备IOC容器

docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(三):准备IOC容器.md

1.0.014.4 KB
Original Source

һƪܽ springboot £

ģǼIJ衣

3.8 ioc

ioc Ĵ£

ConfigurableApplicationContext context = null;
....
// applicationContext
context = createApplicationContext();

ǽ SpringApplication#createApplicationContext

/** Ĭϵ ApplicationContext */
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
        + "annotation.AnnotationConfigApplicationContext";

/** servlet Ӧõĵ ApplicationContext */
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
        + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

/** Reactive Ӧõ ApplicationContext */
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
        + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            // Ӧͬ
            switch (this.webApplicationType) {
            case SERVLET:
                // ʹõ AnnotationConfigServletWebServerApplicationContext
                contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                break;
            case REACTIVE:
                contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                break;
            default:
                // Ĭʹõ AnnotationConfigApplicationContext
                contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(...);
        }
    }
    // ʹ÷ʵ
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

ҪǸӦͬ ApplicationContextʹ÷ķʵӦͶӦ ApplicationContext £

  1. servlet ӦãAnnotationConfigServletWebServerApplicationContext
  2. reactive ӦãAnnotationConfigReactiveWebServerApplicationContext
  3. ϶ǣAnnotationConfigApplicationContext

ǰӦõ servlet˴ ApplicationContext AnnotationConfigReactiveWebServerApplicationContextĹ췽

public class AnnotationConfigServletWebServerApplicationContext 
        extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {

    //  BeanDefinition ע
    private final AnnotatedBeanDefinitionReader reader;

    // ɨ
    private final ClassPathBeanDefinitionScanner scanner;

    ...

    public AnnotationConfigServletWebServerApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    ...
}

AnnotationConfigServletWebServerApplicationContext Ĺ췽DZȽϼ򵥵ģֻԣͲ˵ˡҲҪĿԶһ㣬丸Ĺ췽 GenericApplicationContext Ĺ췽ҵôһ䣺

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

д봴 DefaultListableBeanFactory 丳ֵ beanFactory ApplicationContext ʹõ beanFactory DefaultListableBeanFactory

3.9 ׼ ioc

ioc 󣬽žǶһЩ׼£

public class SpringApplication {

    ...

    private void prepareContext(ConfigurableApplicationContext context, 
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, 
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // õӦûõIOC
        context.setEnvironment(environment);
        // һЩ
        postProcessApplicationContext(context);
        // ӦInitializerгʼ
        applyInitializers(context);
        //  SpringApplicationRunListenerscontextPrepared
        // ڴ׼ApplicationContext֮󣬵ڼ֮ǰ
        listeners.contextPrepared(context);
        // ӡ־
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // ȡbeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // вΪbeanעᵽbeanFactory
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        //  banner ΪbeanעᵽbeanFactory
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            // ǷbeanϢ
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(
                    new LazyInitializationBeanFactoryPostProcessor());
        }
        // ȡԴ
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //  class
        load(context, sources.toArray(new Object[0]));
        // ¼
        listeners.contextLoaded(context);
    }
}

׼IJ軹ǺģҪݶڴнעͣһЩ΢չ¡

1. Environment

òĴΪ

private void prepareContext(ConfigurableApplicationContext context, 
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, 
        ApplicationArguments applicationArguments, Banner printedBanner) {
    // õӦûõIOC
    context.setEnvironment(environment);
    ...
}

environment ǰ洴 environmentioc Ҳʹò

public class AnnotationConfigServletWebServerApplicationContext extends ... {

    ...

    @Override
    public void setEnvironment(ConfigurableEnvironment environment) {
        // øķ
        super.setEnvironment(environment);
        // Ҳenvironmentõ
        this.reader.setEnvironment(environment);
        this.scanner.setEnvironment(environment);
    }

    ....
}

2. ioc IJ

postProcessApplicationContext(context); Ĺ

public class SpringApplication {

    ...

    protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        //  beanNameGenerator bean ƣﴫnull
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                    this.beanNameGenerator);
        }
        //  resourceLoaderزΪnullifĴ벻ִ
        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
            }
            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader) context).setClassLoader(
                        this.resourceLoader.getClassLoader());
            }
        }
        // ִ
        if (this.addConversionService) {
            // תStringתNumber
            context.getBeanFactory().setConversionService(
                    ApplicationConversionService.getSharedInstance());
        }
    }

    ...

}

ⲿ־ ApplicationContext ļԣǵ demo УbeanNameGenerator resourceLoader null鶼Уеľֻ룺

 context.getBeanFactory().setConversionService(
        ApplicationConversionService.getSharedInstance());

ConversionService ǰҲᵽҪвתġ

3. ӦóʼapplyInitializers(context)

SpringApplication#applyInitializers £

public class SpringApplication {

    ...

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected void applyInitializers(ConfigurableApplicationContext context) {
        // getInitializers()ȡеijʼ
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            // һinitializerinitialize(...)
            initializer.initialize(context);
        }
    }

}

Ǻģǻȡе InitializerȻ initialize(...)

ﻹҪ£getInitializers() ôȡ Initializer أش£

public class SpringApplication {

    private List<ApplicationContextInitializer<?>> initializers;

    ...

    // ڹ췽õ initializers
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        ...

        // óʼgetSpringFactoriesInstances META-INF/spring.factories лȡ
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));

        ...
    }

    // ȡ Initializer IJлȡ
    public Set<ApplicationContextInitializer<?>> getInitializers() {
        return asUnmodifiableOrderedSet(this.initializers);
    }

    ...

˴ˣǰ SpringApplication Ĺ췽ʱᵽ springboot META-INF/spring.factories ȡõ Initializerõ initializers ԣʹ Initializer ĵطˡ

4. ȡԴ

£

private void prepareContext(ConfigurableApplicationContext context, 
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, 
        ApplicationArguments applicationArguments, Banner printedBanner) {
    ...
    // ȡԴ
    Set<Object> sources = getAllSources();
    ...
}

getAllSources()

//  primarySources setУȻsetתΪɱset
public Set<Object> getAllSources() {
    Set<Object> allSources = new LinkedHashSet<>();
    if (!CollectionUtils.isEmpty(this.primarySources)) {
        allSources.addAll(this.primarySources);
    }
    // sources Ϊգifִ
    if (!CollectionUtils.isEmpty(this.sources)) {
        allSources.addAll(this.sources);
    }
    return Collections.unmodifiableSet(allSources);
}

ܼ򵥣һ primarySources set УȻ set תΪɱ setء

primarySources ɶأҪص SpringApplication Ĺ췽ˣ

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    ...
    //  primarySources
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    ...
}

Ȼϣ primarySources main дģ

@SpringBootApplication
public class Demo01Application {

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

}

Ǵ Demo01Application.class primarySources

ˣgetAllSources() һ setset ֻһԪأDemo01Application.classҲ֤ͨ

5. Դ

Ĵ£

private void prepareContext(ConfigurableApplicationContext context, 
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, 
        ApplicationArguments applicationArguments, Banner printedBanner) {
    ...
    //  class
    load(context, sources.toArray(new Object[0]));
    ...
}

SpringApplication#load

public class SpringApplication {
    ...

    protected void load(ApplicationContext context, Object[] sources) {
        // һBeanDefinitionļ
        BeanDefinitionLoader loader = createBeanDefinitionLoader(
                getBeanDefinitionRegistry(context), sources);
        // ǰ beanNameGenerator Ϊ null
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        // ǰ resourceLoader Ϊ null
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        // ǰ environment Ϊ null
        // ǰ洴environmentûиֵԱ
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }
    ...
}

Ǵһ BeanDefinitionLoader ʵȡ source BeanDefinitionLoader Ĺ췽д뵽ʵУȻԸ loader һϵеãٵ load() Ҫ˵ǣȻǰ洴 environment this.environment Ϊ nullԭǰ洴 environment ûиֵ this.environment

Ǽ BeanDefinitionLoader#load()

class BeanDefinitionLoader {

    ...

    int load() {
        int count = 0;
        //  sources оֻһԪأDemo01Application.class
        for (Object source : this.sources) {
            count += load(source);
        }
        return count;
    }

    // ز
    private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        // Class 
        if (source instanceof Class<?>) {
            // source Ϊ Demo01Application.classҪע
            return load((Class<?>) source);
        }
        if (source instanceof Resource) {
            return load((Resource) source);
        }
        if (source instanceof Package) {
            return load((Package) source);
        }
        if (source instanceof CharSequence) {
            return load((CharSequence) source);
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }

    // Class ͵ļز
    private int load(Class<?> source) {
        //  grouovy Եģù
        if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            GroovyBeanDefinitionSource loader 
                    = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
            load(loader);
        }
        // Ƿ @Component ע
        if (isComponent(source)) {
            //  BeanDefinition 󣬲עᵽspring
            this.annotatedReader.register(source);
            return 1;
        }
        return 0;
    }
    ...

ڴ BeanDefinitionLoader ʵʱͨ乹췽 sources BeanDefinitionLoader ʵУsources оֻһԪأDemo01Application.classֻע Class ԴļؾͿˣյ BeanDefinitionLoader#load(java.lang.Class<?>) ÷IJΪжϴ Class Ƿ @Componentоͽעᵽ ioc С

ô Demo01Application.class Ƿ @Component עأеģصñȽע㼶£

@SpringBootApplication
public class Demo01Application {
    ...
}

@SpringBootApplication

...
@SpringBootConfiguration
...
public @interface SpringBootApplication {
    ...
}

@SpringBootApplication

...
@Configuration
public @interface SpringBootConfiguration {
    ...
}

@Configuration

...
@Component
public @interface Configuration {
    ...
}

زۣ @Configuration עҵ @Component.

this.annotatedReader.register(source) עľ spring УѾˣͲٷˡ

ƪľ͵ˣƪʣµ̡


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