Spring的依赖注入是指将对象的创建权交给Spring框架,将对象所依赖的属性注入进来的行为.在学习了dom4j后,其实也可以利用dom4j和反射做一个小Demo模拟Spring框架的这种功能.下面是具体的步骤:

  第一步,编写配置文件.配置文件的书写,采用了和Spring的配置文件applicationContext.xml一样的书写规则:

<?xml version="1.0" encoding="UTF-8"?>
<!-- applicationContext.xml配置文件 -->
<beans>
<bean id="student1" class="com.xyy.domain.Student">
<property name="name" value="hlhdidi"></property>
<property name="age" value="13"></property>
<property name="teacher" ref="teacher1"></property>
</bean>
<bean id="teacher1" class="com.xyy.domain.Teacher">
<property name="name" value="cwb"></property>
<property name="classes" value="高三九班"></property>
</bean>
</beans>

  第二步,编写JavaBean类,书写了两个JavaBean,其中Student类中有一个Teacher类的引用.

//Student类
public class Student implements Serializable{
private String name;
private int age;
private Teacher teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", teacher=" + teacher + "]";
} }
//Teacher类
public class Teacher implements Serializable{
private String name;
private String classes;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClasses() {
return classes;
}
public void setClasses(String classes) {
this.classes = classes;
}
@Override
public String toString() {
return "Teacher [name=" + name + ", classes=" + classes + "]";
} }

  第三步,也是最关键的一步,编写MyClassPathXmlApplicationContext类,在这个类里面做了如下操作:

  1.利用传入的参数获取xml文件的流,并且利用dom4j解析成Document对象

  2.对于Document对象获取根元素对象<beans>后对下面的<bean>标签进行遍历,判断是否有符合的id.

  3.如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据属性值利用反射建立对象.

  4.遍历<bean>标签下的property标签,并对属性赋值.注意,需要单独处理int,float类型的属性.因为在xml配置中这些属性都是以字符串的形式来配置的,因此需要额外处理.

  5.如果属性property标签有ref属性,说明某个属性的值是一个对象,那么根据id(ref属性的值)去获取ref对应的对象,再给属性赋值.

  6.返回建立的对象,如果没有对应的id,或者<beans>下没有子标签都会返回null

  代码如下:

