Spring beanFactoryPostProcessor

项目结构和代码

@Component
public class CustomerBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("CustomerBeanFactoryPostProcessor.postProcessBeanFactory");
    }
}
@Component
public class CustomerBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        System.out.println("CustomerBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry");
        AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(NotComponentService.class).getBeanDefinition();
        beanDefinitionRegistry.registerBeanDefinition("notComponentService", definition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("CustomerBeanDefinitionRegistryPostProcessor.postProcessBeanFactory");
    }
}
@Service
public class HelloService {
}


@Service
public class UserService {
}


public class NotComponentService {
}
@ComponentScan
public class DddApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DddApplication.class);
    }

}


 

beanFactory 初始化流程

 构造器

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

	private final AnnotatedBeanDefinitionReader reader;

	private final ClassPathBeanDefinitionScanner scanner;


	public AnnotationConfigApplicationContext() {
		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
		this.reader = new AnnotatedBeanDefinitionReader(this);
		createAnnotatedBeanDefReader.end();
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

	
	
	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		this();
		register(componentClasses);
		refresh();
	}
}

this()

首先调用父类构造器创建 beanFactory

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

	private final DefaultListableBeanFactory beanFactory;


	/**
	 * Create a new GenericApplicationContext.
	 * @see #registerBeanDefinition
	 * @see #refresh
	 */
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
}

创建 AnnotatedBeanDefinitionReader

	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(this.registry)

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

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

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

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		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;
	}


	private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(beanName, definition);
		return new BeanDefinitionHolder(definition, beanName);
	}

该方法的逻辑是向 beanFactory 添加五个 postProcessor

 此时无参构造已经执行完成,该构造一共做了三件事情

  1. 调用父类 GenericApplicationContext 的无参构造,创建  DefaultListableBeanFactory
  2. 创建 AnnotatedBeanDefinitionReader,添加五个 postProcessor的beanDefinition 到 beanFactory
  3. 创建 ClassPathBeanDefinitionScanner

register()

register(componentClasses) 的作用就是调用 AnnotatedBeanDefinitionReader.register() 将启动类注册到 beanDefinition

 

beanFactory refresh()

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

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

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

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

				// 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();
				contextRefresh.end();
			}
		}
	}

prepareBeanFactory()

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		}
	}

向 beanFactory 添加了两个 beanPostProcessor

添加四个组件

添加默认的 enviroment 组件

invokeBeanFactoryPostProcessors()

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// WARNING: Although it may appear that the body of this method can be easily
		// refactored to avoid the use of multiple loops and multiple lists, the use
		// of multiple lists and multiple passes over the names of processors is
		// intentional. We must ensure that we honor the contracts for PriorityOrdered
		// and Ordered processors. Specifically, we must NOT cause processors to be
		// instantiated (via getBean() invocations) or registered in the ApplicationContext
		// in the wrong order.
		//
		// Before submitting a pull request (PR) to change this method, please review the
		// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
		// to ensure that your proposal does not result in a breaking change:
		// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}

ConfigurationClassPostProcessor

ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor,用于处理一些配置信息和注解扫描,并且该处理器执行的时候有优先级顺序,优先执行PriorityOrdered,然后执行Ordered,最后执行默认没有优先级的处理器。

并且ConfigurationClassPostProcessor 是 spring框架中最重要的BeanFactoryPostProcessor,也是最重要的内置组件之一

