@Configuration注解加载过程

22 篇文章 0 订阅
订阅专栏

@Configuration注解加载过程

一、注解加载过程分析

  1. 启动类调用main方法,其中调用SpringApplicationBuilder的run方法

    public static void main(String[] args) {
    		new SpringApplicationBuilder(ElawApplication.class).web(true).run(args);
    }
    
  2. run方法中使用AtomicBoolean running标志来记录是否已经在启动中,若未启动则进入同步代码块调用SpringApplication类的run方法进行构造ConfigurableApplicationContext上下文对象
    在这里插入图片描述
    请添加图片描述
    在这里插入图片描述

  3. SpringApplication的run方法中调用自身的createApplicationContext来创建对象
    在这里插入图片描述

  4. createApplicationContext方法根据webEnvironment来判断生成哪个上下文对象,webEnvironment用于标识是否为web应用,在默认情况下,如果是Web应用,则会创建AnnotationConfigEmbeddedWebApplicationContext类的对象;否则会创建AnnotationConfigApplicationContext类的对象;而 webEnvironment 这个变量是由项目的classpath下是否存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext,如果存在其中的一个,则为true;否则为false。
    在这里插入图片描述

  5. 以AnnotationConfigApplicationContext为源码示例,构造方法中会调用AnnotatedBeanDefinitionReader的构造方法来实例化注解的BeanDefinition。
    在这里插入图片描述

  6. 在AnnotatedBeanDefinitionReader构造方法中会调用自身的另一个带有环境对象的构造函数,环境对象使用getOrCreateEnvironment方法来获取,

    在该构造函数中会调用AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)来手动创建(也就是硬编码)注解对应的PostProcessor。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

其中,这些PostProcessor的类路径都是在代码中写死的,如果容器中不存在该PostProcessor的BeanDefinition,则手动创建并加入到容器中,

二、Configuration注解详解

1. 注解作用:

​ @Configuration标识的类有这些特性:可以声明多个@Bean方法,且在运行时被spring容器处理来生成BeanDefinition。@Configuration类是被AnnotationConfigWebApplicationContext启动(bootstrap)处理流程的。

2. 源码解析:

在这里插入图片描述
ConfigurationClass: 专门表示@Configuration class。存储解析@Configuration class的信息
ConfigurationClassPostProcessor: 专门用于处理@Configuration class的BeanDefinitoinRegistryPostProcessor(BeanFactoryPostProcessor子类)
AnnotationConfigUtils :专门注册BeanPostProcessor和BeanFactoryPostProcessor到spring容器

3. PostProcessorRegistrationDelegate解析过程:

​ Configuration注解的核心作用组件是ConfigurationClassPostProcessor,它是BeanFactoryPostProcessor类和BeanDefinitoinRegistryPostProcessor类型的子类。BeanFactoryPostProcessor实现了**AbstractApplicationContext's post-processor handling**技术规范,在项目启动时,便会进行扫描处理,这个逻辑的入口在PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法,代码如下:
在这里插入图片描述

