上一篇中,我们的代码已经可以使用工厂实例化一个bean并放到容器中。但是还剩下一个问题,我们实例化的bean还没有属性,或者定义了属性,但没有为属性赋值。在这一篇的代码中,我们将重构上一篇中出现的几个类,并添加两个新类,最终完成bean属性的初始化。
首先是一个保存bean属性字段和值的配置类。
/**
* 用于bean的属性注入
* @author yihua.huang@dianping.com
*/
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;
}
}
然而一个bean可能有多个属性,所以还需要一个类来维护一个属性列表。
/**
* 包装一个对象所有的PropertyValue。<br/>
* 为什么封装而不是直接用List?因为可以封装一些操作。
* @author yihua.huang@dianping.com
*/
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类中需要加入Property这个类作为关联的对象,用来保存Bean的属性值,为初始化做准备。
/**
* bean的内容及元数据,保存在BeanFactory中,包装bean的实体
* @author yihua.huang@dianping.com
*/
public class BeanDefinition {
private Object bean;
private Class beanClass;
private String beanClassName;
private PropertyValues propertyValues; //注意新加入的关联对象
public BeanDefinition() {
}
public void setBean(Object bean) {
this.bean = bean;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Object getBean() {
return bean;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}
上一篇中bean的实例化在AutowireCapableBeanFactory这个类里面完成,所以我们重构这个类,在初始化的时候为属性赋值。
/**
* 可自动装配内容的BeanFactory
*
* @author yihua.huang@dianping.com
*/
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
@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();
}
/**
* 在这里实现了bean属性的赋值操作
* @param bean
* @param mbd
* @throws Exception
*/
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());
}
}
}
于是,结合上一篇的代码,我们这一小个系列所要完成的目标就此实现啦。。。
当然,测试代码中需要给出bean属性的值,下面就是测试代码。
/**
* @author yihua.huang@dianping.com
*/
public class BeanFactoryTest {
@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();
}
}
当然,最后要附上代码的UML啦,这个图就包括上一篇提及的代码加上这一篇的
可以看到,HelloWorldService和框架类没有关联,仅仅通过配置文件进行装配,符合松散的耦合关系。
当然,整个一次的配置只是一个类,没有写到XML里面。在下一篇中我们将实现XML的配置。