作用:

  1. 对于候选配置类使用CGLIB Enhancer增强
  2. 解析处理@PropertySource 注解
  3. 解析@ComponentScan注解,扫描@Configuration、@Service、@Controller、@Repository和@Component注解并注册BeanDefinition
  4. 解析@Import注解,然后进行实例化,并执行ImportBeanDefinitionRegistrar的registerBeanDefinitions逻辑,或者ImportSelector的selectImports逻辑
  5. 解析@ImportResource注解,并加载相关配置信息
  6. 解析方法级别@Bean注解并将返回值注册成BeanDefinition
  7. 注册ImportRegistry到容器中,用于处理ImportAware

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	// 候选配置类定义列表
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	// 获取容器中所有bean定义的名字
	String[] candidateNames = registry.getBeanDefinitionNames();
	// 循环名字
	for (String beanName : candidateNames) {
		// 获取bean定义
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			// 省略...
		}
		// 查看bean是否是ConfigurationClass
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			// 加入到候选配置类定义列表
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

	// 没有@Configuration的bean就返回
	if (configCandidates.isEmpty()) {
		return;
	}

	// 省略排序,beanName生成规则,环境变量等...

	// 构造一个配置类解析器,用来把bean定义的重要信息提取转化为ConfigurationClass
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	// 候选配置类定义列表(查重)
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	// 存储已解析的配置类列表
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		// 核心解析流程,重要!
        // 其实就是把类上面的特殊注解解析出来,最终封装成 BeanDefinition 注册到工厂
		parser.parse(candidates);
		parser.validate();

		// 获取解析器中解析出的配置类ConfigurationClass:parser.getConfigurationClasses()
		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		// 过滤掉已解析的配置类
		configClasses.removeAll(alreadyParsed);

		// 构造一个bean定义读取器
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		// 读取ConfigurationClass获取衍生bean定义并注册到容器
        // 这里是去真正的注册!刚刚在解析 @Import、@Bean、@Import 等注解的时候,
        // 并没实际创建 BeanDefinition 并注册,而是将数据暂存起来
		this.reader.loadBeanDefinitions(configClasses);
		// 加入已解析配置类
		alreadyParsed.addAll(configClasses);
		// 清空候选配置类定义列表
		candidates.clear();
		// 如果容器中bean定义有新增
        // 这样做主要是防止有些 Bean 没有注册
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			/** 查找出新增的配置类bean定义 start **/
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			Set<String> alreadyParsedClasses = new HashSet<>();
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			/**查找出新增的配置类bean定义 end , 最终新的配置bean定义加入到候选配置类定义列表 **/
			// 覆盖所有beanName,为下一次判断是否有新增
			candidateNames = newCandidateNames;
			
		}
	}
	while (!candidates.isEmpty()); // 只要候候选配置类定义列表不为空就一直循环下去

	// 省略...
}

上面的代码比较长,但流程很清晰,总结一下

  1. 查找spring容器中的配置类bean定义,存储候选列表
  2. 使用解析器,解析候选列表中的配置类bean定义,根据配置的扫描范围把相关的类都解析为ConfigurationClass对象(其中@CommpentScan下扫描的类直接注册bean定义)
  3. 使用读取器,读取上一步解析出的新未解析ConfigurationClass,注册相关bean定义
  4. 清空候选列表
  5. 继续查询spring容器,如果有新增的配置类bean定义,读取加入候选列表,跳转回第2步

 

上文ConfigurationClassPostProcessor对parser具体使用主要有三处

  • 初始化构造parser,传入了BeanDefinitionRegistry等构造传参数
  • 调用parse方法解析bean定义集合
  • 通过getConfigurationClasses方法获取解析结果configurationClasses

ConfigurationClassParser中一个属性configurationClasses,用来存放解析出来的结果

class ConfigurationClassParser {
  private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
}

解析(parse)的重点责任就是根据传入的参数(bean定义列表)转化为Map<ConfigurationClass, ConfigurationClass>,下面重点分析分析方法:parse方法:

Parser#parse()

org.springframework.context.annotation.ConfigurationClassParser#parse() 

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	// 循环
	for (BeanDefinitionHolder holder : configCandidates) {
		// 获取bean定义
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			// 根据bean定义的类型走不通参数的重载parse方法
            // 扫描注解得到的 BeanDefinition
			if (bd instanceof AnnotatedBeanDefinition) {
				parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
			}
			else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                // 非扫描注解得到的 BeanDefinition
				parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
			}
			else {
				parse(bd.getBeanClassName(), holder.getBeanName());
			}
		}
		// 省略catch...
	}
     // 处理延迟加载的 importSelect?为什么要延迟加载,估计就是为了延迟吧
	this.deferredImportSelectorHandler.process();
}

org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass 

protected void processConfigurationClass(ConfigurationClass configClass)  {
    // 根据注解信息判断是不是跳过解析
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    // 处理 Imported 的情况,就是当前这个注解类有没有被别的类 import
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
                existingClass.mergeImportedBy(configClass);
            }
            return;
        } else {
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }

    // 递归地处理配置类及其超类层次结构
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        // 处理配置类
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    this.configurationClasses.put(configClass, configClass);
}

又是一个循环,调用doProcessConfigurationClass方法,如果有返回值,递归调用doProcessConfigurationClass,看spring的注释说递归解析配置类和他的父类,所以这代码的意思就是解析配置类,如果有父类再解析父类,如果父类有父类再一直解析下去。

最后this.configurationClasses.put(configClass, configClass);就是把上一步根据bean定义生成的ConfigurationClass对象存入解析的结果map:configurationClasses,实际上,对解析结果的添加只有这一处代码

如果单单看到这里,parser的功能就是把传入的多个bean定义循环转换为ConfigurationClass并存入解析结果中,相当于传入多少bean定义就转换多少ConfigurationClass对象

单parse方法的功能远不止如此,重点在doProcessConfigurationClass方法

doProcessConfigurationClass

org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

protected final SourceClass doProcessConfigurationClass(
		ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
		throws IOException {
    // 1.内部类  这一步看看有没有内部类
	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		processMemberClasses(configClass, sourceClass, filter);
	}

	// 2.@PropertySource 这一步解析@PropertySource注解,更改配置文件位置时会使用,一般使用默认位置,不咋更改
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			processPropertySource(propertySource);
		}
		// 省略...
	}

	// 3.@ComponentScan 这一步就很重要了,解析@ComponentScan注解
    // 此处或扫描到 @ComponentScan 注解包下面的所有加了 @Component、@Service 等注解的类
    // 注意的是,每扫描到一个符合条件的类,都要进行递归扫描,重新调用 doProcessConfigurationClass() 方法
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		for (AnnotationAttributes componentScan : componentScans) {
			// 这里扫描出来所有 @Component,并且把扫描的出来的普通 bean 放到 bdMap 当中
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			// 检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析
            // 检查扫描出来的类当中是否还有 configuration
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					// 获取bean定义
					bdCand = holder.getBeanDefinition();
				}
				//判断是不是配置类
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					// 检查扫描出来的配置类有没有配置类,进行再次解析,递归调用
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}

	// 4.@Import 解析@Import注解
	processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

	// 5.@ImportResource解析@ImportResource解析
    // 这里只是去解析配置文件的位置添加到配置类的 importedResources 中,没有进行扫描处理
	AnnotationAttributes importResource =
			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	if (importResource != null) {
		String[] resources = importResource.getStringArray("locations");
		Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
		for (String resource : resources) {
			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
			configClass.addImportedResource(resolvedResource, readerClass);
		}
	}

	// 6.@Bean 解析带有@Bean注解的方法,加入到configClass的beanMethods属性中
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// 6.接口@Bean 解析实现的接口中带有@Bean注解的默认方法,加入到configClass的beanMethods属性中
	processInterfaces(configClass, sourceClass);

	// 7.父类 如果有父类返回父类,以继续解析
	if (sourceClass.getMetadata().hasSuperClass()) {
		String superclass = sourceClass.getMetadata().getSuperClassName();
		if (superclass != null && !superclass.startsWith("java") &&
				!this.knownSuperclasses.containsKey(superclass)) {
			this.knownSuperclasses.put(superclass, configClass);
			// Superclass found, return its annotation metadata and recurse
			return sourceClass.getSuperClass();
		}
	}

	// 没有父类,解析结束
	return null;
}

这个方法很长,主要包含以下几个功能

  • 解析内部类
  • 解析@PropertySource注解
  • 解析@ComponentScan注解,扫描指定包下的所有@Component类,直接注册bean定义至spring,并递归解析
  • 解析@Import注解
  • 解析@ImportResource注解
  • 解析@Bean
  • 解析实现接口中的@Bean
  • 返回父类

所以doProcessConfigurationClass这一步的重点工作就是扫描某个配置类的注解,根据注解功能找到指定扫描范围的类,递归解析(调用parse或processConfigurationClass方法)

