在框架中,你经常发现,框架读取xml中的配置来完成解耦的操作,比如mybatis,或者是spring等。比如在学习spring的时候,我们会这xml中编写这些配置:
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="xxxService" class="com.wei.service.impl.xxxServiceImpl">
<property name="XxxDao" ref="xxxDao"></property>
</bean>
<bean id="xxxDao" class="com.wei.dao.impl.XxxDao"></bean>
</beans>
上面的xml主要讲的就是在xxxServiceImpl配置了XxxDao属性,即如下的形式:
public class XxxServiceImpl implements XxxService {
private XxxDao xxxDao;
public XxxServiceImpl(XxxDao xxxDao) {
this.xxxDao = xxxDao;
}
}
所以今天的内容就是通过在xml中配置bean的关系,就是类与类之间的依赖关系。在以前,我们都是通过new来进行bean的依赖关系,即:如果A类中需要B类的实例,就是在A类中new 出一个B类,现在我们已经把A和B类的关系通过xml来配置了,所以就不能通过new了。
我们的今天的任务也是明确的,就是读取xml中的配置,完成bean的注入。
设计步骤:
- 读取xml中的配置,并通过反射,拿到类的实例
- 存储类的实例,并对外提供一个方法,可以获取bean的实例
以上的两大步骤就可以完成今日的任务了
首先我们构建一个BeanFactory类,这个类承担两个步骤的功能。为了更好的读取xml中的内容,我们需要引入两个jar:
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
public class BeanFactory {
public static Map<String,Object> map = new HashMap<>();
/**
* 用静态代码块进行初始化
*/
static {
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.xml");
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(resourceAsStream);
Element rootElement = document.getRootElement();
List<Element> beanNodes = rootElement.selectNodes("//bean");
for (int i = 0; i < beanNodes.size(); i++) {
Element element = beanNodes.get(i);
String id = element.attributeValue("id");
String aClass = element.attributeValue("class");
//反射拿到类模板
Class<?> aClass1 = Class.forName(aClass);
Object o = aClass1.newInstance();
map.put(id,o);
}
//维护bean之间的关系
//拿到property节点的信息
List<Element> propertyElements = rootElement.selectNodes("//property");
for (int i = 0; i < propertyElements.size(); i++) {
Element element = propertyElements.get(0);
String name = element.attributeValue("name");
String ref = element.attributeValue("ref");
String parentId = element.getParent().attributeValue("id");
Object parentObject = map.get(parentId);
//利用反射拿到父类对象的全部方法
Method[] methods = parentObject.getClass().getMethods();
//遍历全部方法,找到set方法,完成bean的注入
for (int j = 0; j < methods.length; j++) {
if (("set" + name).equalsIgnoreCase(methods[j].getName())) {
Object propertyObject = map.get(ref);
methods[j].invoke(parentObject,propertyObject);
}
}
}
} catch (DocumentException | ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 通过对外暴漏接口,获取对应的bean实例
* @param id
* @return
*/
public Object getBean(String id) {
return map.get(id);
}
}
结果演示: