注解方式下Bean的注册
前面我们讲到xml配置文件进行Bean的注册,xml配置是Spring早期常用的配置方式,现在基本上大部分场景上都推荐使用注解的方式,尤其是SpringBoot时代的来临,进一步推动了注解方式的全面使用,下面我们来看看注解方式下的Bean注册,还是从个简单的例子入手
publicclassAnnotionConfig { (name="userBean") publicUsergetUserBean(){ Useruser=newUser(); user.setUserName("Lucy"); returnuser; } } publicclassAnnotionBeanTest { publicstaticvoidmain(String[] args){ AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext("org.kxg.springDemo"); Useruser= (User) applicationContext.getBean("userBean"); System.out.println(user.getUserName()); } }
这里用到AnnotationConfigApplicationContext,是另外一种容器的实现,传入一个包名,会自动扫描包下面的Spring注解,然后将其注册到容器中
publicAnnotationConfigApplicationContext(String... basePackages) { this(); //主要是scan方法完成bean的注册scan(basePackages); //又到了这个方法,有没有很熟悉~~~refresh(); }
下面我们重点看一下注解方式的Bean注册
publicintscan(String... basePackages) { intbeanCountAtScanStart=this.registry.getBeanDefinitionCount(); //扫描包,进行Bean注册doScan(basePackages); // Register annotation config processors, if necessary.if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } return (this.registry.getBeanDefinitionCount() -beanCountAtScanStart); }
//ClassPathBeanDefinitionScannerprotectedSet<BeanDefinitionHolder>doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder>beanDefinitions=newLinkedHashSet<>(); for (StringbasePackage : basePackages) { //扫描包下打了注解的类,并将其转换成BeanDefinitionSet<BeanDefinition>candidates=findCandidateComponents(basePackage); for (BeanDefinitioncandidate : candidates) { ScopeMetadatascopeMetadata=this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); StringbeanName=this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidateinstanceofAbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidateinstanceofAnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolderdefinitionHolder=newBeanDefinitionHolder(candidate, beanName); definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); //进行BeanDefinition注册registerBeanDefinition(definitionHolder, this.registry); } } } returnbeanDefinitions; }
publicstaticvoidregisterBeanDefinition( BeanDefinitionHolderdefinitionHolder, BeanDefinitionRegistryregistry) throwsBeanDefinitionStoreException { // Register bean definition under primary name.StringbeanName=definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any.String[] aliases=definitionHolder.getAliases(); if (aliases!=null) { for (Stringalias : aliases) { registry.registerAlias(beanName, alias); } } }
看到这个方法,有没有点眼熟的感觉
上面xml方式进行Bean注册也调用到这个方法了,所以后面的流程都是一样的,注解方式和xml配置方式从本质上来讲,并没有什么不同,只是Bean的描述不同而已,最终都会被解析成BeanDefinition,注册到容器中,至此整个Bean的注册流程就已经完了。
当然在整个过程中,忽略了很多细节,只看了主线流程。
读源码的时候,很容易陷入细节中,尤其是像Spring这样通用的框架,它为了通用性和扩展性,会把代码写的很“绕”,如果你过于关注细节很容易让自己陷入实现的细节中,一开始看源码的时候,建议不用太关注细节,把主线功能先看完,知道大概的原理后再逐个去击破~