BeanDefinition的构建
beanDefinition的构建通常有两种方式,一种是builder的方式,另一种可以通过AbstractBeanDefinition的派生类进行手动构建。
方式一:
//方式一 通过 BeanDefinitionBuilder
AbstractBeanDefinition beanDef = BeanDefinitionBuilder.genericBeanDefinition(Cat.class)
.addPropertyValue("name", "tom")
.addPropertyValue("age", 2)
.addPropertyValue("weight", 3.3)
.getBeanDefinition();
方式二:
//方式二 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Cat.class);
//k-v
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue(new PropertyValue("name", "tom1"));
pvs.addPropertyValue("age", 3);
pvs.add("weight", 4.1);
//set
beanDefinition.setPropertyValues(pvs);
BeanDefinition 注册
BeanDefinition的注册提供了多种方式,可以根据项目需要或个人偏好进行选择,但是整体上要么全部采用xml形式,或者全部采用java注解的形式,避免两种混用,增加开发维护成本。
- XML 配置元信息
- <bean name="xxx" .../>
- java 注解配置元信息
- @Component(及其派生注解)
- 配置类的@Bean
- @Import外部依赖导入形式
- java API配置元信息
- 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)
- 非命名方式:BeanDefinitionReaderUtils.registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
- 配置类方式(扫描):AnnotatedBeanDefinitionReader#register(Calss ...)
这里简单讨论几种方式
1.配置类中@Bean的方式,示例:
public class BeanDefConfig {
@Bean
public Cat cat() {
return new Cat();
}
}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//1.注册Configuration配置类
ctx.register(BeanDefConfig.class);
//启动上下文
ctx.refresh();
Map<String, Cat> beansOfType = ctx.getBeansOfType(Cat.class);
System.out.println(beansOfType);
ctx.close();
2.@Import外部依赖导入形式,示例:
@Import(BeanDefConfig.class)
public class BeanDefinitionRegisterDemo {
public static void main(String[] args) {
//2.注册配置类+@Import方式
importMethod();
}
private static void importMethod() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//2.注册配置类+@Import方式
ctx.register(BeanDefinitionRegisterDemo.class);
//启动上下文
ctx.refresh();
Map<String, Cat> beansOfType = ctx.getBeansOfType(Cat.class);
System.out.println(beansOfType);
ctx.close();
}
}
@Import是构建SpringBoot Starter的一种实现方式,实现功能组件化。
3.java API方式
@Import(BeanDefConfig.class)
public class BeanDefinitionRegisterDemo {
public static void main(String[] args) {
//register配置类
//configClassRegister();
//2.注册配置类+@Import方式
//importMethod();
//手动注册
//manualRegisterDefine();
scan();
}
private static void scan() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(ctx);
reader.register(BeanDefinitionRegisterDemo.class);
ctx.refresh();
Map<String, Cat> beansOfType = ctx.getBeansOfType(Cat.class);
System.out.println("CAT: " + beansOfType);
ctx.close();
}
private static void manualRegisterDefine() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//bean定义
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Cat.class)
.addPropertyValue("name", "tom")
.addPropertyValue("age", 3)
.addPropertyValue("weight", 5.0)
.getBeanDefinition();
//1.指定名称
ctx.registerBeanDefinition("cat01", beanDefinition);
//2.自动生成名称
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, ctx);
//启动上下文
ctx.refresh();
Map<String, Cat> beansOfType = ctx.getBeansOfType(Cat.class);
System.out.println("CAT: " + beansOfType);
ctx.close();
}
}
此处给出在未指定beanName情况下使用默认的生成名称的方式源码如下:
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
int counter = -1;
// Increase counter until the id is unique.
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
return id;
}
得到的beanName类似于:com.xx.xxx.Cat#0,若有重复数字递增。