一、为什么需要PropertyValues
- Bean中可能会有多个属性,这些属性需要初始化
- 使用PropertyValues记录所有属性的值,并放入BeanDefinition中
- 便于实例化Bean后,填充属性的值
二、单个属性的值PropertyValue
新建PropertyValue类,保存一个属性的值,简称pv
@Data
@AllArgsConstructor
public class PropertyValue {
private final String name;
private final Object value;
}
三、多个属性的值PropertyValues
新建PropertyValues类,保存多个属性的值,简称pvs
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();
public void addPropertyValue(PropertyValue pv) {
this.propertyValueList.add(pv);
}
public PropertyValue getPropertyValue(String propertyName) {
for (PropertyValue pv : propertyValueList) {
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}
public PropertyValue[] getPropertyValues() {
return propertyValueList.toArray(new PropertyValue[0]);
}
}
四、新增引用类型BeanReference
表示一个Bean对另一个Bean的引用,例如Controller会用到Service
- 记录引用到的Bean的名称,即可从工厂中获取
/**
* 一个bean对另一个bean的引用
*
* @Author 孤风雪影
* @Email gitee.com/efairy520
* @Date 2025/1/2 4:29
* @Version 1.0
*/
public class BeanReference {
private final String beanName;
public BeanReference(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return beanName;
}
}
五、创建Bean后填充属性值
给BeanDefinition类,加上pvs属性,保存多个属性的值
@Data
public class BeanDefinition {
private Class<?> beanClass;
private PropertyValues propertyValues;
public BeanDefinition(Class<?> beanClass) {
this.beanClass = beanClass;
this.propertyValues = new PropertyValues();
}
public BeanDefinition(Class<?> beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}
}
六、修改AbstractAutowireCapableBeanFactory类
首先修改createBean的业务逻辑,增加一个方法调用populateBean
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = doCreateBean(beanName, beanDefinition, args);
populateBean(beanName, bean, beanDefinition);
addSingleton(beanName, bean);
return bean;
}
新增填充Bean属性值的方法populateBean
- 如果属性是引用类型,那么就立即从工厂中获取,调用getBean方法
- 此处先不考虑循环引用
protected void populateBean(String beanName, Object bean, BeanDefinition beanDefinition) {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
//A依赖B,先实例化B,先不考虑循环引用
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
BeanUtil.setFieldValue(bean, name, value);
}
}
七、测试
新建Cat类
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Cat {
private String name;
private int weight;
}
新建Person类
- 注意Person有一个Cat属性
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Person {
private String name;
private int age;
private Cat cat;
}
新建测试类
public class ApiTest {
@Test
public void test_BeanFactory(){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//注册cat
PropertyValues propertyValuesCat = new PropertyValues();
propertyValuesCat.addPropertyValue(new PropertyValue("name", "tomcat"));
propertyValuesCat.addPropertyValue(new PropertyValue("weight", 2000));
beanFactory.registerBeanDefinition("cat", new BeanDefinition(Cat.class, propertyValuesCat));
//注册person
PropertyValues propertyValuesPerson = new PropertyValues();
propertyValuesPerson.addPropertyValue(new PropertyValue("name", "jack"));
propertyValuesPerson.addPropertyValue(new PropertyValue("age", 35));
propertyValuesPerson.addPropertyValue(new PropertyValue("cat", new BeanReference("cat")));
beanFactory.registerBeanDefinition("person", new BeanDefinition(Person.class, propertyValuesPerson));
Person person = (Person) beanFactory.getBean("person");
System.out.println("person = " + person);
}
}
打印输出
person = Person(name=jack, age=35, cat=Cat(name=tomcat, weight=2000))
八、总结
- 我们可以在创建BeanDefinition的时候,传入PropertyValues,便于初始化属性
- 在调用getBean带args参数方法,使用的是构造器注入,PropertyValues则是使用set方法注入
- 后续会通过XML简化Bean的注册,但是底层仍然是BeanDefinition与PropertyValues