class PostProcessorRegistrationDelegate {

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

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

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

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryPostProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
					registryPostProcessors.add(registryPostProcessor);
				}
				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.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
			registryPostProcessors.addAll(priorityOrderedPostProcessors);
			invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(beanFactory, orderedPostProcessors);
			registryPostProcessors.addAll(orderedPostProcessors);
			invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);

			// 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)) {
						BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
						registryPostProcessors.add(pp);
						processedBeans.add(ppName);
						pp.postProcessBeanDefinitionRegistry(registry);
						reiterate = true;
					}
				}
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryPostProcessors, 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<BeanFactoryPostProcessor>();
		List<String> orderedPostProcessorNames = new ArrayList<String>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
		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(beanFactory, priorityOrderedPostProcessors);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

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

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
		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();
	}

	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
		List<String> orderedPostProcessorNames = new ArrayList<String>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(beanFactory, orderedPostProcessors);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(beanFactory, internalPostProcessors);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

	private static void sortPostProcessors(ConfigurableListableBeanFactory beanFactory, List<?> postProcessors) {
		Comparator<Object> comparatorToUse = null;
		if (beanFactory instanceof DefaultListableBeanFactory) {
			comparatorToUse = ((DefaultListableBeanFactory) beanFactory).getDependencyComparator();
		}
		if (comparatorToUse == null) {
			comparatorToUse = OrderComparator.INSTANCE;
		}
		Collections.sort(postProcessors, comparatorToUse);
	}

	/**
	 * Invoke the given BeanDefinitionRegistryPostProcessor beans.
	 */
	private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}

	/**
	 * Invoke the given BeanFactoryPostProcessor beans.
	 */
	private static void invokeBeanFactoryPostProcessors(
			Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanFactory(beanFactory);
		}
	}

	/**
	 * Register the given BeanPostProcessor beans.
	 */
	private static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

		for (BeanPostProcessor postProcessor : postProcessors) {
			beanFactory.addBeanPostProcessor(postProcessor);
		}
	}


	/**
	 * BeanPostProcessor that logs an info message when a bean is created during
	 * BeanPostProcessor instantiation, i.e. when a bean is not eligible for
	 * getting processed by all BeanPostProcessors.
	 */
	private static class BeanPostProcessorChecker implements BeanPostProcessor {

		private static final Log logger = LogFactory.getLog(BeanPostProcessorChecker.class);

		private final ConfigurableListableBeanFactory beanFactory;

		private final int beanPostProcessorTargetCount;

		public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
			this.beanFactory = beanFactory;
			this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
		}

		@Override
		public Object postProcessBeforeInitialization(Object bean, String beanName) {
			return bean;
		}

		@Override
		public Object postProcessAfterInitialization(Object bean, String beanName) {
			if (bean != null && !(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
					this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
				if (logger.isInfoEnabled()) {
					logger.info("Bean '" + beanName + "' of type [" + bean.getClass() +
							"] is not eligible for getting processed by all BeanPostProcessors " +
							"(for example: not eligible for auto-proxying)");
				}
			}
			return bean;
		}

		private boolean isInfrastructureBean(String beanName) {
			if (beanName != null && this.beanFactory.containsBeanDefinition(beanName)) {
				BeanDefinition bd = this.beanFactory.getBeanDefinition(beanName);
				return RootBeanDefinition.ROLE_INFRASTRUCTURE == bd.getRole();
			}
			return false;
		}
	}


	/**
	 * {@code BeanPostProcessor} that detects beans which implement the {@code ApplicationListener}
	 * interface. This catches beans that can't reliably be detected by {@code getBeanNamesForType}
	 * and related operations which only work against top-level beans.
	 *
	 * <p>With standard Java serialization, this post-processor won't get serialized as part of
	 * {@code DisposableBeanAdapter} to begin with. However, with alternative serialization
	 * mechanisms, {@code DisposableBeanAdapter.writeReplace} might not get used at all, so we
	 * defensively mark this post-processor's field state as {@code transient}.
	 */
	private static class ApplicationListenerDetector
			implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {

		private static final Log logger = LogFactory.getLog(ApplicationListenerDetector.class);

		private transient final AbstractApplicationContext applicationContext;

		private transient final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>(256);

		public ApplicationListenerDetector(AbstractApplicationContext applicationContext) {
			this.applicationContext = applicationContext;
		}

		@Override
		public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
			if (this.applicationContext != null && beanDefinition.isSingleton()) {
				this.singletonNames.put(beanName, Boolean.TRUE);
			}
		}

		@Override
		public Object postProcessBeforeInitialization(Object bean, String beanName) {
			return bean;
		}

		@Override
		public Object postProcessAfterInitialization(Object bean, String beanName) {
			if (this.applicationContext != null && bean instanceof ApplicationListener) {
				// potentially not detected as a listener by getBeanNamesForType retrieval
				Boolean flag = this.singletonNames.get(beanName);
				if (Boolean.TRUE.equals(flag)) {
					// singleton bean (top-level or inner): register on the fly
					this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
				}
				else if (flag == null) {
					if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
						// inner bean with other scope - can't reliably process events
						logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
								"but is not reachable for event multicasting by its containing ApplicationContext " +
								"because it does not have singleton scope. Only top-level listener beans are allowed " +
								"to be of non-singleton scope.");
					}
					this.singletonNames.put(beanName, Boolean.FALSE);
				}
			}
			return bean;
		}

		@Override
		public void postProcessBeforeDestruction(Object bean, String beanName) {
			if (bean instanceof ApplicationListener) {
				ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
				multicaster.removeApplicationListener((ApplicationListener<?>) bean);
				multicaster.removeApplicationListenerBean(beanName);
			}
		}

		@Override
		public boolean requiresDestruction(Object bean) {
			return (bean instanceof ApplicationListener);
		}
	}

}