比如@ComponentScan就是扫描到basePackages指定路径下的类,然后通过递归调用parse解析这些类,@Import通过value属性指定的类,递归调用processConfigurationClass解析

重点这个递归,有了它就可以实现一个bean定义解析出多个ConfigurationClass对象

这里有个特例,@ComponentScan扫描的类会被直接注册到spring容器

解析内部类
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

也就是说如果一个类有@Component注解,processMemberClasses内部会解析当前类的内部类,如果是配置类,则会递归调用processConfigurationClass去解析这个内部类

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException {
	// 获取所有内部类
	Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
	if (!memberClasses.isEmpty()) {
		// 候选列表
		List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
		for (SourceClass memberClass : memberClasses) {
			// 如果是配置类,加入候选
			if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
					!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
				candidates.add(memberClass);
			}
		}
		OrderComparator.sort(candidates);
		// 循环候选列表
		for (SourceClass candidate : candidates) {
			if (this.importStack.contains(configClass)) {
				this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
			}
			else {
				this.importStack.push(configClass);
				try {
					// 递归解析内部类
					processConfigurationClass(candidate.asConfigClass(configClass), filter);
				}
				finally {
					this.importStack.pop();
				}
			}
		}
	}
}

解析@ComponentScan
Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

componentScanParser内部有个scaner(扫描器),扫描@Component注解的类,包括子注解@Configuration@Service等(这过程还会直接把扫描到的类注册bean定义)

org.springframework.context.annotation.ComponentScanAnnotationParser#parse 

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    // Spring 自己 new 的一个 ClassPathBeanDefinitionScanner 进行扫描!这个类见到很多次了
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                                                                                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    // 下面这一堆都是在配置扫描策略...
    
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    // 设置扫描器的 BeanName 生成器
    scanner.setBeanNameGenerator(useInheritedGenerator ?
                                 this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass));

    // 设置 componentScan 的代理模式
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    } else {
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }

    // 设置扫描器的资源模式
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));

    // 看看 componentScan 注解是否设置了 includeFilters 属性
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addIncludeFilter(typeFilter);
        }
    }

    // 看看 componentScan 注解是否设置了 excludeFilters 属性
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addExcludeFilter(typeFilter);
        }
    }

    // 	看看 componentScan 注解是否设置了 lazyInit 属性
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }

    // 此集合放的是扫描的路径
    Set<String> basePackages = new LinkedHashSet<>();
    // 获取componentScan注解的basePackages属性
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                                                               ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });
    // 开始扫描
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // 存储创建出的 BeanDefinitionHolder
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 依次扫描每个包中的相关注解,创建获取到所有的 BeanDefinition
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 生成 Bean 的名称
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
                // 包装成 BeanDefinitionHolder
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 创建代理
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                 // 注册到上下文工厂
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

扫描的核心是 findCandidateComponents 方法,这个方法就是寻找到 @Component 和 @Component 的衍生注解的类。

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents 

回到 org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

循环判断扫描到的类是否是ConfigurationClass,如果是则递归解析

解析@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

参数getImports方法获取到了当前配置类所有@Import注解指定的类集合,然后进入processImports

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

	// 省略...
	
	// 循环所有@Import指定的类
	for (SourceClass candidate : importCandidates) {
		// 如果这个类实现了ImportSelector,即导入多个类
		if (candidate.isAssignable(ImportSelector.class)) {
			// 实例化这个导入的ImportSelector类
			ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
							this.environment, this.resourceLoader, this.registry);
							
			// 省略一些过滤...
			
			// 如果是延迟导入,交给deferredImportSelectorHandler处理
			if (selector instanceof DeferredImportSelector) {
				this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
			}
			// 普通的多个导入
			else {
				// 找到导入的多个类
				String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
				Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
				// 递归调用当前方法
				processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
			}
		}
		// 如果这个类实现了ImportBeanDefinitionRegistrar
		else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
			// 实例化这个ImportBeanDefinitionRegistrar类
			ImportBeanDefinitionRegistrar registrar =
							ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
									this.environment, this.resourceLoader, this.registry);
			// 加入该类到当前配置类解析对象ConfigurationClass的importBeanDefinitionRegistrars列表属性中
			configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
		}
		// 排除上面两种情况,这个类就是个普通类
		else {
			// 省略...
			// 递归解析这个类
			processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
		}
	}
		
}

