开启掘金成长之旅!这是我参与「掘金日新计划 · 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对象时,需要进行递归处理。最后在进行属性填充时需要用到反射或者工具类。