​ 该方法会处理所有的BeanFactoryPostProcessor类型对象,但是通过优先级来规定先后处理顺序。这个优先级顺序会根据以下两个条件来判断:

​ a)BeanDefinitionRegistryPostProcessor类型和BeanFactoryPostProcessor类型

​ b)PriorityOrdered和Ordered

​ 而ConfigurationClassPostProcessor同时实现了BeanDefinitionRegistryPostProcessor和PriorityOrdered接口,所以它得到最优先处理的机会,在代码流程中,首先会获取所有BeanDefinitionRegistryPostProcessor类型的beanName;

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); 

​ 然后使用isTypeMatch方法进行查找,此时ConfigurationClassPostProcessor正好满足条件,则根据beanName从spring容器中获取ConfigurationClassPostProcessor实例。

currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

​ 接着调用invokeBeanDefinitionRegistryPostProcessors方法将@Configuration类生成BeanDefinition,此时的BeanDefinition.Class为原类class对象;

	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); 


	/**
	 * Invoke the given BeanDefinitionRegistryPostProcessor beans.
	 */
	private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}

   
	/**
	 * ConfigurationClassPostProcessor class
	 */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        processConfigBeanDefinitions(registry);
    }

​ 此时ConfigurationClassPostProcessor实例会将BeanDefinition.beanClass生成proxy代理类;

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

4. @Configuration class过程解析

下面的方法就是解析@Configuration class的核心逻辑了。解析过程可以总结分三步:

ConfigurationClassPostProcessor class
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames(); 

    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)){
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));//(1)
        }
    }
    ··· 排序等
s
    // Parse each @Configuration class
    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 {
        parser.parse(candidates); //(2)
        parser.validate();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());

        // Read the model and create bean definitions based on its content
        this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());

        this.reader.loadBeanDefinitions(configClasses); //(3)

    }
    while (!candidates.isEmpty());

    ··· ···
}

step1: 获取候选者
从spring容器拿到所有的beanDefinitionNames,然后遍历验证获得候选者,验证的依据是class metadata是否含有@Configuration注解,从下面我们可知,此时,beanDefinitionNames中只有consumerFeignApp符合条件。所以候选者就是consumerFeignApp及他的beanDefinition

step2: 通过候选者获取ConfigurationClass
找到了候选者,下面就对候选者进行解析,解析的全部功能和逻辑都集中在ConfigurationClassParser类中,看名称可知,这个类专业解析@Configuration类。