这里涉及的内容较多,主要分几种情况

  • 如果导入的就是普通类 直接递归解析这个类
  • 如果导入的类实现了ImportBeanDefinitionRegistrar(导入的bean定义注册器) 直接实例化这个类,并加入到当前解析配置类的importBeanDefinitionRegistrars(列表)属性中,以便后续调用其registerBeanDefinitions方法
  • 如果导入的是实现了ImportSelector的普通类(多类导入) 直接实例化这个类,循环selectImports方法放回的多个类,递归调用processImports
  • 如果导入的是实现了DeferredImportSelector的特殊ImportSelector类(延迟多类导入) 直接实例化这个类,委托给解析器内部的deferredImportSelectorHandler处理,deferredImportSelectorHandler内部把这个实例对象和当前解析类封装为DeferredImportSelectorHolder, 暂存入解析器内部的deferredImportSelectors属性 因为是延迟,所以这里暂存了一下,并没有像普通ImportSelector那样循环递归解析processImports,而其真正的执行实际就是上文parse主方法最后的那一句this.deferredImportSelectorHandler.process(),而process方法内部依然是循环递归processImports方法,只不过延迟了,相当于所有的类被解析过才开始解析DeferredImportSelector导入的类

解析@Bean
        // Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

这里通过解析当前配置类@Bean方法,并将方法打包为BeanMethod存入配置类beanMethods属性中

总结Parser

基本上parser内部解析的重点方法都分析完了,总结一下,parser都干了什么?

  • parser作为一个解析器,根据传入的配置类解析出多个ConfigurationClass对象

  • 配置类实际上是一个树形结构,他的子节点包含@ComponentScan扫描到的配置类,@Import引入的普通类等

  • 而spring中这个树结构的根节点一般就是用户定义的主启动类

  • parser通过递归解析完成整个树的解析(解析成多个ConfigurationClass对象),并把解析结果存入parser内部configurationClasses属性

  • parser解析某个配置类节点过程中 会把其@Bean方法加入ConfigurationClass对象的属性beanMethods列表中 会把@Import注解引入的ImportBeanDefinitionRegistrar加入ConfigurationClass对象的属性importBeanDefinitionRegistrars列表中 会把@Import注解引入的DeferredImportSelector加入到解析器内部的属性deferredImportSelectors列表中,延迟到所有节点解析完成后再统一解析

  • 在解析某配置类的@ComponentScan注解时,扫描到的类会同时注册bean定义至spring容器

所以最终结果是把根配置类下的整个树扫描,生成多个ConfigurationClass对象,同时@ComponentScan扫描到的配置类会直接注册bean定义

最后画个图梳理整个解析过程

image.png

DeferredImportSelector只不过是延迟导入,从整个解析过程来看最终结果与@Import一样

Reader

相比于parser,reader的任务轻松多了,主要任务就是把parser解析出的ConfigurationClass集合读取并转换为bean定义,并最终注册到spring容器

回到 org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}
private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

	// 省略的

	// 注册被Import引入的类,标识ConfigurationClass.isImported==true
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	// 注册@Bean的工厂方法,存储在ConfigurationClass.beanMethods属性中
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}

	// ImportedResource(忽略)
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 执行ImportBeanDefinitionRegistrar实现注册用户自定义bean定义,存储在ConfigurationClass.importBeanDefinitionRegistrars属性中
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

Parser注册了@ComponentScan扫描的bean定义,而Reader主要注册了这几个bean定义

  • 通过@Import引入的(标识ConfigurationClass.isImported==true)
  • @Bean的工厂方法(存储在ConfigurationClass.beanMethods属性中)
  • 执行ImportBeanDefinitionRegistrar实现注册用户自定义bean定义(存储在ConfigurationClass.importBeanDefinitionRegistrars属性中)

这么一看Reader反而成了捡漏的了...,就是把Parser没注册的bean定义都注册上

