当前位置: 移动技术网 > IT编程>开发语言>Java > 解析Spring中@Bean的实现原理

解析Spring中@Bean的实现原理

2020年08月01日  | 移动技术网IT编程  | 我要评论
在SpringBoot的项目中,使用@Bean的注解将非常的普遍,这个是一个方法级别的注解,通常定义在类上有@Configuration或者@Component的注解中。@Bean也是替代传统使用XML注入Bean的方式。

在SpringBoot的项目中,使用@Bean的注解将非常的普遍,这个是一个方法级别的注解,通常定义在类上有@Configuration或者@Component的注解中。

@Bean也是替代传统使用XML注入Bean的方式。

先来分析一下Spring是如何扫描到@Bean注释的

refresh是Spring容器启动的主流程方法,就从这开始看起。

 @Override public void refresh() throws BeansException, IllegalStateException { //。。。省略部分代码 //这个方法会处理bean中的各种注解,其中包含了@Bean的解析 invokeBeanFactoryPostProcessors(beanFactory); //。。。省略部分代码 } 
 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } } 
 public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { //。。。省略部分代码 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //。。。省略部分代码 } 

这里利用BeanFactoryPostProcessor扩展处理

 private static void invokeBeanDefinitionRegistryPostProcessors( Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanDefinitionRegistry(registry); } } 
 @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { int registryId = System.identityHashCode(registry); if (this.registriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); } if (this.factoriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + registry); } this.registriesPostProcessed.add(registryId); processConfigBeanDefinitions(registry); } 

大概分析这部分处理流程

 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); //先获取容器中所有的BeanDefinition对象,这部分对象会更早的被容器加载到,利用ConfigurationClassPostProcessor这个类完成的,我在之前的博文中有介绍过 String[] candidateNames = registry.getBeanDefinitionNames(); //遍历所有beanName for (String beanName : candidateNames) { //通过beanName,获取BeanDefinition对象 BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } //这个判断会找当前BeanDefinition的方法中是否有@Bean的注解,如果有就返回true /**
			// Finally, let's look for @Bean methods...
			try {
					return metadata.hasAnnotatedMethods(Bean.class.getName());
				}
				catch (Throwable ex) {
					if (logger.isDebugEnabled()) {
						logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
					}
					return false;
			}
			*/ else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { //封装成BeanDefinitionHolder对象,并添加到list集合中 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // Return immediately if no @Configuration classes were found if (configCandidates.isEmpty()) { return; } // Sort by previously determined @Order value, if applicable //有@Order注解的完成排序 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); } // 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); parser.validate(); //从刚刚解析的过程中获取ConfigurationClass集合,这个类里面又包含了BeanMethod对象集合,而这个对象封装了@Bean的方法 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对象到BeanDefinitions中,看后面分析。 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()); // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } } 

parser.parse(candidates)方法最终会执行到下面这个方法

 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //。。。省略部分代码 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { //主要看这边,把有@Bean注解的封装成BeanMethod对象,并添加到ConfigurationClass类中的一个set集合属性中 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } //。。。省略部分代码 } 

loadBeanDefinitions

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

loadBeanDefinitionsForConfigurationClass

 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); } //遍历ConfigurationClass中的beanMethods集合。 for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); } 

loadBeanDefinitionsForBeanMethod

 private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { ConfigurationClass configClass = beanMethod.getConfigurationClass(); MethodMetadata metadata = beanMethod.getMetadata(); //。。。省略部分代码 ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata); //。。。省略部分代码 // instance @Bean method //设置BeanDefinition中的factoryBeanName属性值为当前class对象的beanName beanDef.setFactoryBeanName(configClass.getBeanName()); //设置BeanDefinition中的factoryMethodName属性值为当前class对象中@Bean方法的methodName beanDef.setUniqueFactoryMethodName(methodName); //。。。省略部分代码 BeanDefinition beanDefToRegister = beanDef; //。。。省略部分代码 //把封装后的BeanDefinition注册到beanDefinitionMap和beanDefinitionNames容器中,spring实例化过程会遍历这个容器中的bean //beanDefinitionMap中key是@Bean的方法名,value是@Bean所属对象的BeanDefinition //beanDefinitionNames是list集合,存放的是@Bean的方法名 this.registry.registerBeanDefinition(beanName, beanDefToRegister); } 

分析到这对有@Bean注解的方法,Spring的处理策略就大致了解了。
1、先找到有@Configuration或者@Component注解的bean对象。
2、检查bean对象中是否有@Bean注解的方法,如果存在封装成BeanMethod对象,并添加到一个set集合中。
3、遍历集合,然后拿到bean对象对应的BeanDefinition,设置factoryMethodName属性为@Bean方法的先关信息,这就相当于在当前bean对应的BeanDefinition对象中添加了一个标识,用于识别是否有@Bean的方法。
4、最后把以@Bean注解的方法名为key,BeanDefinition为value,添加到beanDefinitionMap容器中,把@Bean注解的方法名添加到beanDefinitionNames容器中,一个map集合,一个list集合。

后半部分再来看一下,BeanDefinition对象有了factoryMethodName属性后,又是如何被最终添加到Spring的容器中的。

 @Override public void preInstantiateSingletons() throws BeansException { //。。。省略部分代码 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); //遍历beanDefinitionNames集合,包含了之前添加进去的@Bean注释的方法名 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { //获取bean对象 getBean(beanName); } } } //。。。省略部分代码 } 
 @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } 

getBean会执行到doGetBean方法

 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //。。。省略部分代码 //根据beanName获取BeanDefinition对象,之前解析过可以从一个名为beanDefinitionMap的map容器中获取,value就是bean对应的BeanDefinition对象。 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); //。。。省略部分代码 // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { //创建bean对象,beanName为方法名,mbd为bean对应的BeanDefinition对象 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //。。。省略部分代码 } 

最终会执行到createBeanInstance方法,这是bean的实例化方法

 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { //。。。省略部分代码 //判断当前BeanDefinition是否有factoryMethodName属性,之前分析过有@Bean注解的会设置这个属性 if (mbd.getFactoryMethodName() != null) { //利用反射调用@Bean注释的方法 return instantiateUsingFactoryMethod(beanName, mbd, args); } //。。。省略部分代码 } 
 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Object factoryBean, final Method factoryMethod, Object... args) { //。。。省略部分代码 try { //factoryMethod即@Bean注释的方法,利用反射完成调用并返回方法中的对象 Object result = factoryMethod.invoke(factoryBean, args); if (result == null) { result = new NullBean(); } return result; } //。。。省略部分代码 } 

总结

后半部分也比较简单,先遍历beanDefinitionNames这个list集合,依次处理,再通过beanDefinitionMap找到bean对应的BeanDefinition对象,最后在实例化对象的时候,判断当前BeanDefinition对象中factoryMethodName属性是否有值,如果有则通过反射调用@Bean注释的方法拿到bean的实例,这就实现将@Bean注解的方法注入到容器中了,name为方法名,value为方法返回值。

本文地址:https://blog.csdn.net/CSDN_WYL2016/article/details/108223930

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网