Springboot源码:自动装配流程解析

前言

前面在写业务框架后,由于项目依赖的Spring IOC,单将该项目install后,在其它项目引入时,会找不到所依赖的Bean。所以利用Springboot的自动转配,在项目启动时加载Bean,并注册到IOC容器中。

Springboot自动装配可以说是SpringBoot自己定义的SPI机制,SPI 的全名为 Service Provider Interface ,SPI 思想 也可以叫做 SPI机制 ,它就是为某个接口寻找服务实现的机制。

正文

项目启动时,会传入启动类的Class对象,在创建完容器后,会将该传入的启动类注册包装成BeanDeifinition后注册到BeanFactory中。

    public static void main(String[] args) {
    
    
        //这里传入启动类对象
        SpringApplication.run(BtestApplication.class, args);
    }
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    
    
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
        //这里存放启动类传入的Class对象
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

BtestApplication.class 这个对象最终会被存入到primarySources属性集合中。

1:注册后置处理器

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    
    

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
    
    
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
    
    
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
    
    
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
		//注册ConfigurationClassPostProcessor 工厂后置处理器
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    
    
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
		//注册AutowiredAnnotationBeanPostProcessor 工厂后置处理器,用于处理器@Autowire等
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    
    
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		//注册AutowiredAnnotationBeanPostProcessor 工厂后置处理器,用于处理器@Resoruce注解等
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    
    
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    
    
			RootBeanDefinition def = new RootBeanDefinition();
			try {
    
    
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
    
    
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
    
    
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
    
    
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}

在创建ConfigurableApplicationContext上下文对象时,会往容器中注册Spring内部处理器类,包括后面需要用到的BeanFactoryPostProcessor,跟自动装配相关的是ConfigurationClassPostProcessor后置处理器。