其中loadBeanDefinitionsFromRegistrars这步就是执行ImportBeanDefinitionRegistrar实现的registerBeanDefinitions方法,即用户自定义注册bean常用的@Import+ImportBeanDefinitionRegistrar模式的实际执行时机

image.png

回到 org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()

可以看到我没自定义的 bean已经注册进容器了

  Ordered  BeanDefinitionRegistryPostProcessors

all other BeanDefinitionRegistryPostProcessors

执行自定义的 BeanDefinitionRegistryPostProcessor,并向容器中注册一个 beanDefition

beanDefinitionRegisterPostProcesso.rpostProcessBeanFactory

接下来按照优先级依次执行  BeanFactoryPostProcessor

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/903078.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的宿舍管理系统设计与实现(源码+定制+开发)宿舍信息管理平台、智能宿舍系统开发、学生宿舍管理平台设计、宿舍入住与信息管理

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

华为:高级ACL 特定ip访问特定ip命令

网络拓扑图&#xff1a; 网络环境&#xff1a; 全网互通即可 1.创建一个名为test的高级ACL acl name test advance 2.添加规则 ##拒绝所有ip访问 rule 10 deny ip source any destination 192.168.1.10 0.0.0.0 只允许特定ip访问特定ip rule 5 permit ip source 192.168.2.10…

C++与现代开发实践第三节:多线程与并发编程

第四章&#xff1a;C与现代开发实践 第三节&#xff1a;多线程与并发编程 在这一课中&#xff0c;我们将详细探讨多线程与并发编程的各个方面&#xff0c;特别是从线程的创建、管理到高级的优化技术&#xff0c;并且通过复杂的实战案例来展示如何应对并发问题。最后&#xff…

并联 高电压、高电流 放大器实现 2 倍输出电流模块±2A

1.1 并联输出电路设计注意事项 直接对两个功率运算放大器的输出进行硬接线并不是一种好的电气做法。如果两个运算放大器的输出直接连接在一起&#xff0c;则可能会导致不均匀的电流共享。这是因为其中的每个运算放大器都尝试强制施加略微不同的 Vout 电压&#xff0c;该电压取决…

【HarmonyOS NEXT】使用 Navigation 对折叠屏设备页面进行分栏展示,优化 UI 交互

关键词&#xff1a;折叠屏、navigation、router、路由、分栏、UI 随着科技的发展&#xff0c;手机设备形态也由一面屏向多面屏进行发展&#xff0c;那么软件的UI适配也面临着问题&#xff0c;本篇文章主要解决大屏设备的页面 UI 适配问题&#xff0c;如折叠屏&#xff0c;平板&…

Spring Boot 3项目创建与示例(Web+JPA)

以下是一个Spring Boot 3.3.4整合JPA的示例,它展示了如何在Spring Boot应用程序中使用JPA进行数据持久化。 版本与环境 Spring Boot 3.3.4数据库: MySQL 8.0.40, MySQL的安装使用可以参考: MySQL 8 下载与安装攻略JDK 17Maven 3.6项目创建 可以使用Spring Initializr 初始…

一家生物技术企业终止,科创属性可能不足,报告期内专利数猛增

轩凯生物九成以上营业收入来源于植物营养领域&#xff0c;收入来源结构单一&#xff0c;产品下游应用领域较为集中。报告期内公司应收账款账面价值逐年上升&#xff0c;回款比例显著低于前两年&#xff0c;遭交易所问询是否存在较大的坏账风险。 轩凯生物核心技术是否成熟以及是…