public class MyClassPathXmlApplicationContext {
private String xmlName; public MyClassPathXmlApplicationContext(String xmlName) {
this.xmlName=xmlName;
} public Object getBean(String id) {
Object obj=null; //声明引用.
//进行xml的解析
SAXReader reader=new SAXReader();
try {
Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream(xmlName));
Element root=document.getRootElement();
//遍历.看是否有元素的id为传入的参数.
List<Element> elements = root.elements();
if(elements.size()>0) {
for(Element element:elements ) {
if(element.attributeValue("id").equals(id)) {//id相同开始创建对象
//采用反射创建对象.
String className=element.attributeValue("class");
Class beanClass=Class.forName(className);
obj=beanClass.newInstance();
//获取子标签的属性.
List<Element> attributes=element.elements();
if(attributes.size()>0) {
for(Element attribute:attributes) {
String name=attribute.attributeValue("name");
Field field = beanClass.getDeclaredField(name);
field.setAccessible(true);
if(attribute.attribute("ref")!=null) {
//此属性的值是一个对象.这里由于直接调用getBean方法赋值给对象,返回的对象一定是Bean参数的对象,因此强制转换不会出问题
String refid=attribute.attributeValue("ref");
field.set(obj, getBean(refid));
}
else {
//此属性值是一个字符串.这里单独处理int,float类型变量.如果不处理,会将String类型直接赋值给int类型,发生ClassCastException
String value=attribute.attributeValue("value");
//需要对类型进行判断
if(value.matches("[0-9]+")) {
//整数
int x=Integer.parseInt(value);
field.set(obj, x);
continue;
}
if(value.matches("[0-9]*(\\.+)[0-9]*")) {
//浮点数
float y=Float.parseFloat(value);
field.set(obj, y); //注意double可以接受float类型
continue;
}
field.set(obj, value);//处理String类型
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}

  第四步:测试.

@Test
public void testMySpring() {
MyClassPathXmlApplicationContext applicationContext=new MyClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(applicationContext.getBean("student1"));
}

  测试结果:

Student [name=hlhdidi, age=13, teacher=Teacher [name=cwb, classes=高三九班]]

  总结:

  dom4j是一个很好的解析xml的工具,而解析xml是一个很重要的基本功,对于理解框架原理有很大的帮助.反射结合xml文件的解析,可以实现在任何类中方便的创建任何对象.

采用dom4j和反射模拟Spring框架的依赖注入功能的更多相关文章

  1. spring框架之依赖注入(DI)

    1. IOC和DI的概念 * IOC -- Inverse of Control,控制反转,将对象的创建权反转给Spring!! * DI -- Dependency Injection,依赖注入,在 ...

  2. PHP 从另一个角度来分析 Laravel 框架的依赖注入功能

    从根本上说,依赖注入不是让对象创建一个依赖关系,也不是让工厂对象去创建对象,而是将所需的依赖变成一个外部对象,使之成为一个"某些人的问题” 你为"某些人的问题”注入了类的依赖关系. ...

  3. Spring框架——IOC依赖注入

    本来想把IOC和AOP一起介绍的,但是AOP内容太多了,所以就分开了,最后的结果就是这一篇只剩下一点点了.这不是第一次写关于IOC的文章了,之前写过Java反射,Java注解,也写过通过XML解析实现 ...

  4. Spring框架(依赖注入)

    特点 1轻量级和侵入性低 2依赖注入和面向接口实现松耦合 3面向切面编程 减少样式代码 专有名词: 1依赖注入:对象无需自行管理依赖关系.通过系统负责协调在创建对象的第三方组件的设定,实现依赖关系自动 ...

  5. Spring框架的IOC核心功能快速入门

    2. 步骤一:下载Spring框架的开发包 * 官网:http://spring.io/ * 下载地址:http://repo.springsource.org/libs-release-local/ ...

  6. JavaEE开发之Spring中的依赖注入与AOP

    上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...

  7. JavaEE开发之Spring中的依赖注入与AOP编程

    上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...

  8. [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期

    生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...

  9. [ASP.NET Core 3框架揭秘] 依赖注入[9]:实现概述

    <服务注册>.<服务消费>和<生命周期>主要从实现原理的角度对.NET Core的依赖注入框架进行了介绍,接下来更进一步,看看该框架的总体设计和实现.在过去的多个版 ...

随机推荐

  1. 我的第一个FluentNHibernate例子

    刚刚接触NHibernate和FluentNHibernate,所以最好的方法是从一个简单的例子入手. 开发环境考虑到是实际情况还有好多朋友没有用VS2015,就用VS2013withUpdate5吧 ...

  2. 夺命雷公狗-----React---17--事件常用的属性

    我们可以通过打印的方式将他打印出来看看,如下所示: <!DOCTYPE> <html> <head> <meta charset="utf-8&qu ...

  3. C/C++之指针加减法

    C和C++中可对指针进行加减,但对其进行乘除则基本无实际意义.一般来说,对指针进行减法的前提是减数和被减数均指向同一数组.加法同理.需要注意的是,两个指针的减法,结果是两个地址之间索引变量的数目,而不 ...

  4. 敏捷项目开源管理软件ScrumBasic(1)

    ScrumBasic 是本人基于Asp.net mvc6 最新的core 1.0写的一个敏捷项目管理软件. 目前只是一个基础版本的功能.只支持1个project. 后期会在这个基础上做扩展和权限管理. ...

  5. 总结工作中常见的linux命令

    本文是总结下自己在工作中遇到的常见linux 命令,会持续更新! 1.文件路径切换 进入 cd 返回上一级  cd .. 2.复制 cp 源文件名 目标文件夹 cp log.log test5 3.编 ...

  6. Android studio 中的配置编译错误总结

    1.编译Andorid 工程的时候,有时候出现gradle 报下面的错误. Error:(1, 0) Cause: com/android/build/gradle/LibraryPlugin : U ...

  7. A ship is always safe at the shore - but that is not what it is built for.

    A ship is always safe at the shore - but that is not what it is built for. 船靠岸边总是安全的,但那不是建造它的目的.

  8. php时间戳之间相互转换

    第一种情况: 将时间戳转换成年月日格式 <?php echo date('Y-m-d H:i:s',$v['apply_time']);?> 第二种情况: 将年月日转换成时间戳 strto ...

  9. UITableView heightForHeaderInSection遇到的坑

    出现这种现象只需要把 heightforfoot改为0.01 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSectio ...

  10. 计算缓存文件大小、清除缓存的Cell

    计算缓存文件大小 - (void)getCacheSize { // 总大小 unsigned long long size = 0; // 获得缓存文件夹路径 NSString *cachesPat ...