2:注册启动类

	private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
    
    
        //设置系统环境参数
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		bootstrapContext.close(context);
		if (this.logStartupInfo) {
    
    
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
        //获取Bean工厂
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
    
    
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
    
    
			((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
			if (beanFactory instanceof DefaultListableBeanFactory) {
    
    
				((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
			}
		}
		if (this.lazyInitialization) {
    
    
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
		// Load the sources
        //获取存放启动类Class对象的集合
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
        //将其注册到Bean工厂中
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}
	public Set<Object> getAllSources() {
    
    
		Set<Object> allSources = new LinkedHashSet<>();
		if (!CollectionUtils.isEmpty(this.primarySources)) {
    
    
			allSources.addAll(this.primarySources);
		}
		if (!CollectionUtils.isEmpty(this.sources)) {
    
    
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}

在前面Spring将系统启动所传入的Class对象存入到了primarySources集合中,现将该集合中的对象获取出来并注册到BeanFactory工厂中,后续需要扫描该类的注解。

3:容器刷新

public void refresh() throws BeansException, IllegalStateException {
    
    
		synchronized (this.startupShutdownMonitor) {
    
    
			// 容器刷新前准备工作
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//创建Bean工厂,解析配置
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// bean工厂准备工作
			prepareBeanFactory(beanFactory);

			try {
    
    
				//拓展接口,留给子类进行实现拓展
				postProcessBeanFactory(beanFactory);

				// 注册执行,BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册创建BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// 这个方法主要作用就是使用国际化,定制不同的消息文本,比如定义了一个Person的Bean,它有name属性,我们需要在不同的国家展示对应国家所在语言名称,这时候就可以使用国际化了。
				initMessageSource();

				// Initialize event multicaster for this context.
				//初始化应用事件广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//拓展接口,留给子类进行实现拓展,springboot就对该方法进行了处理
				onRefresh();

				// Check for listener beans and register them.
				//将内部的、以及我们自定义的监听器添加到缓存中,为后续逻辑处理做准备。还有添加事件源到缓存中。
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//实例化剩下非懒加载的Bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				//使用应用事件广播器推送上下文刷新完毕事件(ContextRefreshedEvent )到相应的监听器。
				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();
			}
		}
	}

前面步骤都是基本准备工作,创建完上下文对象之后,调用Spring IOC的核心流程,完成Bean的扫描注册、实例化、初始化工作。笔者前面写了16篇Spring IOC的流程文章,有兴趣可以看一下。

4:执行BeanFactory后置处理器

在步骤1中,已经往BeanFactory工厂中注册了一个ConfigurationClassPostProcessor后置处理器

在这里插入图片描述在这里插入图片描述

该后置处理器实现了BeanDefinitionRegistryPostProcessor接口,所以最终会调用其postProcessBeanDefinitionRegistry方法。

该方法主要作用:

1、获取所有的BeanDefinition,挨个循环判断

2、对@Componet、@PropertySources、@ComponentScans、@Import、@ImportResource进行解析处理

我们启动类配置了@SpringBootApplication注解,@SpringBootApplication注解信息如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
    
     @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    
    

@EnableAutoConfiguration:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    
    

由于启动类配置了@Import注解,所以会动@Import进行解析操作

5: @Import解析处理

	private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {
    
    

		if (importCandidates.isEmpty()) {
    
    
			return;
		}

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
    
    
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
    
    
			this.importStack.push(configClass);
			try {
    
    
				for (SourceClass candidate : importCandidates) {
    
    
					if (candidate.isAssignable(ImportSelector.class)) {
    
    
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
    
    
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
                        //如果Import选择器 实现了DeferredImportSelector接口,则添加到容器里面。后续会调用其getAutoConfigurationEntry方法
						if (selector instanceof DeferredImportSelector) {
    
    
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
    
    
                            //调用Import选择器的selectImports方法,返回需要注册的BeanName
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
    
    
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
    
    
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
    
    
				throw ex;
			}
			catch (Throwable ex) {
    
    
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
    
    
				this.importStack.pop();
			}
		}
	}

由于启动类配置的Import是AutoConfigurationImportSelector类,而该类实现了DeferredImportSelector接口,所以不会直接调用其selectImports方法,网上有很多文章说是掉这个方法进来的,其实并不是。如果实现了DeferredImportSelector接口,会将该Selector实现类加入到集合中,在后续调用其getAutoConfigurationEntry()方法;

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    
    
}	

6:getAutoConfigurationEntry解析

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    
    
		if (!isEnabled(annotationMetadata)) {
    
    
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //获取META/INF/spring.factories
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

getCandidateConfigurations(annotationMetadata, attributes),见方法1详解

方法1:getCandidateConfigurations

该方法会加载META-INF/spring.factories目录下的文件,并获取文件KEY为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有配置类。

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    
    
		List<String> configurations = new ArrayList<>(
				SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
		ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
		Assert.notEmpty(configurations,
				"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()),见方法2详解

方法2:loadFactoryNames

	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    
    
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
    
    
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
        //factoryTypeName=org.springframework.boot.autoconfigure.EnableAutoConfiguration
		String factoryTypeName = factoryType.getName();
        //加载获有的配置类放到缓存中,并从中获取KEY为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置类
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    
    
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
    
    
			return result;
		}

		result = new HashMap<>();
		try {
    
    
            //FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
            //加载配置文件中的所有KEY-VELUE配置类,并将其放入缓存中
			while (urls.hasMoreElements()) {
    
    
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
    
    
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
    
    
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
    
    
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

只要我们在META-INF/目录下的spring.factories文件中配置key为org.springframework.boot.autoconfigure.EnableAutoConfiguration,值为我们需要注入的自动装配类,Springboot会将该类包装成BeanDefinition并注入到IOC容器中;

总结

使用Spring开发时,由于项目中某些类需要提前注入到IOC容器中时,我们可以利用Springboot的自动装配,遵守其约定,将自动装配类配置到META-INF/目录下的spring.factories文件中,并指定key为org.springframework.boot.autoconfigure.EnableAutoConfiguration。这样Springboot就可以将该类注入到IOC容器中。

如果一个ImportSelector实现类,实现了DeferredImportSelector接口,那么该ImportSelector并不会调用selectImports()方法,而是直接调用getAutoConfigurationEntry()方法,网上有很多文章直接说入口是selectImports(),所以学会看源码,才能看清本质。

猜你喜欢

转载自blog.csdn.net/weixin_45031612/article/details/130668328