欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解析Spring中@Bean的实现原理

程序员文章站 2022-04-15 23:00:39
在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

相关标签: Spring java