springboot2.1.7启动分析(三)SpringApplication run

目录

 

context = createApplicationContext()

 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context)

prepareContext(context, environment, listeners, applicationArguments, printedBanner)

refreshContext(context)

afterRefresh(context, applicationArguments)

listeners.started(context)

callRunners(context, applicationArguments)

listeners.running(context)


context = createApplicationContext()

因为是servlet,所以会去实例化org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext这个context 。GenericApplicationContext是其父类,所以会执行GenericApplicationContext无参构造函数,这就是我们看到的ApplicationContext中的beanFactory是DefaultListableBeanFactory原因。

public AnnotationConfigServletWebServerApplicationContext() {
   //用于以编程方式注册带注释的Bean类
   this.reader = new AnnotatedBeanDefinitionReader(this);
//一个bean定义扫描器,它检测类路径上的bean候选者,并使用给定的注册表( BeanFactory或ApplicationContext )注册相应的bean定义。
//通过可配置的类型过滤器检测候选类。 默认的过滤器包括用Spring的@Component , @Repository , @Service @Controller或@Controller型注释的@Component 
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public GenericApplicationContext() {
   this.beanFactory = new DefaultListableBeanFactory();
}

 new AnnotatedBeanDefinitionReader(this)最后会调用如下构造函数 

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

 AnnotationConfigUtils.registerAnnotationConfigProcessors:在给定的注册表中注册所有相关的注释后处理器。挑几个重要简单说明下:

  • ConfigurationClassPostProcessor:(重要,后续refresh会重点介绍)此后处理器按优先级排序,因为在任何其他BeanFactoryPostProcessor执行之前, @Configuration类中声明的任何Bean方法都必须注册其对应的Bean定义,这一点很重要。
  • AutowiredAnnotationBeanPostProcessor:简单来说就是处理spring定义的注入的注解。@Autowired @Value等
  • CommonAnnotationBeanPostProcessor:简单来说就是处理javax.annotation下的某些注解。@Resource等。

new ClassPathBeanDefinitionScanner(this)最后会调用如下构造函数 

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		this.registry = registry;

		if (useDefaultFilters) {
            //为@Component注册默认过滤器。这将隐式注册具有@Component元注释的所有注释,包括@Repository , @Service 和@Controller构造型注释
			registerDefaultFilters();
		}
		setEnvironment(environment);
        //设置ResourceLoader以用于资源位置。 这通常是ResourcePatternResolver实现。默认值为PathMatchingResourcePatternResolver ,也能够通过ResourcePatternResolver接口解析资源模式。
		setResourceLoader(resourceLoader);
	}

 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context)

从META-INF/spring.factories文件中获取到SpringBootExceptionReporter并反射实例化出来,目前就一个实例FailureAnalyzers,FailureAnalyzers构造函数会去从META-INF/spring.factories加载并实例化FailureAnalyzer,FailureAnalyzer用于分析故障并提供可以显示给用户的诊断信息。

prepareContext(context, environment, listeners, applicationArguments, printedBanner)

	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

context.setEnvironment(environment)源码:

	public void setEnvironment(ConfigurableEnvironment environment) {
		super.setEnvironment(environment);
		this.reader.setEnvironment(environment);
		this.scanner.setEnvironment(environment);
	}

在初始化context时给reader和scanner设置过environment(上方 AnnotationConfigServletWebServerApplicationContext构造函数调用链中),但当时设置的environment并非一开始SpringApplication中prepareEnvironment实例化出来的,而是context自身实例化出来的,相当于有两个environment。这里将context中相关的environment全部替换成SpringApplication中创建的environment。经过此方法后,就只会存在SpringApplication中的environment了,而context中的原environment会被回收。

  • postProcessApplicationContext(context):应用任何相关的后处理ApplicationContext 。 SpringApplication子类可以根据需要应用其他处理(可重写该方法)
  • applyInitializers(context):执行实例化SpringApplication时的ApplicationContextInitializer类型的实例的initialize方法。主要就是注册了两个BeanFactoryPostProcessor(CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor),添加了两个ApplicationListener(ServerPortInfoApplicationContextInitializer、ConditionEvaluationReportListener),注册单例bean(ContextId)等。
  • Set<Object> sources = getAllSources():返回当调用run(String...)时将添加到ApplicationContext的所有源的不可变集合。目前就只有启动类(SpringApplication实例化时将启动类class设置为了primarySources)
  • load(context, sources.toArray(new Object[0])):加载当前sourcebean定义到context中。
    protected void load(ApplicationContext context, Object[] sources) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    		}
    		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    		......
    		loader.load();
    	}
    
    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    
    		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));
    	}

    load方法首先创建一个新的BeanDefinitionLoader ,它将bean加载到指定的BeanDefinitionRegistry(AnnotationConfigServletWebServerApplicationContext继承自BeanDefinitionRegistry) 。可以看出BeanDefinitionLoader包含了各种加载bean定义的实例对象。

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

    从上述load方法可以看出,可以加载的bean定义的source类型包括:Class、Resource、Package和CharSequence四种。Class用AnnotatedBeanDefinitionReader处理、Resource用XmlBeanDefinitionReader处理、Package用ClassPathBeanDefinitionScanner,而CharSequence比较特殊,它按Class、Resource、Package的顺序处理,哪种处理成功就按哪种处理。

     当前souce是calss类型,所以通过AnnotatedBeanDefinitionReader处理。最终会调用AnnotatedBeanDefinitionReader的doRegisterBean方法。

    doRegisterBean:从给定的bean类中注册一个bean,并从类声明的批注中派生其元数据。

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(instanceSupplier);
		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));
				}
			}
		}
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

 new AnnotatedGenericBeanDefinition(annotatedClass)调用链如下。

1、AnnotatedGenericBeanDefinition bean定义首先设置了当前bean的类型beanClass

2、实例化类的抽象元数据的接口ClassMetadata的实现类。简单说该接口就是通过class获取该class的各种信息。比如是否抽象,是否是final的等。其中StandardAnnotationMetadata会获取该class上的注解。StandardClassMetadata会存储该class类型

public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
		setBeanClass(beanClass);
		this.metadata = new StandardAnnotationMetadata(beanClass, true);
	}
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
		super(introspectedClass);
		this.annotations = introspectedClass.getAnnotations();
		this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
	}
public StandardClassMetadata(Class<?> introspectedClass) {
		Assert.notNull(introspectedClass, "Class must not be null");
		this.introspectedClass = introspectedClass;
	}

 conditionEvaluator

处理@Conditional注解的,因此不会跳过。

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd)

abd.setScope(scopeMetadata.getScopeName())

描述Spring托管bean的范围特征,包括范围名称和scoped-proxy行为。默认是singleton,默认不创建作用域代理。此处scope为singleton。resolveScopeMetadata会通过当前bean定义的元数据信息获取指定类型注解的AnnotationAttributes。获取AnnotationAttributes会调用AnnotatedElementUtils如下方法,其中annotationName为@Scope类型的className.

public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
			String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {

		AnnotationAttributes attributes = searchWithGetSemantics(element, null, annotationName,
				new MergedAnnotationAttributesProcessor(classValuesAsString, nestedAnnotationsAsMap));
		AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
		return attributes;
	}

上述方法源码注释:在提供的element上方的注释层次结构中获取指定annotationName的第一个注释,并将该注释的属性与注释层次结构较低级别中的注释的匹配属性合并。
注释层次结构中较低级别的属性会覆盖较高级别中的同名属性,并且在单个注释内和注释层次结构中都完全支持@AliasFor语义。
相较于getAllAnnotationAttributes ,使用此方法将停止搜索注释层次一旦指定的第一个注释搜索算法annotationName已经找到。 结果,将忽略指定annotationName其他注解。

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd)

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
		else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(), Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}

		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}

		AnnotationAttributes role = attributesFor(metadata, Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}
		AnnotationAttributes description = attributesFor(metadata, Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}

查找该bean定义是否有某种注解或某种注解对应的AnnotationAttributes。然后设置该bean 定义对应的属性值。可以看出有@Lazt、@Primary等。

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName)

包装bean定义和bean名称


definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry)

根据情况判断是否要创建代理


BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry)

注册该bean定义到registry中。

  • listeners.contextLoaded(context):广播ApplicationPreparedEvent事件,并触发对应的事件。

ConfigFileApplicationListener :向context注册了一个BeanFactoryPostProcessor:PropertySourceOrderingPostProcessor实例;该实例后面会对我们的property sources进行重排序。

LoggingApplicationListener :向beanFactory中注册了一个名叫springBootLoggingSystem的单例bean

其它listener什么也没做。

refreshContext(context)

后续详解

afterRefresh(context, applicationArguments)

目前什么也没做,可重写该方法

listeners.started(context)

广播ApplicationStartedEvent事件,并触发对应的事件。这里主要关注TomcatMetricsBinder这个Listener

callRunners(context, applicationArguments)

调用所有实现了ApplicationRunner和CommandLineRunner接口的bean的run方法

listeners.running(context)

广播ApplicationReadyEvent事件,并触发对应的事件。

猜你喜欢

转载自blog.csdn.net/sinat_33472737/article/details/112800567