step1、2中我们完成了一个简单的IOC的容器,可以利用反射将bean放入工厂。下边我们就看看step3做了什么
Step3 为bean注入属性
这一步,我们想要为bean注入属性。我们选择将属性注入信息保存成PropertyValue对象,并且保存到BeanDefinition中。这样在初始化bean的时候,我们就可以根据PropertyValue来进行bean属性的注入。Spring本身使用了setter来进行注入,这里为了代码简洁,我们使用Field的形式来注入。
类图(简单呈现,并不标准)
PropertyValue
public class 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
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
public PropertyValues() {
}
public void addPropertyValue(PropertyValue pv) {
//TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
this.propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}
}
BeanDefinition
public class BeanDefinition {
...//相同的部分不再重复
private PropertyValues propertyValues;
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}
AutowireCapableBeanFactory
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
applyPropertyValues(bean, beanDefinition);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}
protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, propertyValue.getValue());
}
}
测试类:
public class HelloWorldService {
private String text;
public void helloWorld(){
System.out.println(text);
}
public void setText(String text) {
this.text = text;
}
}
@Test
public void test() throws Exception {
// 1.初始化beanfactory
BeanFactory beanFactory = new AutowireCapableBeanFactory();
// 2.bean定义
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService");
// 3.设置属性
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!"));
beanDefinition.setPropertyValues(propertyValues);
// 4.生成bean
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
// 5.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();
}
走测试方法前3步的过程就是在装配beanDefinition的过程,下图就是走完前3步代码呈现的结果,我们可以发现,在第二步的时候得到了beanClass,也就是说通过类名,我们找到了这个具体的类,第3步就是然后往类(beanDefinition)里边set属性:
接下来就是生成bean的过程:
1. doCreateBean:传入的参数是上一步装配好的beanDefinition对象,这一步主要是实例化我们的HelloWorldService对象,然后给我们的对象附上属性值
上述过程被作者拆分成了三个方法,这也是我们在代码中需要学习的地方,一个方法只做一件事,作者的第一个方法是doCreateBean,这个方法调用了其他两个方法,第二个方法是createBeanInstance实例化类的对象,第三个方法是给类的字段赋值applyPropertyValues,这样看代码就非常的清晰且明了,一目了然,这三个方法可以说是生成bean的核心代码,都利用了反射的机制来实现
最后,bean就被生成出来了,跟第二个过程相比,只是加入了属性的赋值,架构上边没有大的调整,下一篇,我们将学习通过配置文件进行bean的生成