ConfigurationClassParser class
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        if (bd instanceof AnnotatedBeanDefinition) {
            parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
        }
        ...
    }

    this.deferredImportSelectorHandler.process();
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    // 评估标识@Configuration的类是否满足条件去加载,这是条件注解@ConditionalXXX起的作用
    // 实际开发中,我们可以依据这个功能实现灵活的加载配置(如让谁加载进来,不让谁加载进来^_^)
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    // Recursively process the configuration class and its superclass hierarchy.
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    // 所有加载的@Configuration类都会转为ConfigurationClass放入这个map中
    this.configurationClasses.put(configClass, configClass);
}

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass){
    // 为了集中说明意图,隐藏了代码
    // Recursively process any member (nested) classes first
    // Process any @PropertySource annotations
    // Process any @ComponentScan annotations
    for (AnnotationAttributes componentScan : componentScans) {
        for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            if () {
                // 进入递归调用
                parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
        }
    }

    // Process any @Import annotations
    // Process any @ImportResource annotations
    // Process individual @Bean methods
    // Process default methods on interfaces
    // Process superclass, if any
    // No superclass -> processing is complete
    return null;
}

​ 如上方法整体的逻辑为对ConfigurationClass和SourceClass解析,检查他们有没有@ComponentScan,@Import,@Bean methods,@ImportResource,@PropertySource这些注解,如果有,分别对其解析,解析后的结果放入ConfigurationClass的各属性中

​ 各个注解的属性值中可能又包含@Configuration注解,又要对包含的@Configuration注解进行解析,这样形成了递归,所以解析过程中有三个方法形成了三角递归调用的逻辑,

​ 这一步会将我们项目中定义的@Configuration类都加载进来,你可能有疑问,难道项目中我们自己定义的@Configuration类都是靠递归加载进来的?答案当然是NO,请注意@ComponentScan注解,这个注解的解析器很厉害,它把所有的标识@Component注解的class加载进来,而@Configuration,@RestController,@Service,@Repository等都包含@Component,所有这些注解的class都会加载进来形成BeanDefinition存入spring 容器(解析过程详见ComponentScanAnnotationParser)。说回来,对于@ComponentScan解析器加载进来的BeanDefinitoin,会进行时@Configuration进行过滤,从而得到@Configuration类,再次调用parse()方法,这时体现出三角递归调用了。此时,项目中所有我们自定义的@Configuration类都获取到了

step3: 解析每个ConfigurationClass
​ step2中对@Configuration类的@Import,@Bean methods,@ImportResource进行解析,解析的结果放入ConfigurationClass对象的importBeanDefinitionRegistrars,beanMethods,importedResources,metadata等属性。
所以,step2将@Configuration类的解析结果都放入了ConfigurationClass对象,即ConfigurationClass对象包装了@Configuration类的所有信息。

​ 回到ConfigurationClassPostProcessor.processConfigBeanDefinitions()方法(3)处,现在,我们解析ConfigurationClass,而解析ConfigurationClass过程由ConfigurationClassBeanDefinitionReader类负责的

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

private void loadBeanDefinitionsForConfigurationClass(
        ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

    if (trackedConditionEvaluator.shouldSkip(configClass)) {
        String beanName = configClass.getBeanName();
        if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
            this.registry.removeBeanDefinition(beanName);
        }
        this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        return;
    }

    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

​ 看loadBeanDefinitionsForConfigurationClass()方法,方法主要功能为对ConfigurationClass的beanMethods,importedResources,importBeanDefinitionReistrars属性进行解析,为什么要对这三个属性进行解析呢,看看这三个其@Import,@Bean methods,@ImportResource的用法

@Import(DispatcherServletConfiguration.class)
@ImportResource("classpath:/com/acme/database-config.xml")
protected static class DispatcherServletRegistrationConfiguration {

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    public DispatcherServletRegistrationBean dispatcherServletRegistration(){
        ...
    }
}

可以看到,这三个注解的属性值都是类或者配置文件或者加载文件的类,所以,需要解析,从而将解析到的.class文件转化为BeanDefinition放入spring容器。

5. @Configuration类的cglib代理类实例化分析

​ 由于@Configuration注解的都是类,而非接口,所有这里使用的是cglib代理技术,ConfigurationClassEnhancer包装了cglib。这里我们实际工作中可以直接复用ConfigurationClassEnhancer满足我们生成代理类的场景

