读懂Spring核心系列3(自动装配属性)

来源:互联网 发布:淘宝刷单权重 编辑:程序博客网 时间:2024/06/14 09:50

上一篇中,我们的代码已经可以使用工厂实例化一个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 {@Overrideprotected 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 {@Testpublic void test() throws Exception {// 1.初始化beanfactoryBeanFactory 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.生成beanbeanFactory.registerBeanDefinition("helloWorldService", beanDefinition);// 5.获取beanHelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");helloWorldService.helloWorld();}}


当然,最后要附上代码的UML啦,这个图就包括上一篇提及的代码加上这一篇的





可以看到,HelloWorldService和框架类没有关联,仅仅通过配置文件进行装配,符合松散的耦合关系。

当然,整个一次的配置只是一个类,没有写到XML里面。在下一篇中我们将实现XML的配置。


0 0
原创粉丝点击