ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Spring源码分析--Bean的注册

2020-03-04 17:37:52  阅读:125  来源: 互联网

标签:容器 Spring bean Bean 源码 registry 注册 new


Spring中共有两种bean,一种为普通bean,另一种则为工厂bean:
BeanFactory 用于管理Bean的一个工厂,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的
FactoryBean 是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似,省去xml配置工厂模式出现的。通过FactoryBean创建一个代理类来增强目标类。

二、bean的创建

我们继续看AbstractApplicationContext.refresh方法

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();
 
			// Tell the subclass to refresh the internal bean factory.
			
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			
			prepareBeanFactory(beanFactory);
 
			try {
				// Allows post-processing of the bean factory in context subclasses.
				
				postProcessBeanFactory(beanFactory);
 
				// Invoke factory processors registered as beans in the context.
				
				invokeBeanFactoryPostProcessors(beanFactory);
 
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
 
				// Initialize message source for this context.
				initMessageSource();
 
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();
 
				// Initialize other special beans in specific context subclasses.
				onRefresh();
 
				// Check for listener beans and register them.
				registerListeners();
 
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
 
				// Last step: publish corresponding event.
				finishRefresh();
			}
 
			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
 
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();
 
				// Reset 'active' flag.
				cancelRefresh(ex);
 
				// Propagate exception to caller.
				throw ex;
			}
 
			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

5、invokeBeanFactoryPostProcessors(beanFactory)

遍历所有实现BeanFactoryPostProcessor接口的实现类

// 调用beanFactory的后置处理器 BeanDefinitionRegistryPostProcessor
// 用户可以实现BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 注册bean
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// 用户实现了BeanFactoryPostProcessor 但没有实现BeanDefinitionRegistryPostProcessor
regularPostProcessors.add(postProcessor);
}
}

 解析注解完成bean的注册,前面只是注册了XML中的bean而没有注册被注解标注的bean

// 会调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 解析注解,注册bean
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

我们需要知道哪些注解标识的就是bean交给spring管理。

1、@Configuration+@Bean

用@Configuration注释类表明其主要目的是作为bean定义的源,@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系。 

@Configuration 
public class AppConfig {
@Bean      
public MyService myService() {        
return new MyService();    
 }
 @Bean    
public UserService userService(){        
return new UserService(myService()); 
 }         
}

配置了@Configuration ,打印结果显示 UserService 依赖的对象myService和从容器中获取的对象 myService;
没有配置@Configuration,UserService依赖的对象myService 不是从容器中获取的,只是一个普通的对象。

因为@Configuration修饰的AppConfig是一个cglib的代理对象,所以@Configuration 保证了配置类的内部方法之间依赖调用时都从容器中获取bean

2、@ComponentScan+@Component, @Repository,@Service, @Controller 

这个用的比较多就不一一介绍了。

3、@Import

在下面例子中MyImportBeanDefinitionRegistrar:

如果实现了ImportSelector接口,实例化会并调用其selectImports方法,可以根据这个方法来规定bean只能根据类型来装配
如果实现了DeferredImportSelector,实例化并且调用其selectImports方法,会晚于前面一个的调用,
如果实现了ImportBeanDefinitionRegistrar接口,实例化并且调用其registerBeanDefinitions方法,可以修改注册bean的信息。
如果都没实现就只会实例化类

@Configuration 
@Import(value = MyImportBeanDefinitionRegistrar.class)
public class AppConfig {
 @Bean   
public User user(){      
return new User();   
} 
}

在@MapperScan注解中就使用了@import,所以可以扫描解析mapper文件

4、@Conditional

MyConditional会实现Condition接口中的matches方法,满足什么条件才能装配bean

@Configuration 
public class AppConfig {
 @Bean 
 @Conditional(value = MyConditional.class) 
public User user(){      
return new User();   
} 
}

 

在回到invokeBeanDefinitionRegistryPostProcessors方法中,可以看到会调用实现BeanFactoryPostProcessor接口的postProcessBeanDefinitionRegistry方法。我们重点看ConfigurationClassPostProcessor解析注解的后置处理器。

private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

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

进入ConfigurationClassPostProcessor.processConfigBeanDefinitions去扫描注解并注册bean。

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 {
			// 解析配置类  @ComponentScan (bean注册到容器) @Import @ImportResource @Bean(后面三个不会注册到bean容器)
			parser.parse(candidates);
			parser.validate();

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

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			// 注册bean到容器
			//  注册实现了ImportSelector的bean
			// 方法bean注册到容器
			// @ImportResource("spring.xml") 配置的bean注册到容器
			// 实现ImportBeanDefinitionRegistrar的bean 注册到容器
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				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));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

首先会扫描并解析@Configuration注解,parser.parse(candidates)

//在这个parse方法中,所有DeferredImportSelector实现类都会被放入集合deferredImportSelectors中,
// 它们的selectImports方法不会被执行,而其他ImportSelector实现类的selectImports都会被执行
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

里面会调用doProcessConfigurationClass(configClass, sourceClass)

这里处理将@Component修饰的bean注册到容器

//  处理@ComponentScan   将@Component修饰的bean注册到容器
		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) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				// @ComponentScan扫描bean,返回@Component修饰的BeanDefinitionHolder 集合,并且
				// 会将bean注册到容器
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

 处理@Import注解的,如果是实现ImportSelector接口的类不会在此时注册到bean中,而在最开始的processConfigBeanDefinitions调用this.reader.loadBeanDefinitions(configClasses)注册

// 处理@Import   implements ImportSelector  并不会将bean注册到容器
processImports(configClass, sourceClass, getImports(sourceClass), true);

那么现在为止所有的bean的信息都注册到DefaultListableBeanFactory的map集合中去了

标签:容器,Spring,bean,Bean,源码,registry,注册,new
来源: https://blog.csdn.net/qq_38682952/article/details/104656128

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有