前言:对于spring IOC概念不是很了解的朋友可以阅读我上一篇博客——轻松理解spring IOC(这两篇博客也是由于我的个人原因导致现在才发布,惭愧啊)。通过这篇博客的理解之后,相信大家会对spring的IOC概念会有进一步的理解。接下来我先预览一下本例中java的类图关系。

解析:我们有一个Master接口,接口中定义了一个WalkDog()遛狗的方法,Hostess是对这个接口的具体实现。然后我们有一个Dog接口,接口中有一个bark()方法,Labuladuo和Taidi是对其的实现。最后我们的程序入口Client类调用Hostess对象的WalkDog方法。

需求:Hostess对象遛狗需要一个狗对象,目前我们的类中有两个符合需求的对象,我们只要在配置文件中进行相关配置便可以指定我们的Hostess对象调用的是哪一个具体的Dog对象。

 public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Master master = (Master)context.getBean("hostess"); System.out.println();
System.out.println();
System.out.println();
System.out.println("***********************************");
master.WalkDog();
}

解析:从main方法的前两句原spring的代码中我们可以猜想,spring框架中一定是定义了ApplicationContext这个接口,并且接口中定义了一个getBean()的方法,而ClassPathXmlApplicationContext类肯定是对其的实现。既然是我们自己动手写spring框架,我们把这个接口和类实现了也就可以了。

接口 ApplicationContext

 public interface ApplicationContext {
public Object getBean(String beanid);
}

实现类 ClassPathXmlApplicationContext

 package com;

 import java.io.File;
import java.lang.reflect.Method; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader; public class ClassPathXmlApplicationContext implements ApplicationContext { private String fileName; public ClassPathXmlApplicationContext(String fileName){
this.fileName = fileName;
} @Override
public Object getBean(String beanid) {
//获取本类的当前目录
String currentPath = this.getClass().getResource("").getPath().toString(); SAXReader reader = new SAXReader();//DOM4J解释器
Document doc = null;//xml文档本身
Object obj = null;//目标表创建出来的实例
try {
doc = reader.read( new File(currentPath+fileName) );
String xpath = "/beans/bean[@id='"+beanid+"']";
Element beanNode = (Element) doc.selectSingleNode(xpath);
String className = beanNode.attributeValue("class");
obj = Class.forName(className).newInstance(); Element propertyNode = (Element) beanNode.selectSingleNode("property"); if(propertyNode!=null){
System.out.println("当前bean有属性需要注入"); String propertyName = propertyNode.attributeValue("name");
System.out.println("当前bean需要注入的属性为"+propertyName); //拼接出注入方法
String setMethod = "set"+(propertyName.substring(0, 1)).toUpperCase()+propertyName.substring(1,propertyName.length());
System.out.println("自动调用注入方法"+setMethod); String set_object_name = propertyNode.attributeValue("ref");
System.out.println("需要注入的对象名"+set_object_name); Object di_object = getBean(set_object_name);
System.out.println("注入的对象实例"+di_object); Method []methods = obj.getClass().getMethods(); for (Method m : methods) {
if(setMethod.equals(m.getName()) ) {
m.invoke(obj, di_object);
break;
}
} }else{
System.out.println("当前bean没有属性,无需注入直接结束");
} } catch (Exception e) {
e.printStackTrace();
} return obj;
} }

配置文件 applicationContext.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="hostess" class="com.Hostess">
<property name="dog" ref="Taidi_dog"></property>
</bean> <bean id="Taidi_dog" class="com.Taidi"></bean> <bean id="Labuladuo_dog" class="com.Labuladuo"></bean>
</beans>

解析:① 我们的applicationContext.xml文件主要是配置我们的java bean。这里我们自己写一份这样的文件通知我们自己的框架有哪些对象需要注入。

② 接口 ApplicationContext 这里我只是定义了一个方法就不多解释了。

③ 实现类 ClassPathXmlApplicationContext 主要是解析我们的xml文件然后构造实例的一个类。解析xml文件我们主要使用的是dom4j,获取各个节点和节点属性与属性值。创建对象则是通过反射的方式构造对象 [obj = Class.forName(className).newInstance();]。 在判断一个对象是否有属性需要注入则是使用递归算法对其一一注入。

最后: 我们来看一下运行结果

小结:我们自己手写的框架自然没有spring框架严谨,安全(不然它早倒闭了),不过spring的原理我们自己的也是大同小异的。通过源码级别的解读,相信大家已经可以熟练掌握IOC原理。

最新文章

  1. MSSQL 2012安装报错之0x858C001B
  2. Java socket长连接代码实现
  3. &amp;12-2 查找二叉搜索树
  4. [译]Canvas的基本用法
  5. c#之习题
  6. poj1971Parallelogram Counting
  7. 关于浮动-float
  8. PL/SQL Developer 使用中文条件查询时无数据的解决方法
  9. Cubieboard4卡片式电脑
  10. iOS 使用UIBezierPath类实现随手画画板
  11. Developing Backbone.js Applications
  12. MySql COUNT(),SUM()组合用法
  13. zabbix自定义key监控memcache状态及其他服务进程
  14. &lt;&lt;精通iOS开发&gt;&gt;第14章例子代码小缺陷的修复
  15. Cannot attach medium &#39;D:\program\VirtualBox\VBoxGuestAdditions.iso&#39; {}: medium is already associated with the current state of machine uuid {}返回 代码: VBOX_E_OBJECT_IN_USE (0x80BB000C)
  16. linux基础01-bash特性
  17. 2018蓝桥杯 全球变暖(dfs)
  18. 用Power BI观察经济与健康的关系
  19. 2018C语言第三次作业
  20. LeetCode150:Evaluate Reverse Polish Notation

热门文章

  1. 学习 git基础命令
  2. Kali v2.1.2 for Raspberry Pi 3B
  3. css:overflow属性妙用
  4. j2ee项目服务器怎样部署?
  5. monkey命令选项参考
  6. 数据结构(c语言)之学生信息管理系统
  7. centos7 apache httpd安装和配置django项目
  8. linux下EOF写法梳理
  9. Django rest_framework 实用技巧
  10. [LeetCode] Minimum Unique Word Abbreviation 最短的独一无二的单词缩写