docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(三):准备IOC容器.md
һƪܽ springboot £
ģǼIJ衣
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 £
servlet ӦãAnnotationConfigServletWebServerApplicationContextreactive ӦãAnnotationConfigReactiveWebServerApplicationContextAnnotationConfigApplicationContextǰӦõ 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
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軹ǺģҪݶڴнעͣһЩչ¡
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);
}
....
}
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 ǰҲᵽҪвתġ
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 ĵطˡ
£
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Ҳ֤ͨ
Ĵ£
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 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע