springboot启动流程 + 自动装配原理

简要说明

简单一点就是 : 扫描到spring.factories中的EnableAutoConfiguration,进行注入。比如RedisAutoConfiguration.class中的@bean注解,应该就明白,这里和spring中创建通过注解创建bean一样了。后面详细说明。 @Bean怎么注入ioc不明白可以去看一下spring ioc。
这里随便取一个spring.factories

springboot启动流程 + 自动装配原理_第1张图片
springboot启动流程 + 自动装配原理_第2张图片

那么现在问题就是spring是如何找到该类或者该注解,并且注入进容器的。
再简单说下。
就是在Spring ioc容器创建refresh()的时候,在执行beanFactoryPostProcessor链条的时候有类扫描到 springbootApplication主类上的注解@springBootApplication ,里的@EnableAutoConfiguration 里的@import(AutoConfIgurationImportSelector.class). AutoConfIgurationImportSelector类中会加载spring.factories中的EnableAutoConfiguration对应的类。后面会列出。将里面的bean统一转化为BeanDefinition等待后面初始化。

springboot启动流程

  1. 入口启动类
@EnableDiscoveryClient
@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserCenterApplication.class, args);
    }
}

springboot启动的入口,通过run进去就可以看到会初始化一个SpringApplication,然后执行run方法。

  1. SpringApplication的构造方法。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = deduceWebApplicationType();
		//读取化加载器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//读取监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
}

getSpringFactoriesInstances(XXXXX.class) 这个方法在springboot初始化经常会看到。从名字也可以看出,其实就是从META-INF/spring.factories通过反射加载该类型的类。

  1. SpringApplication.run具体执行过程 (这个是springApplication中的方法)
public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		//加载监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//触发starting事件(观察者模式,通知观察者listeners)
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			//加载环境参数
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			//banner图,忽略
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			//准备工作,将springbootApplication主类注册到beanfactory中的beanDefinitionMap中。
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			//spring容器的refresh()方法。 
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			//触发监听器
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

4.spring中的refresh()方法,spring中的核心流程。

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//执行BeanFactoryPostProcessors链条
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

5.在beanfactoryPostProcessor执行链条中,完成对自动装配类beanDefinition的加载。
6. ConfigurationClassPostProcessor (beanfactoryPostProcessor) 解析启动主类(DemoApplication),并且读取解析注解,也就是常说的核心注解(@SpringBootApplication ,@EnableAutoConfiguration ,@Import(AutoConfigurationImportSelector.class))。

ConfigurationClassPostProcessor.class
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	。。。
		do {
			//parse方法解析springApplication,解析自动装配的核心入口
			parser.parse(candidates);
			parser.validate();
			//得到parse出来的自动装配(autoConfiguration)的类
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			//将解析到configClasses元数据 读取到beanDefinitionMap中去
			this.reader.loadBeanDefinitions(configClasses);
	。。。
}

这一步可以看到ConfigurationClassPostProcessor类中parse方法解析启动类,将自动装配的类信息扫描到beanDefinitionMap中了。等后续的refresh()方法执行到finishBeanFactoryInitialization()完成初始化。

现在进入parse方法看一下:类信息是怎么扫描加载到beanDefinitionMap中的。

会执行AutoConfIgurationImportSelector类中的的方法。

AutoConfIgurationImportSelector.class
 @Override
public void process(AnnotationMetadata annotationMetadata,
	DeferredImportSelector deferredImportSelector) {
	//导入
	String[] imports = deferredImportSelector.selectImports(annotationMetadata);
	for (String importClassName : imports) {
		this.entries.put(importClassName, annotationMetadata);
	}
}

selectImports的实现

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//
		List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return StringUtils.toStringArray(configurations);
	}

你可能感兴趣的:(spring,spring,boot)