ssm智慧社区电子商务系统+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 [2 系统…

Java面向对象编程进阶(四)

Java面向对象编程进阶&#xff08;四&#xff09; 一、equals()方法的使用二、toString()方法的使用三、复习 一、equals()方法的使用 适用性&#xff1a;任何引用数据都可以使用。 自定义的类在没有重写Object中equals()方法的情况下&#xff0c;调用的就是Object类中声明的…

C++初阶教程——C++入门

一、本章主要内容 C在C的基础之上&#xff0c;加入了面向对象编程的思想&#xff0c;并增加了许多有用的库以及编程范式。可以说&#xff0c;C是C的子集。在这章的内容中&#xff0c;笔者将会为诸位读者讲C如何补充C语言的一些不足。比如&#xff1a;作用域、IO、函数、指针等。…

Swift Macro 在业务开发中的探索与实践

简介 Swift Macro 在 Swift 5.9 版本中正式引入&#xff0c;且需配合 Xcode 15 使用。Swift Macro 作为一种新的设计方法&#xff0c;致力于帮开发者降低编写重复代码的繁琐&#xff0c;以更为简洁优雅的方式去实现。 在 OC 中&#xff0c;有大家熟知的宏 #define&#xff0c;…

Pseudo Multi-Camera Editing 数据集:通过常规视频生成的伪标记多摄像机推荐数据集,显著提升模型在未知领域的准确性。

2024-10-19&#xff0c;由伊利诺伊大学厄巴纳-香槟分校和香港城市大学的研究团队提出了一种创新方法&#xff0c;通过将常规视频转换成伪标记的多摄像机视角推荐数据集&#xff0c;有效解决了在未知领域中模型泛化能力差的问题。数据集的创建&#xff0c;为电影、电视和其他媒体…

练习LabVIEW第二十三题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第二十三题&#xff1a; 建立一个枚举控件&#xff0c;其内容为张三、李四、王五共三位先生&#xff0c;要求当枚举控件显…

Spring Boot 实现文件分片上传和下载

文章目录 一、原理分析1.1 文件分片1.2 断点续传和断点下载1.2 文件分片下载的 HTTP 参数 二、文件上传功能实现2.1 客户端(前端)2.2 服务端 三、文件下载功能实现3.1 客户端(前端)3.2 服务端 四、功能测试4.1 文件上传功能测试4.2 文件下载功能实现 参考资料 完整案例代码&…

分类预测|基于WOA鲸鱼优化K近邻KNN的数据分类预测Matlab程序 多特征输入多类别输出GWO-KNN

文章目录 一、基本原理原理流程总结 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 鲸鱼优化算法&#xff08;WOA&#xff0c;Whale Optimization Algorithm&#xff09;是一种模拟座头鲸捕猎行为的启发式优化算法&#xff0c;适用于解决各种优化问题。在K近邻&…

深度探索:超实用阿里云应用之低功耗模组AT开发示例

今天我们讲解一款低功耗4G全网通模组作为例子&#xff0c; 基于Air780EP模组AT开发的阿里云应用教程&#xff0c; 本文同样适用于以下型号&#xff1a; Air700ECQ/Air700EAQ/Air700EMQ Air780EQ/Air780EPA/Air780EPT/Air780EPS Air780E/Air780EX/Air724UG… 1、相关准备工作 …

大白话讲解分布式事务-SEATA事务四种模式(内含demo)

因为这里主要是讲解分布式事务&#xff0c;关于什么是事务&#xff0c;以及事务的特性&#xff0c;单个事务的使用方式&#xff0c;以及在Spring框架下&#xff0c;事务的传播方式&#xff0c;这里就不再赘述了。但是我这里要补充一点就是&#xff0c;一提到事务大家脑子里第一…

假如浙江与福建合并为“浙福省”

在中国&#xff0c;很多省份之间的关系颇有“渊源”&#xff0c;例如河南与河北、湖南与湖北、广东与广西等等&#xff0c;他们因一山或一湖之隔&#xff0c;地域相近、文化相通。 但有这么两个省份&#xff0c;省名没有共通之处&#xff0c;文化上也有诸多不同&#xff0c;但…

[简易版] 自动化脚本

前言 uniapp cli项目中没办法自动化打开微信开发者工具&#xff0c;需要手动打开比较繁琐&#xff0c;故此自动化脚本就诞生啦~ 实现 const spawn require("cross-spawn"); const chalk require("picocolors"); const dayjs require("dayjs&quo…

7.使用Redis进行秒杀优化

目录 1. 优化思路 总结之前实现的秒杀过程 下单流程 2. 使用Redis完成秒杀资格判断和库存 0. Redis中数据类型的选用 1.将优惠券信息保存到Redis中 2.基于Lua脚本&#xff0c;判断秒杀库存、一人一单&#xff0c;决定用户是否抢购成功 3. 开启新协程&#xff0c;处理数…