/**
* 解析类中含有@Bean注解的方法
*/private Set<MethodMetadata>retrieveBeanMethodMetadata(SourceClass sourceClass){/**
* 获取含有@Bean注解的方法的元信息
*/
AnnotationMetadata original = sourceClass.getMetadata();
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());/**
* 如果含有@Bean注解的方法超过两个,并且是标准注解信息,则Spring会使用ASM技术
* Spring使用了JAVA的反射机制获取的Class,但是反射不能保证方法的声明顺序,也就是它所返回的方法顺序
* 并不一定是代码从上到下编写的顺序,有可能类中的最下面的一个方法在beanMethods集合中是第一个
* Spring为保证方法的声明顺序,使用ASM技术读取作比较
* 注意:这里只有ASM获取的方法比反射获取的方法多或者相等才会比较
*/if(beanMethods.size()>1&& original instanceofStandardAnnotationMetadata){// Try reading the class file via ASM for deterministic declaration order...// Unfortunately, the JVM's standard reflection returns methods in arbitrary// order, even between different runs of the same application on the same JVM.try{/**
* 利用ASM技术返回类的元信息,并获取含有@Bean注解的方法元信息
*/
AnnotationMetadata asm =this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());/**
* 这里重新创建了一个LinkedHashSet集合保证放入的顺序,遍历ASM方法名与java反射方法名一致
* 则可以放入集合中并赋值给局部变量用于返回
*/if(asmMethods.size()>= beanMethods.size()){
Set<MethodMetadata> selectedMethods =newLinkedHashSet<>(asmMethods.size());for(MethodMetadata asmMethod : asmMethods){for(MethodMetadata beanMethod : beanMethods){if(beanMethod.getMethodName().equals(asmMethod.getMethodName())){
selectedMethods.add(beanMethod);break;}}}if(selectedMethods.size()== beanMethods.size()){// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;}}}catch(IOException ex){
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);// No worries, let's continue with the reflection metadata we started with...}}return beanMethods;}
ConfigurationClassParser#processInterfaces
/**
* 获取接口上含有@Bean注解的方法
*/privatevoidprocessInterfaces(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {/**
* 获取父级接口,遍历
*/for(SourceClass ifc : sourceClass.getInterfaces()){/**
* 获取接口中含有@Bean注解的方法元信息,然后遍历
*/
Set<MethodMetadata> beanMethods =retrieveBeanMethodMetadata(ifc);for(MethodMetadata methodMetadata : beanMethods){/**
* 只要此方法不是抽象类型的,则可以放入集合中待后续处理
*/if(!methodMetadata.isAbstract()){// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));}}/**
* 这里使用了递归,用来处理父级接口的父接口
*/processInterfaces(configClass, ifc);}}
/**
* 处理配置类中@Bean注解的方法
* @param beanMethod
*/privatevoidloadBeanDefinitionsForBeanMethod(BeanMethod beanMethod){/**
* 获得方法所在类的类信息
*/
ConfigurationClass configClass = beanMethod.getConfigurationClass();/**
* 获得方法的元信息
*/
MethodMetadata metadata = beanMethod.getMetadata();/**
* 获得方法名
*/
String methodName = metadata.getMethodName();// Do we need to mark the bean as skipped by its condition?/**
* 此方法是否需要跳过解析
*/if(this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)){
configClass.skippedBeanMethods.add(methodName);return;}if(configClass.skippedBeanMethods.contains(methodName)){return;}/**
* 获得@Bean注解中的属性
*/
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null,"No @Bean annotation attributes");// Consider name and any aliases/**
* 获得@Bean注解中指定方法返回对象的BeanName
* 如果没有设置则默认使用方法名
* 如果设置了则使用第一个名称,其它名称作为别名,因为@Bean注解中name属性为数组
*/
List<String> names =newArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName =(!names.isEmpty()? names.remove(0): methodName);// Register aliases even when overriddenfor(String alias : names){this.registry.registerAlias(beanName, alias);}// Has this effectively been overridden before (e.g. via XML)?/**
* 判断容器中与beanName相同的BeanDefinition是否可以被覆盖
*/if(isOverriddenByExistingDefinition(beanMethod, beanName)){/**
* 如果@Bean所在方法配置的beanName与配置类的BeanName相同,则抛异常
*/if(beanName.equals(beanMethod.getConfigurationClass().getBeanName())){thrownewBeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName,"Bean name derived from @Bean method '"+ beanMethod.getMetadata().getMethodName()+"' clashes with bean name for containing configuration class; please make those names unique!");}return;}/**
* 通过@Bean所在方法元信息和类信息构建BeanDefinition
*/
ConfigurationClassBeanDefinition beanDef =newConfigurationClassBeanDefinition(configClass, metadata);/**
* 设置BeanDefinition的来源
*/
beanDef.setResource(configClass.getResource());/**
* 设置BeanDefinition的提取源,即所代表的对象从哪里提取,取决于配置机制
* 默认使用PassThroughSourceExtractor这个类,机制是按原样返回,即从方法中提取
*/
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));/**
* 如果方法是static静态类型,将其置为静态方法调用
* 实际就是向BeanDefinition中设置工厂方法名称,即产生对象需要调用的方法
*/if(metadata.isStatic()){// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);}/**
* 如果不是静态类型,将其置为实例调用
*/else{// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);}/**
* 设置由方法提取的实例为属性自动注入的方式,默认为构造方法
*/
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);/**
* 是否跳过属性检查
*/
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);/**
* 提取方法上的其它注解
*/
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);/**
* 设置由方法提取的实例是否会根据类型或者名称为属性自动注入,默认不会,除非显示设置
*/
Autowire autowire = bean.getEnum("autowire");if(autowire.isAutowire()){
beanDef.setAutowireMode(autowire.value());}/**
* 指定由方法提取的实例的初始化方法名
*/
String initMethodName = bean.getString("initMethod");if(StringUtils.hasText(initMethodName)){
beanDef.setInitMethodName(initMethodName);}/**
* 指定由方法提取的实例的销毁方法名
*/
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);// Consider scoping/**
* 设置动态代理模型的初始值
*/
ScopedProxyMode proxyMode = ScopedProxyMode.NO;/**
* 获得方法上的@Scope注解
*/
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);/**
* 存在@Scope注解时进行相关的设置
*/if(attributes != null){/**
* 设置作用域
*/
beanDef.setScope(attributes.getString("value"));/**
* 设置动态代理模型,如果是使用默认的话则置为初始化值
*/
proxyMode = attributes.getEnum("proxyMode");if(proxyMode == ScopedProxyMode.DEFAULT){
proxyMode = ScopedProxyMode.NO;}}// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;/**
* 如果需要动态代理的话,则将原始的BeanDefinition替换为动态代理的BeanDefinition
*/if(proxyMode != ScopedProxyMode.NO){
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(newBeanDefinitionHolder(beanDef, beanName),this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister =newConfigurationClassBeanDefinition((RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);}if(logger.isDebugEnabled()){
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));}/**
* 将其注册进容器中
*/this.registry.registerBeanDefinition(beanName, beanDefToRegister);}
isOverriddenByExistingDefinition
/**
* 如果容器中存在与beanName相同的BeanDefinition是否可以被覆盖
* 返回false则是没有与beanName相同的BeanDefinition或者可以被覆盖
* 返回true则不能覆盖
*/protectedbooleanisOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName){/**
* 根据beanName判断容器中是否已经存在相应的BeanDefinition,不存在则返回false可以注册到容器中
*/if(!this.registry.containsBeanDefinition(beanName)){returnfalse;}/**
* 获取容器中BeanName对应的BeanDefinition
*/
BeanDefinition existingBeanDef =this.registry.getBeanDefinition(beanName);// Is the existing bean definition one that was created from a configuration class?// -> allow the current bean method to override, since both are at second-pass level.// However, if the bean method is an overloaded case on the same configuration class,// preserve the existing bean definition./**
* 如果容器中的BeanDefinition是一个ConfigurationClassBeanDefinition
* ConfigurationClassBeanDefinition是由@Bean注解方法返回对象封装的
* 如果配置类的类名和@Bean方法所在类的类名相同,则返回true,这时发生了重载,不解析@Bean所在的方法
* 如果类名不相同,则解析@Bean所在的方法,覆盖容器中存在的
*/if(existingBeanDef instanceofConfigurationClassBeanDefinition){
ConfigurationClassBeanDefinition ccbd =(ConfigurationClassBeanDefinition) existingBeanDef;return ccbd.getMetadata().getClassName().equals(
beanMethod.getConfigurationClass().getMetadata().getClassName());}// A bean definition resulting from a component scan can be silently overridden// by an @Bean method, as of 4.2.../**
* 如果容器中存在的BeanDefinition是通过扫描注册的,则@Bean方法的BeanDefinition会覆盖容器中存在的
*/if(existingBeanDef instanceofScannedGenericBeanDefinition){returnfalse;}// Has the existing bean definition bean marked as a framework-generated bean?// -> allow the current bean method to override it, since it is application-level/**
* 如果容器中存在的BeanDefinition是应用程序级别的,则@Bean方法的BeanDefinition可以覆盖容器中的
*/if(existingBeanDef.getRole()> BeanDefinition.ROLE_APPLICATION){returnfalse;}// At this point, it's a top-level override (probably XML), just having been parsed// before configuration class processing kicks in.../**
* 通过以上判断,仍然不能确定容器中的BeanDefinition是否能被覆盖
* 如果当前注册器实现了DefaultListableBeanFactory(肯定实现了)并且DefaultListableBeanFactory不允许覆盖
* BeanDefinition,此时就会抛异常,因为不允许覆盖的情况下而应用程序中出现了两个相同的BeanDefinition
* 如果允许覆盖,则返回true,注意此时也是不会解析@Bean所在方法的,这里的允许覆盖是允许其它来源的
* BeanDefinition可以覆盖,比如XML
*/if(this.registry instanceofDefaultListableBeanFactory&&!((DefaultListableBeanFactory)this.registry).isAllowBeanDefinitionOverriding()){thrownewBeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName,"@Bean definition illegally overridden by existing bean definition: "+ existingBeanDef);}if(logger.isInfoEnabled()){
logger.info(String.format("Skipping bean definition for %s: a definition for bean '%s' "+"already exists. This top-level bean definition is considered as an override.",
beanMethod, beanName));}returntrue;}