实现自BeanFactoryPostProcessor.postProcessBeanFactory
ConfigurationClassPostProcessor class
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 生成代理
    enhanceConfigurationClasses(beanFactory);
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

ConfigurationClassPostProcessor.ConfigurationClassEnhancer class
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
            if (!(beanDef instanceof AbstractBeanDefinition)) {
                throw 
            }
            configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
        }
    }

    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // Set enhanced subclass of the user-specified bean class
        Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
        if (configClass != null) {
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }
}

ConfigurationClassPostProcessor.ConfigurationClassEnhancer class
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
    if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
        return configClass;
    }
    Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
    return enhancedClass;
}
springboot 自定义@Configuration加载顺序
zhang3093966的专栏
09-21 1万+
在学习Springboot的时候遇到@Configuration的指定顺序加载问题。做个记录,防止以后遇到的时候再次懵逼。 Springboot的执行类,有main方法的那个类,正常情况下有@SpringBootApplication和@ComponentScan两个注解。@SpringBootApplication就不再多说啥了,主要记录一下和@ComponentScan注解有关的一个问题。@ComponentScan可以指定扫描@Configuration配置类的包路径。这里有个问题,就是无法决定加载
关于Spring-Boot配置加载顺序解读
m0_73257876的博客
09-03 2063
经过上面的分析可以得出常用配置文件中读取配置的结论:config配置中心 => jvm参数 => 系统环境变量 => 项目内的application-xxx.yaml => 项目内的application.yaml => bootstrap.yaml。spring-boot 项目可以有多种灵活的方式设置配置项,一般来说项目内的application.yaml是一个默认配置项,再通过基本配置项对参数进行不同的赋值。
SpringBoot设置@Configuration加载顺序
xiaofeilong2016的博客
12-24 2万+
SpringBoot设置@Configuration加载顺序 目录 1、简介 2、例子 1、简介 Spring Boot会检查你发布的jar中是否存在META-INF/spring.factories文件,该文件中以EnableAutoConfiguration为key的属性应该列出你的配置类: org.springframework.boot.autoconfigure.EnableAutoC...
@SpringBootConfiguration重复加载报错
最新发布
我这个代码你能看懂吗?
08-05 386
的exclude属性:用于排除特定的自动配置类,而不是用于排除主配置类本身。不同的配置类:可以创建不同的配置类,并在不同的环境中使用不同的配置类。:用于创建测试专用的配置类,并在测试中使用。
关于Spring框架的 @Configuration 与@Service 加载顺序哪个先后(某些环境加载是随机的)
qyhua的专栏
02-01 1674
本来也是以为 @Configuration 优先加载于 @Service ,那参数处理放在@Configuration注入完后,@service构建时就可以拿来用的,在我在IDEA的调试时下断点验证过。但在正式环境跑项目时并不是这样的。上面的代码在IDEA调试器执行时,确实是加载 @Configuration 执行打印是否调试模式这行 后加载@Service并执行init()方法,此时拿到SysParamApi.is_debug值 是注入后的值。由于是正式服务器不能尝试多次,上面两次验证加载是随机的。
springboot中@Configuration配置类加载流程
shanliang
12-04 1476
@Configuration
Springboot @Configuration @bean注解作用解析
08-25
注解的主要作用是将类标记为配置类,以便 Spring 框架可以自动检测和加载配置信息。在 Spring Boot 框架中,@Configuration 注解通常与 @Bean 注解一起使用,以便注册 Bean 到 Spring 容器中。 例如,在 Spring ...
一文学会Spring的@Configuration配置类解析
xxxzzzqqq_的博客
03-20 160
本篇文章将详细分析Spring中如何加载并解析由@注解修饰的配置类。注解是Spring中特别重要且知名的注解,大家都知道怎么使用(如果还不知道,那你一定是没看超详细总结Spring的配置注解),作用就是可以向容器注册bean,并且就像“每一个成功的男人背后都有一个优秀的女人在支持”,@注解的背后也有一个功能强大的类在支撑,那就是,所以本文的重点就是如何解析由@注解修饰的配置类。本文的一个思维导图如下所示。最后,请务必知道Spring的是什么,不能只知道Spring有bean但不知道bean的前生。
@AutoConfiguration装配的bean和@Component的bean加载顺序如何控制
way2016的博客
03-23 2830
@AutoConfiguration装配的bean和@Component的bean加载顺序如何控制
Spring进阶(十二)之@Configuration和@Bean详解
weixin_56644618的博客
10-05 3947
@Configration和@Bean注解详解
spring(六)-@Configuration注解形式配置 IOC
weixin_43520586的博客
10-10 214
以下两个类分别使用配置形式与注解形式加入 IOC 容器中 service.impl.UserInfoService @Data @Service public class UserInfoService implements IUserInfoService { private UserInfoDao userMapper; } dao.impl.UserInfoDaoImpl @Repository public class UserInfoDaoImpl implements UserInfoDa
Spring中bean注入初始化方式—通过注解@Configuration @bean
热门推荐
vrenzhuv的专栏
05-30 3万+
Spring的初始化bean的另一种方式——注解
SpringBoot配置加载顺序
博客
07-27 451
springboot 配置加载顺序
SpringBoot启动配置类(二)【@Configuration注解的配置类如何被加载到?】
长风破浪会有33的博客
07-13 1万+
spring容器在启动的时候会去扫描@Configuration,并将相关的类进行加载。那么spring容器怎么去扫描的呢? 配置类与启动类同包或者在其子包下 springboot配置数据库连接池 @Configuration public class DruidConfig { //跟配置文件绑定 //spring.druid.xx xx跟DruidDataSource里的属性...
java spring 加载顺序_java编程之如何控制springboot中bean的加载顺序
weixin_35886095的博客
02-24 574
控制加载顺序的目的springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题。在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功能。在一般业务场景,可能你不大关心一个bean是如何被注册进spring容器的。只需要把需要注册进容器的bean声明为@Component即可,spring会自动扫描到这个Bean完成初始化并加载到spring...
基于Spring的@Conditional注解进行条件加载
天行健,君子以自强不息;地势坤,君子以厚德载物。
04-15 387
阅读文本大概需要3分钟。0x01:@Conditional使用 Spring Boot的强大之处在于使用了Spring 4框架的新特性:@Conditional注释,此注释使得只...
【小家Spring】控制Spring IoC容器对Bean(含@Configuration配置类)的加载顺序(@DependsOn注解的使用)
架构师:通透,才能写出好代码!
03-21 1万+
前言 首先,先说明一点:此篇博文相对来说是比较小的专题,只讲解Spring IoC加载Bean的顺序问题。 为了更好的了解这里面的原理,建议先了解Spring容器内部对Bean执行初始化的原理,因此推荐下面博文(若已了解,请忽略): 【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(二),Spring容器启动...
怎样自定义spring boot @configuration加载顺序? 如果在第三方jar包中,该怎么干预加载顺序呢? 多个conditionOn 到底哪个呢?
a1058926697的博客
08-24 9861
1.spring boot bean 的加载顺序? 2. spring boot bean 是否加载? 3.配置文件的加载顺序,及优先级,怎样干预加载的配置文件? 4 .加载之后怎样修改bean 的属性呢?尤其在修改第三方的jar包中的属性? 怎么做到? 1.@Configuration 注解加载允许由于@AutoConfiguratio注解加载, 实现Ordered接口,...
@Configuration配置加载分析
yxkong的专栏
08-22 635
本来只想分析下@import是如何装载的,一下子没刹住车,整了一个Configuration 配置加载分析。背景周五在给大家分享sleuth的时候在ZipkinAutoConfiguration中关于程序如何选择Reporter一下子没找到具体的实现。两周之前刚翻过源码,当时理的清清楚楚,两周就忘了。再次翻看源码后,记录一下//关键点在ZipkinSenderConfigurationImportSelector,这是一个ImportSelector,先不说为啥 @Import(ZipkinSenderCo
Springboot @configuration 如何加载
05-22
在 Spring Boot 应用程序中,使用 `@Configuration` 注解来表示一个配置类,该类包含一个或多个 `@Bean` 注解的方法,这些方法返回应该由 Spring 容器管理的对象。Spring Boot 应用程序在启动时会自动扫描 `@Configuration` 注解的类,并将其视为配置类。 如果 `@Configuration` 注解的类位于主应用程序类的同一包中或者是其子包中,那么它将自动被扫描并加载。如果在其他包中,可以使用 `@ComponentScan` 注解来指定要扫描的包。此外,也可以使用 `@Import` 注解来导入其他配置类。 例如,在 Spring Boot 应用程序中,可以创建一个名为 `MyConfig` 的配置类: ```java @Configuration public class MyConfig { @Bean public MyBean myBean() { return new MyBean(); } } ``` 这个配置类包含一个 `@Bean` 注解的方法 `myBean()`,返回一个 `MyBean` 对象。在应用程序的其他部分中,可以使用 `@Autowired` 注解将这个 bean 注入到其他类中。 Spring Boot 应用程序将自动加载这个配置类并将其中的 bean 添加到 Spring 容器中,以便在应用程序中使用。
写文章

热门文章

  • Redis监听事件 9457
  • 如何更改springboot的tomcat版本 9448
  • mybatis配置文件详解 5250
  • @Configuration注解加载过程 3628
  • Redis之渐进式rehash 3603

分类专栏

  • spring 5篇
  • #Java基础 4篇
  • 操作系统 1篇
  • #Netty 1篇
  • IO 3篇
  • Java 22篇
  • #监控 1篇
  • 容器 4篇
  • jvm 6篇
  • #并发编程 4篇
  • 网络 7篇
  • redis 4篇
  • docker 1篇
  • mysql 8篇

最新评论

  • Redis渐进式rehash小疑问

    普普通通搬砖: rehash时,旧hash表还会新增吗?

  • Redis之渐进式rehash

    woshishe: dnjd

  • Redis监听事件

    Love_you_for_ever: 引用「@Override protected void doHandleMessage(Messag」 这个

  • Redis监听事件

    Love_you_for_ever: @Override protected void doHandleMessage(Message message) { this.publishEvent(new RedisKeyExpiredEvent(message.getBody())); 第4个栗子这样对么????

  • docker搭建mysql主从

    twenty_twoONE: 写的很详细,真棒

最新文章

  • jmap简介
  • Redis渐进式rehash小疑问
  • SpringBoot启动流程简介
2024年1篇
2023年7篇
2022年29篇
2021年11篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家绍兴玻璃钢抽象动物雕塑厂家价格齐齐哈尔人物玻璃钢雕塑价格黄山商场开业美陈上海主题商场美陈市场报价许昌景观玻璃钢仿铜雕塑加工特色玻璃钢雕塑哪家便宜烟台承接玻璃钢雕塑陕西玻璃钢雕塑上海哪些商场有艺术美陈三八妇女节金店商场美陈安阳玻璃钢花盆十堰户外玻璃钢雕塑厂家日照市玻璃钢雕塑定制玻璃钢动物雕塑维护泰州玻璃钢雕塑设计报价陕西玻璃钢艺术摆件景观雕塑盐城商场圣诞美陈青州玻璃钢造型雕塑中式玻璃钢雕塑厂家大型商场创意商业美陈思路惠州镇隆玻璃钢雕塑厂龙岩园林玻璃钢雕塑直销佛山树脂玻璃钢雕塑现货玻璃钢雕塑 金色宝山玻璃钢雕塑厂珠海玻璃钢动物雕塑河南大型商场美陈怎么样潘多拉商场美陈中山仿真玻璃钢人物雕塑绵阳玻璃钢卡通雕塑费用香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化