Springboot source code: automatic assembly process analysis

foreword

After writing the business framework, because the project depends on Spring IOC, after installing the project, when other projects are introduced, the dependent Bean will not be found. So use Springboot's automatic transfer, load the Bean when the project starts, and register it in the IOC container.

Springboot automatic assembly can be said to be the SPI mechanism defined by SpringBoot itself. The full name of SPI is Service Provider Interface. The SPI idea can also be called the SPI mechanism. It is a mechanism for finding service implementations for an interface.

text

When the project starts, the Class object of the startup class will be passed in. After the container is created, the incoming startup class registration will be packaged into a BeanDefinition and registered in the 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();
	}

The object of BtestApplication.class will eventually be stored in the primarySources property collection.

1: Register post processor

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

When creating a ConfigurableApplicationContext context object, the Spring internal processor class will be registered in the container, including the BeanFactoryPostProcessor that needs to be used later, and the ConfigurationClassPostProcessor post-processor is related to automatic assembly.

2: Register startup class

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

In the previous Spring, the Class object passed in by the system startup was stored in the primarySources collection, and now the objects in the collection are obtained and registered in the BeanFactory factory, and the annotations of this class need to be scanned later.

3: Container Refresh

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

The previous steps are all basic preparations. After the context object is created, the core process of Spring IOC is called to complete the scan registration, instantiation, and initialization of the Bean. The author wrote 16 articles on the process of Spring IOC in front of me. If you are interested, you can take a look.

4: Execute the BeanFactory post-processor

In step 1, a ConfigurationClassPostProcessor post processor has been registered in the BeanFactory factory

insert image description hereinsert image description here

The post-processor implements the BeanDefinitionRegistryPostProcessor interface, so its postProcessBeanDefinitionRegistry method will be called eventually.

The main function of this method is:

1. Obtain all BeanDefinitions and judge them one by one

2. Parse @Componet, @PropertySources, @ComponentScans, @Import, @ImportResource

Our startup class is configured with the @SpringBootApplication annotation, and the @SpringBootApplication annotation information is as follows:

@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 {
    
    

Since the startup class is configured with the @Import annotation, @Import will be used for parsing

5: @Import analysis processing

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

Since the import configured by the startup class is the AutoConfigurationImportSelector class, and this class implements the DeferredImportSelector interface, its selectImports method will not be called directly. There are many articles on the Internet saying that this method is dropped, but it is not. If the DeferredImportSelector interface is implemented, the Selector implementation class will be added to the collection, and its getAutoConfigurationEntry() method will be called later;

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

6: parse 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), see method 1 for detailed explanation

Method 1: getCandidateConfigurations

This method will load the files in the META-INF/spring.factories directory and get all configuration classes whose file KEY is 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()), see method 2 for details

Method 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;
	}

As long as we configure the key as org.springframework.boot.autoconfigure.EnableAutoConfiguration in the spring.factories file in the META-INF/ directory, and the value is the automatic assembly class we need to inject, Springboot will wrap the class into a BeanDefinition and inject it into the IOC in the container;

Summarize

When developing with Spring, because some classes in the project need to be injected into the IOC container in advance, we can use Springboot's automatic assembly, abide by its agreement, and configure the automatic assembly class into the spring.factories file in the META-INF/ directory , and specify the key as org.springframework.boot.autoconfigure.EnableAutoConfiguration. In this way, Springboot can inject this class into the IOC container.

If an ImportSelector implementation class implements the DeferredImportSelector interface, then the ImportSelector will not call the selectImports() method, but directly call the getAutoConfigurationEntry() method. There are many articles on the Internet that directly say that the entry is selectImports(), so learn to read the source code to learn See the essence clearly.

Guess you like

Origin blog.csdn.net/weixin_45031612/article/details/130668328