上篇《照虎画猫写自己的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
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,用于存储属性值
同时,需要在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项目查看。
实现依赖注入函数