前言
这篇文章我们分析SpringApplication#run第8步.执行prepareContext方法.该方法的内容比较多.我们慢慢来.
分析
SpringApplication#run 第8步执行如下代码:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 1. 上下文设置环境 context.setEnvironment(environment); // 2. 调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话) postProcessApplicationContext(context); // 3. 拿到之前实例化SpringApplication对象的时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化 applyInitializers(context); // 4. contextPrepareds 是一个空实现 listeners.contextPrepared(context); // 5. 打印启动日志 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans // 6. 日志往上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象 context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); // 如果之前获取的printedBanner不为空,那么往上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 7. 调用load方法注册启动类的bean定义,也就是调用SpringApplication.run(Application.class, args);的类,SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法 load(context, sources.toArray(new Object[sources.size()])); // 8. 调用listeners的contextLoaded方法,说明上下文已经加载,该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,那么在这一步会调用它的setApplicationContext方法,设置context listeners.contextLoaded(context); }
做了8件事:
为上下文设置Environment. 注意 这里传入的是 StandardServletEnvironment
调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)
- 拿到之前实例化SpringApplication对象的时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化
- 调用listeners#contextPrepared,该方法是一个空实现
- 打印启动日志
- 往上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象,
如果之前获取的printedBanner不为空,那么往上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner.这里默认是SpringBootBanner. - 调用load方法注册启动类的bean定义,也就是调用SpringApplication.run(Application.class, args);的类,SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法
- 调用listeners的contextLoaded方法,说明上下文已经加载,该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,那么在这一步会调用它的setApplicationContext方法,设置context
为上下文设置Environment 执行的是AnnotationConfigEmbeddedWebApplicationContext#setEnvironment,代码如下:
public void setEnvironment(ConfigurableEnvironment environment) { super.setEnvironment(environment); this.reader.setEnvironment(environment); this.scanner.setEnvironment(environment); }
3件事:
调用父类的setEnvironment方法.代码如下:
public void setEnvironment(ConfigurableEnvironment environment) { this.environment = environment; }
为AnnotatedBeanDefinitionReader设置Environment.执行如下代码.
public void setEnvironment(Environment environment) { this.conditionEvaluator = new ConditionEvaluator(this.registry, environment, null); }
实例化了ConditionEvaluator.其构造器如下:
public ConditionEvaluator(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) { this.context = new ConditionContextImpl(registry, environment, resourceLoader); }
在实例化ConditionEvaluator时实例化了ConditionContextImpl.该类是ConditionContext的一个实现.是Condition使用时的上下文.其构造器如下:
public ConditionContextImpl(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) { this.registry = registry; this.beanFactory = deduceBeanFactory(registry); this.environment = (environment != null ? environment : deduceEnvironment(registry)); this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry)); }
- 设置BeanDefinitionRegistry.这里实际上持有的是AnnotationConfigEmbeddedWebApplicationContext.
设置beanFactory.执行如下代码:
private ConfigurableListableBeanFactory deduceBeanFactory(BeanDefinitionRegistry source) { if (source instanceof ConfigurableListableBeanFactory) { return (ConfigurableListableBeanFactory) source; } if (source instanceof ConfigurableApplicationContext) { return (((ConfigurableApplicationContext) source).getBeanFactory()); } return null; }
由于AnnotationConfigEmbeddedWebApplicationContext是ConfigurableApplicationContext的子类,因此会调用getBeanFactory获得ConfigurableListableBeanFactory.代码如下:
public final ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory; }
返回的是DefaultListableBeanFactory.
设置environment.由于environment不为null,因此不会执行deduceEnvironment.因此直接设置为StandardServletEnvironment.
设置resourceLoader.由于传入的resourceLoader 为null,因此会执行deduceResourceLoader.代码如下;
private ResourceLoader deduceResourceLoader(BeanDefinitionRegistry source) { if (source instanceof ResourceLoader) { return (ResourceLoader) source; } return null; }
同样的,由于AnnotationConfigEmbeddedWebApplicationContext是ResourceLoader的子类,因此向上转型为ResourceLoader进行赋值.
为ClassPathBeanDefinitionScanner设置Environment.执行如下代码.
public void setEnvironment(Environment environment) { Assert.notNull(environment, "Environment must not be null"); this.environment = environment; this.conditionEvaluator = null; }
SpringApplication#prepareContext 接下来执行的是 postProcessApplicationContext 方法.设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话).代码如下:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context) .setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context) .setClassLoader(this.resourceLoader.getClassLoader()); } } }
2件事:
- 如果beanNameGenerator不为null的话,就向BeanFactory进行注册,bean id 为 org.springframework.context.annotation.internalConfigurationBeanNameGenerator.
如果resourceLoader不为null的话
- 如果context 是 GenericApplicationContext 子类的话,就为其设置ResourceLoader
- 如果context 是DefaultResourceLoader 子类的话,就为其设置ClassLoader
接下来执行第3步.代码如下:
protected void applyInitializers(ConfigurableApplicationContext context) { // 1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer for (ApplicationContextInitializer initializer : getInitializers()) { // 2. 循环调用ApplicationContextInitializer中的initialize方法 Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
2件事:
从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer.将其封装为LinkedHashSet.
遍历之,调用其initialize 进行初始化.当前的initialize有如下:
org.springframework.boot.context.config.DelegatingApplicationContextInitializer, org.springframework.boot.context.ContextIdApplicationContextInitializer, org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer, org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer, org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer, org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
我们分别看下其initialize 的实现.
DelegatingApplicationContextInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext context) { ConfigurableEnvironment environment = context.getEnvironment(); // 1. 通过env获取到context.initializer.classes配置的值,如果有则直接获取到具体的值并进行实例化 List<Class<?>> initializerClasses = getInitializerClasses(environment); if (!initializerClasses.isEmpty()) { applyInitializerClasses(context, initializerClasses); } }
还是3步
- 从context中获得ConfigurableEnvironment
调用getInitializerClasses获得通过context.initializer.classes 设置的class.
代码如下:
private static final String PROPERTY_NAME = "context.initializer.classes"; private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) { String classNames = env.getProperty(PROPERTY_NAME); List<Class<?>> classes = new ArrayList<Class<?>>(); if (StringUtils.hasLength(classNames)) { for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) { classes.add(getInitializerClass(className)); } } return classes; }
3步:
- 从env获得context.initializer.classes 配置的值
- 如果有配置的话,就依次遍历之,如果有多个的话,用,分隔即可. 一般是没有配置的,这里是一个扩展点.
调用getInitializerClass 进行加载.代码如下:
private Class<?> getInitializerClass(String className) throws LinkageError { try { // 1. 进行加载 Class<?> initializerClass = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader()); // 2. 要加载的类必须是ApplicationContextInitializer 实现才行 Assert.isAssignable(ApplicationContextInitializer.class, initializerClass); return initializerClass; } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load context initializer class [" + className + "]", ex); } }
如果有配置的话,就掉用applyInitializerClasses方法进行初始化. 代码如下:
private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) { Class<?> contextClass = context.getClass(); List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>(); for (Class<?> initializerClass : initializerClasses) { initializers.add(instantiateInitializer(contextClass, initializerClass)); } applyInitializers(context, initializers); }
2件事.
- 依次遍历initializerClasses 进行初始化.
实例化完毕后调用applyInitializers,依次调用其initialize方法.代码如下:
private void applyInitializers(ConfigurableApplicationContext context, List<ApplicationContextInitializer<?>> initializers) { // 排序后调用具体ApplicationContextInitializer类中的initialize方法 Collections.sort(initializers, new AnnotationAwareOrderComparator()); for (ApplicationContextInitializer initializer : initializers) { initializer.initialize(context); } }
ContextIdApplicationContextInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.setId(getApplicationId(applicationContext.getEnvironment())); }
3件事:
- 通过applicationContext 获得ConfigurableEnvironment
调用getApplicationId 生成id.代码如下
private String getApplicationId(ConfigurableEnvironment environment) { String name = environment.resolvePlaceholders(this.name); String index = environment.resolvePlaceholders(INDEX_PATTERN); String profiles = StringUtils .arrayToCommaDelimitedString(environment.getActiveProfiles()); if (StringUtils.hasText(profiles)) { name = name + ":" + profiles; } if (!"null".equals(index)) { name = name + ":" + index; } return name; }
5件事.
- 获取名称。名称的取值依赖如下几个属性获取名称 spring.application.name,vcap.application.name, spring.config.name:application默认是application
获取索引.从以下几个属性中获得.
- vcap.application.instance_index
- spring.application.index
- server.port
- PORT
- null
默认是null
- 获取ActiveProfiles
- 如果profiles 不会null,就与name进行拼接
- 如果index 不为null的话,就与name进行拼接
举例说明. 假如我配置 spring.profiles.active=test.端口号为8881,则最后生成的id为application:test:8881
对applicationContext 设置id.代码如下:
public void setId(String id) { this.id = id; }
ConfigurationWarningsApplicationContextInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext context) { context.addBeanFactoryPostProcessor( new ConfigurationWarningsPostProcessor(getChecks())); }
向context中添加一个ConfigurationWarningsPostProcessor.
在实例化ConfigurationWarningsPostProcessor时首先会调用getChecks获得Check[],传入到ConfigurationWarningsPostProcessor的构造器中.代码如下:
protected Check[] getChecks() { return new Check[] { new ComponentScanPackageCheck() }; }
其返回了一个ComponentScanPackageCheck. 其初始化的代码如下:
private static final Set<String> PROBLEM_PACKAGES; static { Set<String> packages = new HashSet<String>(); packages.add("org.springframework"); packages.add("org"); PROBLEM_PACKAGES = Collections.unmodifiableSet(packages); }
将org.springframework,org 加入到了PROBLEM_PACKAGES 中.
ConfigurationWarningsPostProcessor 构造器如下:
public ConfigurationWarningsPostProcessor(Check[] checks) { this.checks = checks; }
这样 ConfigurationWarningsPostProcessor 就持有了ComponentScanPackageCheck.
ServerPortInfoApplicationContextInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addApplicationListener( new ApplicationListener<EmbeddedServletContainerInitializedEvent>() { @Override public void onApplicationEvent( EmbeddedServletContainerInitializedEvent event) { ServerPortInfoApplicationContextInitializer.this .onApplicationEvent(event); } }); }
向applicationContext 添加一个监听.当发生EmbeddedServletContainerInitializedEvent时间时.会执行ServerPortInfoApplicationContextInitializer#onApplicationEvent方法.将server.ports添加到名为server.ports 的MapPropertySource
SharedMetadataReaderFactoryContextInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addBeanFactoryPostProcessor( new CachingMetadataReaderFactoryPostProcessor()); }
向applicationContext 添加了一个CachingMetadataReaderFactoryPostProcessor 的BeanFactoryPostProcessor
SharedMetadataReaderFactoryContextInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; applicationContext.addApplicationListener(new AutoConfigurationReportListener()); if (applicationContext instanceof GenericApplicationContext) { // Get the report early in case the context fails to load this.report = ConditionEvaluationReport .get(this.applicationContext.getBeanFactory()); } }
2件事
- 向applicationContext添加了一个AutoConfigurationReportListener
如果applicationContext是GenericApplicationContext子类的话,就调用ConditionEvaluationReport#get生成ConditionEvaluationReport.代码如下:
public static ConditionEvaluationReport get( ConfigurableListableBeanFactory beanFactory) { synchronized (beanFactory) { ConditionEvaluationReport report; if (beanFactory.containsSingleton(BEAN_NAME)) { report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class); } else { report = new ConditionEvaluationReport(); beanFactory.registerSingleton(BEAN_NAME, report); } locateParent(beanFactory.getParentBeanFactory(), report); return report; } }
- 首先判断是否包含autoConfigurationReport,如果有的话,直接获取即可.否则就实例化一个,然后进行注册.
调用locateParent.代码如下:
private static void locateParent(BeanFactory beanFactory, ConditionEvaluationReport report) { if (beanFactory != null && report.parent == null && beanFactory.containsBean(BEAN_NAME)) { report.parent = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class); } }
这里很明显,由于当前环境下 AnnotationConfigEmbeddedWebApplicationContext 中的BeanFactory 是顶层容器,因此 其 ParentBeanFactory 是不存在的,因此该方法是不会执行的.
AutoConfigurationReportLoggingInitializer#initialize
代码如下:
public void initialize(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; applicationContext.addApplicationListener(new AutoConfigurationReportListener()); if (applicationContext instanceof GenericApplicationContext) { // Get the report early in case the context fails to load this.report = ConditionEvaluationReport .get(this.applicationContext.getBeanFactory()); } }
3件事:
- 给applicationContext进行赋值
- 添加ApplicationListener
如果当前的applicationContext 是GenericApplicationContext 实例的话,就给report进行赋值.很明显,会执行赋值的.执行如下代码:
public static ConditionEvaluationReport get( ConfigurableListableBeanFactory beanFactory) { synchronized (beanFactory) { ConditionEvaluationReport report; if (beanFactory.containsSingleton(BEAN_NAME)) { report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class); } else { report = new ConditionEvaluationReport(); beanFactory.registerSingleton(BEAN_NAME, report); } locateParent(beanFactory.getParentBeanFactory(), report); return report; } }
2件事:
- 如果当前beanFactory包含autoConfigurationReport定义的话,就从beanFactory中获取,否则就实例化一个,然后进行注册
- 如果存在父容器的话,就从父容器中获取。
很明显,这里是不存在父容器的,并且beanFactory是不包含autoConfigurationReport的定义,因此会实例化后再进行注册.
视线回到SpringApplication#prepareContext中的第5步,打印日志.代码如下:
if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); }
3件事
- 判断是否允许打印启动信息,默认是true.如果为false,则不进行打印.
调用logStartupInfo进行打印.代码如下:
protected void logStartupInfo(boolean isRoot) { if (isRoot) { new StartupInfoLogger(this.mainApplicationClass) .logStarting(getApplicationLog()); } }
由于此时的context为顶级容器,因此为实例化StartupInfoLogger,实例化时将启动类传入构造器,然后调用其logStarting方法.调用时,首先getApplicationLog获得启动类的log.代码如下:
protected Log getApplicationLog() { if (this.mainApplicationClass == null) { return logger; } return LogFactory.getLog(this.mainApplicationClass); }
由于此时的mainApplicationClass不为null,因此会实例化启动类的Log.
public void logStarting(Log log) { Assert.notNull(log, "Log must not be null"); if (log.isInfoEnabled()) { log.info(getStartupMessage()); } if (log.isDebugEnabled()) { log.debug(getRunningMessage()); } }
2件事:
如果日志级别是info的话,调用getStartupMessage进行打印.代码如下:
private String getStartupMessage() { StringBuilder message = new StringBuilder(); message.append("Starting "); message.append(getApplicationName()); message.append(getVersion(this.sourceClass)); message.append(getOn()); message.append(getPid()); message.append(getContext()); return message.toString(); }
会打印启动类名,启动类所在的版本号,主机名,进程id,上下文.打印的日志如下;
2017-12-25 10:25:22.276 INFO 50826 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on localhost with PID 50826 (/Users/hejiarui/Documents/spring-boot-source/demo/target/classes started by hejiarui in /Users/hejiarui/Documents/spring-boot-source/demo)
如果日志级别是debug的话,调用getRunningMessage进行打印.代码如下:
private StringBuilder getRunningMessage() { StringBuilder message = new StringBuilder(); message.append("Running with Spring Boot"); message.append(getVersion(getClass())); message.append(", Spring"); message.append(getVersion(ApplicationContext.class)); return message; }
打印spring boot 的版本号,ApplicationContext的版本号,打印如下:
2017-12-25 10:29:02.626 DEBUG 50852 --- [ main] com.example.demo.DemoApplication : Running with Spring Boot, Spring v4.3.13.RELEASE
第7步代码如下:
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug( "Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } // 1. 实例化BeanDefinitionLoader BeanDefinitionLoader loader = createBeanDefinitionLoader( getBeanDefinitionRegistry(context), sources); // 2. 如果当前的beanNameGenerator 不会null的话,就将SpringApplication中的beanNameGenerator赋值给BeanDefinitionLoader if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } // 3. 如果当前的resourceLoader 不会null的话,就将SpringApplication中的resourceLoader赋值给BeanDefinitionLoader if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } // 4. 如果当前的environment 不会null的话,就将SpringApplication中的environment赋值给BeanDefinitionLoader if (this.environment != null) { loader.setEnvironment(this.environment); } // 5. 调用load方法进行加载 loader.load(); }
5件事:
实例化BeanDefinitionLoader.代码如下:
protected BeanDefinitionLoader createBeanDefinitionLoader( BeanDefinitionRegistry registry, Object[] sources) { return new BeanDefinitionLoader(registry, sources); }
构造器如下:
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) { Assert.notNull(registry, "Registry must not be null"); Assert.notEmpty(sources, "Sources must not be empty"); this.sources = sources; this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); this.xmlReader = new XmlBeanDefinitionReader(registry); if (isGroovyPresent()) { this.groovyReader = new GroovyBeanDefinitionReader(registry); } this.scanner = new ClassPathBeanDefinitionScanner(registry); this.scanner.addExcludeFilter(new ClassExcludeFilter(sources)); }
5件事.
- 将sources赋值给BeanDefinitionLoader中的sources
- 实例化AnnotatedBeanDefinitionReader.该实例化的过程我们之前有分析过
- 实例化了XmlBeanDefinitionReader
判断是否是在groovy的环境中,如果是的话,就实例化GroovyBeanDefinitionReader.一般情况下,是不会实例化的.判断代码如下:
private boolean isGroovyPresent() { return ClassUtils.isPresent("groovy.lang.MetaClass", null); }
- 实例化ClassPathBeanDefinitionScanner.该实例化的过程我们之前有分析过.并将启动类,添加到ClassPathBeanDefinitionScanner的ExcludeFilter中。
如果当前的beanNameGenerator 不会null的话,就将SpringApplication中的beanNameGenerator赋值给BeanDefinitionLoader.对于当前是不会进行赋值的.
- 如果当前的resourceLoader 不会null的话,就将SpringApplication中的resourceLoader赋值给BeanDefinitionLoader.对于当前是不会进行赋值的.
- 如果当前的environment 不会null的话,就将SpringApplication中的environment赋值给BeanDefinitionLoader.对于当前是不会进行赋值的.
调用load方法进行加载.代码如下:
public int load() { int count = 0; for (Object source : this.sources) { count += load(source); } return count; }
2件事:
- 声明一个计数器,该计数器统计的是sources中加载bean的数量.
遍历sources,进行加载.
代码如下:
private int load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof 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()); }
判断source 的类型,然后调用相应的load方法进行加载,由于我们此时传入的是启动类,因此会调用如下方法,代码如下:
private int load(Class<?> source) { if (isGroovyPresent()) { // Any GroovyLoaders added in beans{} DSL can contribute beans here if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); load(loader); } } if (isComponent(source)) { // 进行注册 this.annotatedReader.register(source); return 1; } return 0; }
2件事:
- 如果是Groovy环境下,并且该类是GroovyBeanDefinitionSource的子类的话,就调用BeanDefinitionLoader#load(GroovyBeanDefinitionSource) 进行加载,很明显,是不会执行的.
如果当前类是Component注解的话,就调用AnnotatedBeanDefinitionReader#register进行加载.判断的方法如下:
private boolean isComponent(Class<?> type) { // This has to be a bit of a guess. The only way to be sure that this type is // eligible is to make a bean definition out of it and try to instantiate it. if (AnnotationUtils.findAnnotation(type, Component.class) != null) { return true; } // Nested anonymous classes are not eligible for registration, nor are groovy // closures if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass() || type.getConstructors() == null || type.getConstructors().length == 0) { return false; } return true; }
3件事
- 如果当前类上有@Component 注解的话,则返回true.
- 如果当前类的类名匹配.*$_.*closure.* ,或者是一个匿名类,或者构造器不存在的话,返回false.
- 如果以上都不匹配的话,返回true.
由于我们在启动类上加了@SpringBootApplication的注解,又由于@SpringBootApplication中存在@SpringBootConfiguration,而@SpringBootConfiguration中又存在@Configuration,最终在@Configuration中存在@Component,因此匹配1,因此返回true.
- 如果以上都没匹配到的话,就返回0.
AnnotatedBeanDefinitionReader#register ,通过遍历annotatedClasses,依次调用registerBean进行加载,代码如下:
public void register(Class<?>... annotatedClasses) { for (Class<?> annotatedClass : annotatedClasses) { registerBean(annotatedClass); } }
registerBean代码如下:
public void registerBean(Class<?> annotatedClass) { registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null); }
调用:
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
9件事:
实例化AnnotatedGenericBeanDefinition.该类的继承结构如下:
由继承结构可知.会首先实例化AbstractBeanDefinition,执行如下构造器.代码如下:protected AbstractBeanDefinition() { this(null, null); }
调用
protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) { setConstructorArgumentValues(cargs); setPropertyValues(pvs); }
2件事:
调用 setConstructorArgumentValues 实例化constructorArgumentValues.代码如下:
public void setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) { this.constructorArgumentValues = (constructorArgumentValues != null ? constructorArgumentValues : new ConstructorArgumentValues()); }
由于传入的constructorArgumentValues 为null,因此会实例化ConstructorArgumentValues.
调用setPropertyValues 对propertyValues 进行赋值,代码如下:
public void setPropertyValues(MutablePropertyValues propertyValues) { this.propertyValues = (propertyValues != null ? propertyValues : new MutablePropertyValues()); }
由于传入的propertyValues为null,因此会实例化MutablePropertyValues.
接下来实例化AnnotatedGenericBeanDefinition,构造器如下:
public AnnotatedGenericBeanDefinition(Class<?> beanClass) { setBeanClass(beanClass); this.metadata = new StandardAnnotationMetadata(beanClass, true); }
2件事:
- 对beanClass属性赋值为传入的beanClass.
- 实例化StandardAnnotationMetadata.
如果应该跳过加载的话,就直接return. 判断逻辑如下:
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) { // 如果这个类没有被@Conditional注解所修饰,不会skip if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } // 如果参数中沒有设置条件注解的生效阶段 if (phase == null) { // 是配置类的话直接使用PARSE_CONFIGURATION阶段 if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) { return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION); } // 否则使用REGISTER_BEAN阶段 return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN); } List<Condition> conditions = new ArrayList<Condition>(); // 要解析的配置类的条件集合 // 获取配置类的条件注解得到条件数据,并添加到集合中 for (String[] conditionClasses : getConditionClasses(metadata)) { for (String conditionClass : conditionClasses) { Condition condition = getCondition(conditionClass, this.context.getClassLoader()); conditions.add(condition); } } AnnotationAwareOrderComparator.sort(conditions); for (Condition condition : conditions) { ConfigurationPhase requiredPhase = null; if (condition instanceof ConfigurationCondition) { requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); } if (requiredPhase == null || requiredPhase == phase) { // 阶段不满足条件的话,返回true并跳过这个bean的解析 if (!condition.matches(this.context, metadata)) { return true; } } } return false; }
4件事:
- 如果这个类没有被@Conditional注解所修饰,不会skip
如果参数中沒有设置条件注解的生效阶段
- 是配置类的话直接使用PARSE_CONFIGURATION阶段
- 否则使用REGISTER_BEAN阶段
递归调用shouldSkip进行判断.对于当前阶段 ConfigurationPhase为ConfigurationPhase.PARSE_CONFIGURATION.
- 获取配置类的条件注解得到条件数据,并添加到集合中.排序
- 遍历conditions,进行判断,阶段不满足条件的话,返回true并跳过这个bean的解析
调用AnnotationScopeMetadataResolver#resolveScopeMetadata解析ScopeMetadata. 代码如下:
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { ScopeMetadata metadata = new ScopeMetadata(); if (definition instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition; AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor( annDef.getMetadata(), this.scopeAnnotationType); if (attributes != null) { metadata.setScopeName(attributes.getString("value")); ScopedProxyMode proxyMode = attributes.getEnum("proxyMode"); if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) { proxyMode = this.defaultProxyMode; } metadata.setScopedProxyMode(proxyMode); } } return metadata; }
2件事:
- 实例化ScopeMetadata.其默认scopeName为singleton,scopedProxyMode为NO.
- 如果BeanDefinition是AnnotatedBeanDefinition实例的话,调用AnnotationConfigUtils#attributesFor获得AnnotationAttributes.如果AnnotationAttributes不会null的话,就为metadata设置ScopeName,设置ScopedProxyMode.此处返回的null.
- 如果不是的话,就返回ScopeMetadata.
因此设置AnnotatedGenericBeanDefinition的scope为singleton
调用AnnotationBeanNameGenerator#generateBeanName生成beanName,代码如下:
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { // 1. 如果当前类是AnnotatedBeanDefinition,就调用determineBeanNameFromAnnotation生成beanName // 如果生成的beanName不为空的话,直接return。否则进入第2步. if (definition instanceof AnnotatedBeanDefinition) { String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition); if (StringUtils.hasText(beanName)) { // Explicit bean name found. return beanName; } } // 2. Fallback: generate a unique default bean name. return buildDefaultBeanName(definition, registry); }
2件事:
- 如果当前类是AnnotatedBeanDefinition,就调用determineBeanNameFromAnnotation生成beanName,如果生成的beanName不为空的话,直接return。否则进入第2步.在当前场景,是会进入第2步的.
经过层层调用最终会调用AnnotationBeanNameGenerator#buildDefaultBeanName获得name,代码如下:
protected String buildDefaultBeanName(BeanDefinition definition) {
String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
return Introspector.decapitalize(shortClassName);
}
调用AnnotationConfigUtils#processCommonDefinitionAnnotations进行处理.代码如下:
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { if (metadata.isAnnotated(Lazy.class.getName())) { abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value")); } else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) { abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value")); } if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } if (metadata.isAnnotated(DependsOn.class.getName())) { abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value")); } if (abd instanceof AbstractBeanDefinition) { AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd; if (metadata.isAnnotated(Role.class.getName())) { absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue()); } if (metadata.isAnnotated(Description.class.getName())) { absBd.setDescription(attributesFor(metadata, Description.class).getString("value")); } } }
4件事:
- 如果有Lazy的注解的话,则设置LazyInit的值
- 如果有Primary的注解的话,则设置Primary为true
- 如果有DependsOn的注解的话,则设置DependsOn的值
如果abd 是AbstractBeanDefinition 子类的话
- 如果有Role的注解的话,则设置Role的值
- 如果有Description的注解的话,则设置Description的值
设置qualifier,依次遍历传入的qualifiers进行如下判断.
- 如果 qualifier 为Primary 的话,设置AnnotatedGenericBeanDefinition#Primary为true.
- 如果 qualifier 为 Lazy 的话,就设置AnnotatedGenericBeanDefinition #LazyInit 为true。
- 否则 就添加一个AutowireCandidateQualifier的实例到AnnotatedGenericBeanDefinition#qualifiers中.
由于此时传入qualifier 为null,因此是不会进行遍历的.
调用applyScopedProxyMode,这是有关代理方面的.代码如下:
static BeanDefinitionHolder applyScopedProxyMode( ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) { ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode(); if (scopedProxyMode.equals(ScopedProxyMode.NO)) { return definition; } boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS); return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass); }
2件事
- 如果scopedProxyMode为NO,就直接return。
- 否则调用ScopedProxyCreator#createScopedProxy生成BeanDefinitionHolder.
由于这里的scopedProxyMode为NO,因此是直接进行return的.
视线回到SpringApplication#prepareContext.接下来该执行最后一步了, 调用listeners的contextLoaded方法.代码如下;
public void contextLoaded(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); } }
调用EventPublishingRunListener#contextLoaded,代码如下:
public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } this.initialMulticaster.multicastEvent( new ApplicationPreparedEvent(this.application, this.args, context)); }
2件事
遍历application 中的ApplicationListener,如果listener 实现了ApplicationContextAware的话,就调用其setApplicationContext进行赋值.当前的如下:
org.springframework.boot.context.config.ConfigFileApplicationListener, org.springframework.boot.context.config.AnsiOutputApplicationListener, org.springframework.boot.logging.LoggingApplicationListener, org.springframework.boot.logging.ClasspathLoggingApplicationListener, org.springframework.boot.autoconfigure.BackgroundPreinitializer, org.springframework.boot.context.config.DelegatingApplicationListener, org.springframework.boot.builder.ParentContextCloserApplicationListener, org.springframework.boot.ClearCachesApplicationListener, org.springframework.boot.context.FileEncodingApplicationListener, org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
只有ParentContextCloserApplicationListener实现了ApplicationContextAware接口.
- 发送ApplicationPreparedEvent 事件.由前可知,会依次调用listener的onApplicationEvent事件,接下来我们就来看看其各自的实现.
ConfigFileApplicationListener#onApplicationEvent
代码如下:
public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent( (ApplicationEnvironmentPreparedEvent) event); } if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent(event); } }
调用onApplicationPreparedEvent,代码如下:
private void onApplicationPreparedEvent(ApplicationEvent event) { this.logger.replayTo(ConfigFileApplicationListener.class); addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext()); }
调用
protected void addPostProcessors(ConfigurableApplicationContext context) { context.addBeanFactoryPostProcessor( new PropertySourceOrderingPostProcessor(context)); }
最终添加了一个PropertySourceOrderingPostProcessor.
LoggingApplicationListener#onApplicationEvent
最终会执行LoggingApplicationListener#onApplicationPreparedEvent,向beanFactory注册了一个id为springBootLoggingSystem,class 为 LoggingSystem 的bean.
BackgroundPreinitializer#onApplicationEvent
没有做任何事
DelegatingApplicationListener#onApplicationEvent
没有做任何事