死磕源码系列【BeanNameGenerator生成bean名称策略接口详解】

本文包括bean name实现类源码详解,及自定义bean name生成策略源码原理详解

bean name生成策略三个实现类源码详解

BeanNameGenerator接口是BeanDefinition定义生成bean名称的策略接口;

public interface BeanNameGenerator {

	/**
	 * 为给定的BeanDefinition生成一个bean名称
	 */
	String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);

}

看下BeanNameGenerator接口实现类UML关系图:

在这里插入图片描述

DefaultBeanNameGenerator是BeanNameGenerator接口的默认实现类:

public class DefaultBeanNameGenerator implements BeanNameGenerator {

	/**
	 * DefaultBeanNameGenerator实例常量,用于在AbstractBeanDefinitionReader类中属性beanNameGenerator的设置
	 */
	public static final DefaultBeanNameGenerator INSTANCE = new DefaultBeanNameGenerator();

	//通过BeanDefinitionReaderUtils工具类的generateBeanName方法生成指定BeanDefinition的bean名称
	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
	}

}

BeanDefinitionReaderUtils#generateBeanName代理方法源码:

	/**
	 * 为给定的顶级BeanDefinition定义生成一个bean名称,该名称在给定的bean工厂中是唯一的
	 */
	public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		return generateBeanName(beanDefinition, registry, false);
	}

	/**
	 * 为给定的顶级BeanDefinition定义生成一个bean名称,该名称在给定的bean工厂中是唯一的
	 * @param BeanDefiniton定义
	 * @param 注册bean的工厂类
	 * @param isInnerBean 给定的BeanDefinition是注册为内部bean还是顶级bean(允许内部bean和顶级bean生成特殊名称)
	 */
	public static String generateBeanName(
			BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
			throws BeanDefinitionStoreException {
		//获取bean定义的类名
		String generatedBeanName = definition.getBeanClassName();
		if (generatedBeanName == null) {
			if (definition.getParentName() != null) {
        //当bean定义名称不存在并且存在父类时命名方式
				generatedBeanName = definition.getParentName() + "$child";
			}
			else if (definition.getFactoryBeanName() != null) {
        //读取生成该bean的factoryBean名称做前缀
				generatedBeanName = definition.getFactoryBeanName() + "$created";
			}
		}
		if (!StringUtils.hasText(generatedBeanName)) {
			throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
					"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
		}

		if (isInnerBean) {
			// 当为内部类时使用#好分割和系统的唯一hash码作为后缀
			return generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
		}

		// 顶级bean,使用普通类名加唯一后缀
		return uniqueBeanName(generatedBeanName, registry);
	}

	/**
	 * 将给定的bean名称转换为给定bean工厂的唯一bean名称,如果有必要,附加一个唯一的计数器做后缀
	 */
	public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
		String id = beanName;
		int counter = -1;

		// 增加计数器,直到id唯一
		String prefix = beanName + GENERATED_BEAN_NAME_SEPARATOR;
		while (counter == -1 || registry.containsBeanDefinition(id)) {
			counter++;
			id = prefix + counter;
		}
		return id;
	}

AnnotationBeanNameGenerator是BeanNameGenerator接口的实现类,用来生成被@Component注解或者其它@Component派生注解标注的bean;示例:被@Component注解标注的@Repository注解。

如果注释的值没有指示bean名称,那么将基于类的短名称(第一个字母消息)构建一个适当的名称。例如:com.xyz.FooServiceImpl类的bean名称是fooServiceImpl。

AnnotationBeanNameGenerator类源码:

public class AnnotationBeanNameGenerator implements BeanNameGenerator {

	/**
	 * 默认AnnotationBeanNameGenerator实例的方便常量,用于组件扫描目的(即@Componment注解及@ComponmentScan注解扫描包)bean名称生成
	 * @since 5.2
	 */
	public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();
	//@Component注解类常量
	private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";

