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

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

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

  1. public static void main(String[] args) {
  2. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  3. Master master = (Master)context.getBean("hostess");
  4.  
  5. System.out.println();
  6. System.out.println();
  7. System.out.println();
  8. System.out.println("***********************************");
  9. master.WalkDog();
  10. }

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

接口 ApplicationContext

  1. public interface ApplicationContext {
  2. public Object getBean(String beanid);
  3. }

实现类 ClassPathXmlApplicationContext

  1. package com;
  2.  
  3. import java.io.File;
  4. import java.lang.reflect.Method;
  5.  
  6. import org.dom4j.Document;
  7. import org.dom4j.DocumentException;
  8. import org.dom4j.Element;
  9. import org.dom4j.Node;
  10. import org.dom4j.io.SAXReader;
  11.  
  12. public class ClassPathXmlApplicationContext implements ApplicationContext {
  13.  
  14. private String fileName;
  15.  
  16. public ClassPathXmlApplicationContext(String fileName){
  17. this.fileName = fileName;
  18. }
  19.  
  20. @Override
  21. public Object getBean(String beanid) {
  22. //获取本类的当前目录
  23. String currentPath = this.getClass().getResource("").getPath().toString();
  24.  
  25. SAXReader reader = new SAXReader();//DOM4J解释器
  26. Document doc = null;//xml文档本身
  27. Object obj = null;//目标表创建出来的实例
  28. try {
  29. doc = reader.read( new File(currentPath+fileName) );
  30. String xpath = "/beans/bean[@id='"+beanid+"']";
  31. Element beanNode = (Element) doc.selectSingleNode(xpath);
  32. String className = beanNode.attributeValue("class");
  33. obj = Class.forName(className).newInstance();
  34.  
  35. Element propertyNode = (Element) beanNode.selectSingleNode("property");
  36.  
  37. if(propertyNode!=null){
  38. System.out.println("当前bean有属性需要注入");
  39.  
  40. String propertyName = propertyNode.attributeValue("name");
  41. System.out.println("当前bean需要注入的属性为"+propertyName);
  42.  
  43. //拼接出注入方法
  44. String setMethod = "set"+(propertyName.substring(0, 1)).toUpperCase()+propertyName.substring(1,propertyName.length());
  45. System.out.println("自动调用注入方法"+setMethod);
  46.  
  47. String set_object_name = propertyNode.attributeValue("ref");
  48. System.out.println("需要注入的对象名"+set_object_name);
  49.  
  50. Object di_object = getBean(set_object_name);
  51. System.out.println("注入的对象实例"+di_object);
  52.  
  53. Method []methods = obj.getClass().getMethods();
  54.  
  55. for (Method m : methods) {
  56. if(setMethod.equals(m.getName()) ) {
  57. m.invoke(obj, di_object);
  58. break;
  59. }
  60. }
  61.  
  62. }else{
  63. System.out.println("当前bean没有属性,无需注入直接结束");
  64. }
  65.  
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69.  
  70. return obj;
  71. }
  72.  
  73. }

配置文件 applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans>
  3. <bean id="hostess" class="com.Hostess">
  4. <property name="dog" ref="Taidi_dog"></property>
  5. </bean>
  6.  
  7. <bean id="Taidi_dog" class="com.Taidi"></bean>
  8.  
  9. <bean id="Labuladuo_dog" class="com.Labuladuo"></bean>
  10. </beans>

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

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

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

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

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

自己动手编写spring IOC源码的更多相关文章

  1. 深入Spring IOC源码之ResourceLoader

    在<深入Spring IOC源码之Resource>中已经详细介绍了Spring中Resource的抽象,Resource接口有很多实现类,我们当然可以使用各自的构造函数创建符合需求的Re ...

  2. Spring IOC 源码之ResourceLoader

    转载自http://www.blogjava.net/DLevin/archive/2012/12/01/392337.html 在<深入Spring IOC源码之Resource>中已经 ...

  3. Spring IOC 源码分析

    Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...

  4. spring IoC源码分析 (3)Resource解析

    引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource  ...

  5. Spring IoC源码解析之invokeBeanFactoryPostProcessors

    一.Bean工厂的后置处理器 Bean工厂的后置处理器:BeanFactoryPostProcessor(触发时机:bean定义注册之后bean实例化之前)和BeanDefinitionRegistr ...

  6. Spring IoC源码解析之getBean

    一.实例化所有的非懒加载的单实例Bean 从org.springframework.context.support.AbstractApplicationContext#refresh方法开发,进入到 ...

  7. Spring系列(三):Spring IoC源码解析

    一.Spring容器类继承图 二.容器前期准备 IoC源码解析入口: /** * @desc: ioc原理解析 启动 * @author: toby * @date: 2019/7/22 22:20 ...

  8. Spring IoC 源码分析 (基于注解) 之 包扫描

    在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...

  9. Spring Ioc源码分析系列--Ioc的基础知识准备

    Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...

随机推荐

  1. iOS提交AppStore后申请加急审核

    提交审核后进去下面链接申请加急审核链接:https://developer.apple.com/appstore/contact/appreviewteam/index.html 在I would l ...

  2. 事件分发时候的onTouchEvent,onInterceptTouchEvent,dispatchTouchEvent调用顺序

    一直想弄清楚onTouchEvent,onInterceptTouchEvent,dispatchTouchEvent的执行顺序,以及内部使用switch (event.getAction())中的执 ...

  3. Android Volley

    1.volley简单的介绍: Volley是一个HTTP库,使Android应用程序变得更加容易,最重要的是,网络 得更快. Vollry 提供以下好处: 1.自动调度的网络请求. 2.多个并发的网络 ...

  4. IOS 网络浅析-(十一 三方 AFNetworking3.0简介)

    AFNetworking3.0是目前最新的版本,本来打算介绍一下2.6,但是想想2.6名不久矣,就决定不介绍了,有兴趣的小伙伴可以上网查一查.下面我就开始进入正题了. 目前使用人数最多的第三方网络库, ...

  5. (七)Maven使用的最佳实践

    这里说一下在使用Maven过程中不是必须的,但十分有用的几个实践,关键时刻或许能解决您的问题. 1.设置MAVEN_OPTS环境变量 通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx5 ...

  6. mongodb简介(转)

    1.简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数 ...

  7. Python写各大聊天系统的屏蔽脏话功能原理

    Python写各大聊天系统的屏蔽脏话功能原理 突然想到一个视频里面弹幕被和谐的一满屏的*号觉得很有趣,然后就想用python来试试写写看,结果还真玩出了点效果,思路是首先你得有一个脏话存放的仓库好到时 ...

  8. 使用python的Flask实现一个RESTful API服务器端[翻译]

    最近这些年,REST已经成为web services和APIs的标准架构,很多APP的架构基本上是使用RESTful的形式了. 本文将会使用python的Flask框架轻松实现一个RESTful的服务 ...

  9. IBM Bluemix体验:Containers持久存储

    上一篇介绍了在Bluemix Containers服务中使用docker hub镜像和container的高可用配置.接下来我们尝试如何在容器中使用持久存储. 在Bluemix的Containers服 ...

  10. 开发管理系统时,安装sqlserver2005问题整理

    最近在为单位开发一个综合管理系统.但是由于时间的问题,有时候就把程序带回家进行修改.但是家里有没有环境,就把数据库文件和程序带回家,可是随之问题来了.要重新在家里陪着开发环境,vs2008非常快的就安 ...