四:注入属性和依赖对象

87 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

思考关于“类中是否有属性” ,在实例化时需要填充属性信息,才能创建一个完整的对象

属性填充是在使用 newInstance 或者 Cglib 创建 Bean 对象后开始执行的,所以可以在 AbstractAutowireCapableBeanFactory 类的 createBean 方法中 添加属性填充操作 applayPropertyValues

在定义 Bean 对象的 BeanDefinition 类中添加对象创建需要的 PropertyValues属性集合。

填充的属性需要定义一个 BeanReference 引用对象,在具体实例化时进行递归创建和填充。

ps:在Spring 源码中,BeanReference 是一个接口。

代码实现

PropertyValue - 属性信息

/** 属性名称 */
private final String name;
​
/** 属性值 */
private final Object value;
​
public PropertyValue(String name, Object value) {
    this.name = name;
    this.value = value;
}
​
public String getName() {
    return name;
}
​
public Object getValue() {
    return value;
}

PropertyValues - 属性值集合

private final List<PropertyValue> propertyValueList = new ArrayList<>();
​
public void addPropertyValue(PropertyValue pv) {
    this.propertyValueList.add(pv);
}
​
public PropertyValue[] getPropertyValues() {
    return this.propertyValueList.toArray(new PropertyValue[0]);
}
​
public PropertyValue getPropertyValue(String propertyName) {
    for (PropertyValue pv : this.propertyValueList) {
        if (pv.getName().equals(propertyName)) {
            return pv;
        }
    }
    return null;
}

BeanDefinition - Bean 的定义信息

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();
}
//get set....

AbstractAutowireCapableBeanFactory - 实现默认bean创建的抽象bean工厂超类

private void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
    try {
        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);
        }
    } catch (Exception e) {
        throw new BeansException("Error setting property values:" + beanName);
    }
}

测试部分

UserDao - 模拟Dao层

private static Map<String, String> hashMap = new HashMap<>();
​
static {
    hashMap.put("1", "六一是居");
    hashMap.put("2", "六一不是居");
    hashMap.put("3", "六一肯定居");
}
​
public String queryUserName(String uId) {
    return hashMap.get(uId);
}

UserService - 使用

 private String uId;
​
    private UserDao userDao;
​
    public void queryUserInfo() {
        System.out.println("查询用户信息:" + userDao.queryUserName(uId));
    }
​
    public String getuId() {
        return uId;
    }
​
    public void setuId(String uId) {
        this.uId = uId;
    }
​
    public UserDao getUserDao() {
        return userDao;
    }
​
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

ApiTest - 调用方

// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
​
// 2. UserDao 注册
beanFactory.registerBeanDefinition("userDao", new BeanDefinition(UserDao.class));
​
// 3. UserService 设置属性[uId、userDao]
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("uId", "1"));
propertyValues.addPropertyValue(new PropertyValue("userDao", new BeanReference("userDao")));
​
// 4. UserService 注入bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class, propertyValues);
beanFactory.registerBeanDefinition("userService", beanDefinition);
​
// 5. UserService 获取bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();

与直接获取 Bean 对象不同,需要将 UserDao 注册到Spring Bean 容器中,

beanFactory.registerBeanDefinition("userDao", new BeanDefinition(UserDao.class));

总结

在实现 有无构造函数的实例化策略后,对Bean 对象的属性信息进行填充。当Bean的属性为Bean对象时,需要进行递归处理。最后在进行属性填充时需要用到反射或者工具类。