	private final Map<String, Set<String>> metaAnnotationTypesCache = new ConcurrentHashMap<>();


	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		if (definition instanceof AnnotatedBeanDefinition) {
      //通过注解的属性值获取bean名称
			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
			if (StringUtils.hasText(beanName)) {
				//显式的找到bean名称
				return beanName;
			}
		}
		//如果注解未指定bean名称,则生成一个唯一的默认bean名称
		return buildDefaultBeanName(definition, registry);
	}

	/**
	 * 从类上的一个注释派生bean名称(即通过注解的属性value值来获取唯一的bean名称)
	 * @param annotatedDef the annotation-aware bean definition
	 * @return the bean name, or {@code null} if none is found
	 */
	@Nullable
	protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
		AnnotationMetadata amd = annotatedDef.getMetadata();
		Set<String> types = amd.getAnnotationTypes();
		String beanName = null;
		for (String type : types) {
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
			if (attributes != null) {
				Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
					Set<String> result = amd.getMetaAnnotationTypes(key);
					return (result.isEmpty() ? Collections.emptySet() : result);
				});
        //检查给定的注释是否允许通过其注释的value属性构造bean名称
				if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
					Object value = attributes.get("value");
					if (value instanceof String) {
						String strVal = (String) value;
						if (StringUtils.hasLength(strVal)) {
							if (beanName != null && !strVal.equals(beanName)) {
								throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
										"component names: '" + beanName + "' versus '" + strVal + "'");
							}
							beanName = strVal;
						}
					}
				}
			}
		}
		return beanName;
	}

	/**
	 * 检查给定的注释是否允许通过其注释的value属性构造bean名称
	 */
	protected boolean isStereotypeWithNameValue(String annotationType,
			Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {

		boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
				metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) ||
				annotationType.equals("javax.annotation.ManagedBean") ||
				annotationType.equals("javax.inject.Named");

		return (isStereotype && attributes != null && attributes.containsKey("value"));
	}

	/**
	 * 从给定的bean定义派生一个默认的bean名称,即类名首字母小写
	 */
	protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		return buildDefaultBeanName(definition);
	}

	/**
	 * 从给定的bean定义派生一个默认的bean名称,即类名首字母小写
	 */
	protected String buildDefaultBeanName(BeanDefinition definition) {
		String beanClassName = definition.getBeanClassName();
		Assert.state(beanClassName != null, "No bean class name set");
		String shortClassName = ClassUtils.getShortName(beanClassName);
		return Introspector.decapitalize(shortClassName);
	}

}

FullyQualifiedAnnotationBeanNameGenerator类源码:

FullyQualifiedAnnotationBeanNameGenerator类是AnnotationBeanNameGenerator类的一个扩展用于生成类的全限定类名作为bean名称,

public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {

	@Override
	protected String buildDefaultBeanName(BeanDefinition definition) {
		String beanClassName = definition.getBeanClassName();
		Assert.state(beanClassName != null, "No bean class name set");
		return beanClassName;
	}

}
bean name自定义生成策略源码原理解析

在后置beanfactory容器回调接口实现类ConfigurationClassPostProcessor中定义有三个变量:

//使用类的全限定名作为bean的默认生成策略
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR =
			new FullyQualifiedAnnotationBeanNameGenerator();
			
	/* 使用短类名作为默认bean名称生成策略 */
	private BeanNameGenerator componentScanBeanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

	/* 使用类的全新定名作为bean默认生成策略 */
	private BeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;	
  //是否是本地xml配置的BeanNameGenerator生成器
	private boolean localBeanNameGeneratorSet = false;

ConfigurationClassPostProcessor#setBeanNameGenerator方法设置自定义bean name生成器,这个setter通常只适用于将ConfigurationClassPostProcessor后处理器配置为XML中的独立bean定义,例如:不使用专用的AnnotatiionConfig*应用程序上下文或者context:annotation-config标签,针对应用程序上下文指定的任何bean名称生成器都将优先于此处的设置(此方法只适合Spring中通过xml配置的形式,springboot可以忽略)。

	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
		this.localBeanNameGeneratorSet = true;
		this.componentScanBeanNameGenerator = beanNameGenerator;
		this.importBeanNameGenerator = beanNameGenerator;
	}

ConfigurationClassPostProcessor#processConfigBeanDefinitions方法(只展示bean name名称生成策略部分代码):

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		...

		//检测通过封闭的应用程序上下文提供的任何自定义bean名称生成策略
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
      //springboot 中localBeanNameGeneratorSet默认是false
			if (!this.localBeanNameGeneratorSet) {
        //获取自定义的bean name生成策略
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
          //设置组件扫描bean name生成策略
					this.componentScanBeanNameGenerator = generator;
          //设置import bean name生成策略
					this.importBeanNameGenerator = generator;
				}
			}
		}
		...
		
	}

到这里会有一个疑问内部自定义bean name生成策略bean org.springframework.context.annotation.internalConfigurationBeanNameGenerator(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR)是如何注入到IOC容器之中的?那我们看下启动类SpringApplication#run方法,方法中内嵌prepareContext方法,prepareContext方法内嵌postProcessApplicationContext方法:

	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    //此处会判定bean name生成策略是否为空
		if (this.beanNameGenerator != null) {
    //此处 将上一步中的疑问,自定义bean name生成策略注入到IOC容器		
      context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);
		}
		。。。
	}

此段代码我们看到了如何将bean name自定义生成策略注入到IOC容器之中,那么beanNameGenerator生成策略是如何获取呢?beanNameGenerator是SpringApplication类的一个属性,提供了setter方法:

	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		this.beanNameGenerator = beanNameGenerator;
	}

此处的setter方法就是我们设置自定义bean name生成器的入口,示例如下:

@SpringBootApplication
public class QuartzBootStrap {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(QuartzBootStrap.class);
      		//MySelfBeanNameGenerator是自定义bean name生成策略
        application.setBeanNameGenerator(new MySelfBeanNameGenerator());
        application.run(args);
    }
}

至此,springboot如何自定义bean name生成策略,此处的设置是全局的,不包括指定配置类的bean name生成策略。

自定义生成bean name策略实现类:

public class MySelfBeanNameGenerator implements BeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        System.out.println("--------"+definition.getBeanClassName());
        return definition.getBeanClassName();
    }
}

GitHub源码:https://github.com/mingyang66/spring-parent

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值