照虎画猫写自己的Spring——依赖注入

上篇《照虎画猫写自己的Spring》从无到有讲述并实现了下面几点

声明配置文件,用于声明需要加载使用的类

加载配置文件,读取配置文件

解析配置文件,需要将配置文件中声明的标签转换为Fairy能够识别的类

初始化类,提供配置文件中声明的类的实例

一句话概括:不借助Spring容器,实现了Bean的加载和实例化

要想契合Fairy取名时的初衷(东西不大,但是能量无穷),只有一套加载Bean的机制是远远不够的,所以还是需要照虎画猫,完善这个小精灵。

Spring之所以在Java企业级开发的众多框架中崭露头角光芒万丈,与他的依赖注入(又名控制反转IOC)面向切面(AOP)两大杀手锏是密不可分的。在Fairy实现了加载实例化Bean的功能后,我们再往前走一步,看看依赖注入是如何实现的。

依赖注入

举个例子,大概介绍下依赖注入。
没有依赖注入之前,我们买白菜的时候,需要挎着篮子去菜市场挑选并购买;
有了依赖注入之后,我们需要白菜的时候,菜装在篮子里,已经放在你家门口。
这就是依赖注入。

对于Fairy,如果要实现依赖注入的功能,需要在上一版的代码上做一些小小的改动。
将原来的FairyBean接口和实现类FairyBeanImpl改为FairyDao接口和实现类FairyDaoImpl,除此以外,我们需要新加一个接口FairyService和实现类FairyServiceImpl。
这么声明,相信你一定明白这是为了使用依赖注入功能。

配置

我们依旧采用读取配置文件的方式来初始化容器。新建一个配置文件application-context-inject.xml

<beans> <bean> <property ref="fairyDao"></property> <property value="blue"></property> </bean> <bean> </bean> </beans>

同时我们需要FairyService和FairyServiceImpl
FairyService

package com.jackie.fairy.bean; /** * Created by jackie on 17/11/25. */ public interface FairyService { void greet(); void fly(); void lighting(); }

FairyServiceImpl

package com.jackie.fairy.bean.impl; import com.jackie.fairy.bean.FairyDao; import com.jackie.fairy.bean.FairyService; /** * Created by jackie on 17/11/25. */ public class FairyServiceImpl implements FairyService { private FairyDao fairyDao; private String lightColor; public FairyDao getFairyDao() { System.out.println("===getFairyDao===: " + fairyDao.toString()); return fairyDao; } public void setFairyDao(FairyDao fairyDao) { System.out.println("===setFairyDao===: " + fairyDao.toString()); this.fairyDao = fairyDao; } public String getLightColor() { return lightColor; } public void setLightColor(String lightColor) { this.lightColor = lightColor; } @Override public void greet() { fairyDao.greet(); } @Override public void fly() { fairyDao.fly(); } @Override public void lighting() { System.out.println("----------Hi, I am light fairy. Exactly, " + lightColor + " color light fairy----------"); } }

没有使用@Autowired注入FairyDao,这是Spring的那一套

将FairyDao作为成员变量,添加setter和getter方法(后续做注入使用)

添加FairyService自己的实现方法lighting,这是一个会发光的小精灵的feature,小精灵的发光属性取决于lightColor,这个属性需要注入,所以也有相应的setter和getter方法

升级解析器类

上篇的XmlReaderUtil解析器只能解析这样的配置结构

<parent> <child> </child> ... <child> </child> <parent>

但是我们现在需要支持的配置文件如上面的配置文件所示,所以需要升级解析器类,支持读取子标签的属性标签。
在此之前,需要新建模型PropertyDefinition,用于存储属性值

package com.jackie.fairy.model; /** * Created by jackie on 17/11/25. */ public class PropertyDefinition { private String name; private String ref; private String value; public PropertyDefinition(String name, String ref, String value) { this.name = name; this.ref = ref; this.value = value; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public String toString() { return "PropertyDefinition{" + "name='" + name + '\'' + ", ref='" + ref + '\'' + ", value='" + value + '\'' + '}'; } }

同时,需要在BeanDefinition模型中加入List,因为属性值是依附在BeanDefinition下面的。

XmlReaderUtil将核心代码改为

for (Iterator iterator = rootElement.elementIterator(); iterator.hasNext(); ) { Element element = (Element)iterator.next(); String id = element.attributeValue(Constants.BEAN_ID_NAME); String clazz = element.attributeValue(Constants.BEAN_CLASS_NAME); BeanDefinition beanDefinition = new BeanDefinition(id, clazz); // 遍历属性标签 for (Iterator propertyIterator = element.elementIterator(); propertyIterator.hasNext();) { Element propertyElement = (Element) propertyIterator.next(); String name = propertyElement.attributeValue(Constants.PROPERTY_NAME_NAME); String ref = propertyElement.attributeValue(Constants.PROPERTY_REF_NAME); String value = propertyElement.attributeValue(Constants.PROPERTY_VALUE_NAME); propertyDefinitions.add(new PropertyDefinition(name, ref, value)); } beanDefinition.setPropertyDefinitions(propertyDefinitions); beanDefinitions.add(beanDefinition); // 清空propertyDefinitions集合,因为有些bean没有property标签 propertyDefinitions = Lists.newArrayList(); }

即添加了对于属性标签的解析和存储,详细代码可进入GitHub项目查看。

实现依赖注入函数

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspwdp.html