BeanDefinition元信息有哪些信息?
这里放小马老师的一张图
在我刚开始学习Spring的时候,还是XML方式来配置的,所以大概都知道什么意思,一般我们都BeanDefinition一般通过XML方式配置的比较多一点
下面看看BeanDefinition的构建
BeanDefinition的构建
- 通过BeanDefinitionBuilder
- 通过AbstractBeanDefinition以及派生类
/**
* @ClassName BeanDefinitionCreationDemo
* @Description
* @Author huacheng
* @Date 2021/9/21 4:31 下午
* @Version 1.0
**/
public class BeanDefinitionCreationDemo {
public static void main(String[] args) {
//1.通过BeanDefinitionBuilder
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
//通过属性设置操作
// public BeanDefinitionBuilder addPropertyValue(String name, @Nullable Object value) {
// this.beanDefinition.getPropertyValues().add(name, value);
// return this;
// }
beanDefinitionBuilder.addPropertyValue("name","小王");//等同于XML配置方式
beanDefinitionBuilder.addPropertyValue("age",18);
//获取BeanDefinition实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
//这里只是生成了一个Bean的定义,我们还是可以做修改操作的
//并非是Bean的最终态,可以自定义修改
System.out.println(beanDefinition);
//2。通过AbstractBeanDefinition 以及派生构建
//genericBeanDefinition源码new了GenericBeanDefinition,那么我们就可以通过它来获取
// public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
// BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
// builder.beanDefinition.setBeanClass(beanClass);
// return builder;
// }
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(User.class);
// public void setPropertyValues(MutablePropertyValues propertyValues) {
// this.propertyValues = propertyValues;
// }
//通过MutablePropertyValues 批量操作属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
// public void addPropertyValue(String propertyName, Object propertyValue) {
// this.addPropertyValue(new PropertyValue(propertyName, propertyValue)); 跟上面add实际上是一样的
// }
propertyValues.addPropertyValue("name","小王");
propertyValues.addPropertyValue("age",30);
propertyValues.add("name","小王").add("age",30);
genericBeanDefinition.setPropertyValues(propertyValues);
System.out.println(genericBeanDefinition);
}
}
运行结果
Generic bean: class [com.huacheng.ioc.dependency.lookup.domain.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
Generic bean: class [com.huacheng.ioc.dependency.lookup.domain.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
我们可以看到是一样的
怎么命名Spring Bean
每个Bean拥有一个或者多个识别符(identifiers),这些标识符在 Bean 所在的容器必须是 唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来 扩充。
注:并不是应用里面唯一
在基于 XML 的配置元信息中,开发人员可用 id 或者 name 属性来规定 Bean 的 标识符。通 常 Bean 的 标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在 name 属性使用半角逗号(“,”)或分号(“;”) 来间隔。
Bean 的 id 或 name 属性并非必须制定,如果留空的话,容器会为 Bean 自动生成一个唯一 的名称。Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合 Java 的命名约 定。
Bean 名称生成器(BeanNameGenerator)
由 Spring Framework 2.0.3 引入,框架內建两种实现:
DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现
AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator 实现,起始于 Spring Framework 2.5
public interface BeanNameGenerator {
String generateBeanName(BeanDefinition var1, BeanDefinitionRegistry var2);
}
一个参数是Bean定义,一个是Bean定义的注册中心
我们看看它的第一个实现
public class DefaultBeanNameGenerator implements BeanNameGenerator {
public static final DefaultBeanNameGenerator INSTANCE = new DefaultBeanNameGenerator();
public DefaultBeanNameGenerator() {
}
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
}
}
为什么这个地方没有把构造器写成私有的呢?
因为DefaultBeanNameGenerator是一个公有API,如果擅自在高版本中,把他的构造函数改成非public的话,其他版本就会不兼容
public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
return generateBeanName(beanDefinition, registry, false);
}
public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException {
//先取BeanClassName
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
} else if (definition.getFactoryBeanName() != null) {
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");
} else if (isInnerBean) {//内嵌Bean,会生成一个#号
String id = generatedBeanName + "#" + ObjectUtils.getIdentityHexString(definition);
return id;
} else {//唯一Bean,也会拼接一个#,加一个数字,数字从0开始逐一叠加
return uniqueBeanName(generatedBeanName, registry);
}
}
注解实现
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
public AnnotationBeanNameGenerator() {
}
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {//如果是注解标注
String beanName = this.determineBeanNameFromAnnotation((AnnotatedBeanDefinition)definition);
if (StringUtils.hasText(beanName)) {
return beanName;
}
}
//传统方式的兼容
return this.buildDefaultBeanName(definition, registry);
}
Bean的别名
Bean 别名(Alias)的价值
• 复用现有的 BeanDefinition
• 更具有场景化的命名方法,比如:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
定制别名