一、程序实例

  假设一个简单地实例,我们有一个人,人可能有姓名,年龄等属性,每天上下班的时候需要坐车,他可能做小轿车,suv等,这样一个场景。我们很容易想到如下代码:

1、人的对象类,包括两个属性,姓名和车

package com.zjl.ioc;public class Person {String name;Driveable driveable;public String getName() {return name;}public void setName(String name) {this.name = name;}public Driveable getDriveable() {return driveable;}public void setDriveable(Driveable driveable) {this.driveable = driveable;}public void drive(){System.out.println(this.name+"准备开车");this.driveable.drive();}
}

2、假设我们所有的车子都继承一个可以开走的接口

package com.zjl.ioc;public interface Driveable {public void drive();
}

3、定义一种车,小汽车

package com.zjl.ioc;public class Car implements Driveable {@Overridepublic void drive() {System.out.println("小汽车被开着跑了");}}4、如果一个人,名叫张三,准备开着小汽车走了,我们很容易想到实现代码为
package com.zjl.ioc;public class Test {public static void main(String[] args) {Person person=new Person();person.setName("张三");person.setDriveable(new Car());person.drive();}
}

5、运行结果

张三准备开车
小汽车被开着跑了

  很好,很强大,我们可以看到张三开着小汽车就跑掉了。

  到这里本来就改结束了,不过我们实际开发中的程序并不会如此简单,一个简单的功能,我们需要引入数据库的dateSource,日志记录,交易检查等各种各样的属性,如果都等到具体使用的时候再一个个进行初始化,赋值,这将是一个非常大的工作量。

  那么spring ioc就是将一个类的所有属性在容器中进行初始化后,帮助我们完成所有的赋值操作。我们只需要获得初始化好的实例,就可以使用它所有的方法。

二、使用spring ioc进行改造

1、我们使用spring的xml配置,配置bean的信息

    <bean id="person" class="com.zjl.ioc.Person"><property name="name" value="zhangsan" />  <property name="driveable" ref="car" /></bean>  <bean id="car" class="com.zjl.ioc.Car"></bean> 

2、再次编写测试

public class Test {public static void main(String[] args) {ApplicationContext context=new FileSystemXmlApplicationContext("ioctest.xml");Person person=(Person) context.getBean("person");person.drive();}
}

这里我们可以看到,spring主要做了几件事情:

  1、从配置文件中读取了实例所有的配置,使得应用程序完全不需要关心bean有哪些属性,这个配置文件可以是xml或者properties,也可以是通过类的注解方式

  2、帮我们将所有需要用到的bean从容器中获得,bean在容器中的存储方式和实例化过程对客户隐藏

  3、如果一个bean需要在多个类里使用我们仅仅需要每次使用getBean就可以直接获取,不需要反复手工初始化

  4、从日后的学习中我们还可以看到,ioc容器额外做了许多通用的功能,如类的延迟加载,默认执行方法,动态代理,属性继承,单例模式等等许多好用的功能。

三、简单模拟

  1、分析

  从上边的spring实例,我们可以看到,ioc的加载和初始化过程需要依赖于配置文件,配置文件将每一个类定义为一个bean标签,标签内分为两部分:通用部分和个性化部分

  通用部分主要是:bean的id,class,根据spring配置文件,我们得知还有parent,scope,init-lazy,init-method等许多方法

  个性化部分:每个类的个性化部分都不同,但可以归类为基础类型,引用其他bean,以及一些集合类型-数组,list,set,map等,我们的目前bean比较简单,主要包括一个基础类型,一个引用类型。

  所以我们需要做的事情首先是需要建立一个对象,将所有的配置文件进行解析,进行保存,对于通用属性,作为对象的直接属性,个性化部分使用map进行存储。我们参考spring的命名:

package com.zjl.ioc;import java.util.HashMap;
import java.util.Map;public class BeanDefinition {public String id;public String className;public Map<String,Object> pv =new HashMap<String, Object>();
}

2、定义一个配置解析的容器

  我们定义一个beanFactory来进行参数初始化和实例生成,在BeanFactory中定义一个容器,保存所有的bean基本配置信息,为了便于查找,定义为map

public class BeanFactory {Map<String,BeanDefinition> beanDefinitions=new HashMap<String,BeanDefinition>();public BeanFactory(){init();}}

3、解析配置

  有了一个容器后,我们需要将所有的bean的基本参数进行保存,如前文分析中,这些内容可以来自于xml或者properties中,本例子中为了简便,我直接使用硬编码写入

public void init(){//定义personBeanDefinition personDefinition=new BeanDefinition();personDefinition.id="person";personDefinition.className="com.zjl.ioc.Person";personDefinition.pv.put("name", "zhangsan");personDefinition.pv.put("driveable", "car");beanDefinitions.put(personDefinition.id,personDefinition);//定义carBeanDefinition driveableDefinition=new BeanDefinition();driveableDefinition.id="car";driveableDefinition.className="com.zjl.ioc.Car";beanDefinitions.put(driveableDefinition.id,driveableDefinition);}

实际中可能是这样的: 

    <bean id="person" class="com.zjl.ioc.Person"><property name="name" value="zhangsan" />  <property name="driveable" ref="car" /></bean>  <bean id="car" class="com.zjl.ioc.Car"></bean> 

  也可能是这样的:

person.class=con.zjl.ioc.Person
person.pv.name=zhangsan
person.pv.driveable=carcar.class=com.zjl.ioc.Car

4、实例化bean,提供接口

  此处操作主要有两步:

  a、根据已经有的className,将类进行实例化

  b、将配置文件的属性赋值实例化的对象

public Object getBean(String beanName){Object result = null;if(beanDefinitions.get(beanName)!=null){BeanDefinition beanDefinition=beanDefinitions.get(beanName);String className=beanDefinition.className;try {result=Class.forName(className).newInstance();setPV(result,beanDefinition);} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchFieldException e) {// TODO Auto-generated catch blocke.printStackTrace();}return result;}return result;

5、属性赋值

  遍历pv,一个个进行赋值,如果pv中的value不是基础类型,那么判断是否为其他bean,并实例化引用的对象,此处写的比较简单,仅能处理目前的实例,实际中需要判断各种类型,包括基础类型,数组,容器和对象等等。

private void setPV(Object object, BeanDefinition beanDefinition) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {Map<String, Object> map=beanDefinition.pv;for(String key:map.keySet()){Field field=object.getClass().getDeclaredField(key);Object value=null;//判断如果不是基础类型,那么应该是需要注入其他beanif(field.getType().getName()!="java.lang.String"){value=getBean(map.get(key).toString());}else {value=map.get(key);}field.setAccessible(true);field.set(object, value);
//            System.out.println(field.getType());}

6、修改测试

public class Test {public static void main(String[] args) {BeanFactory beanFactory=new BeanFactory();Person person=(Person) beanFactory.getBean("person");person.drive();}}

四、总结

  到此为止,我们简单模拟了一遍spring的ioc处理过程,主要涉及到的知识包括:配置文件解析,反射等知识。

    但是仍有许多改进的地方,如果对属性注入的改进,对bean的判断,如果是单例我们需要另外一个容器保存已经初始化好的bean等一系列内容,这个都将在我学习源码过程中再仔细体会。

转自:https://www.cnblogs.com/jyyzzjl/p/5420887.html

[spring源码学习]一、IOC简介相关推荐

  1. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  2. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析--核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring 源码 ioc 编程 bean 更多 个人分类: Java https:// ...

  3. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  4. Spring源码学习的初步体会

    Spring源码学习的初步体会: 深入学习和巩固java的基础知识,其中的java知识范围全部,可以边研究源码边巩固复习基础知识 体会其中用到的设计思想:其中包含的设计原则和设计模式. 加深对spri ...

  5. spring源码学习之整合Mybatis原理分析

    本文主要解析spring是如何与mybatis进行整合,整合的过程中需要哪些组件的支持.以前面提到过的配置例子<spring源码学习之aop事物标签解析> 整合的过程中需要使用以下这个依赖 ...

  6. spring源码深度解析— IOC 之 默认标签解析(下)

    默认标签中的自定义标签解析 注册解析的BeanDefinition 通过beanName注册BeanDefinition 通过别名注册BeanDefinition alias标签的解析 import标 ...

  7. 【Spring源码学习】Spring Bean的销毁

    [Spring源码学习]Spring Bean的销毁 一.注册bean销毁的类 1.registerDisposableBeanIfNecessary() 2.DisposableBeanAdapte ...

  8. Spring源码学习(四) | @Configuration的cglib动态代理

    文章目录 前言 例子 @Configuration :full or lite 设置 full or lite Cglib生成代理类AppConfig Where is it generated Ho ...

  9. 结合Spring源码学习单例设计模式

    之前我学习了 Spring Ioc,明白了 Spring IoC 容器是一个管理Bean的容器,在Spring的定义中,它要求所有的IoC容器都需要实现接口 BeanFactory ,它是一个顶级容器 ...

  10. spring源码 — 一、IoC容器初始化

    IoC容器初始化 注意:本次的spring源码是基于3.1.1.release版本 容器:具有获取Bean功能--这是最基本功能,也是BeanFactory接口定义的主要行为,在添加了对于资源的支持之 ...

最新文章

  1. WINCE 自绘位图按钮
  2. (pwn) C语言 write函数且使用write函数泄露 libc版本
  3. 性能优化18招提速宝典
  4. 简单的ViewPager了解Scroller类
  5. pycharm 2020 版取消鼠标悬停显示说明文档的方法
  6. PHP简单方法判断文件是否是图片 PHP best way to check if file is an image
  7. TinyFrame开篇:基于CodeFirst的ORM
  8. 手机存储不足怎么办?用好这份清理指南你的手机还能再战三年
  9. 【java】java JUC 同步器框架 AQS AbstractQueuedSynchronizer源码图文分析
  10. Python的matplotlib库画图不能显示中文问题解决
  11. CQOI2015 解题报告
  12. c++小游戏代码(5个) 免费
  13. 50 道网络面试题及答案
  14. 【渝粤教育】21秋期末考试中国近现代史纲要(A)10881k1
  15. uniapp上班考勤打卡情况日历展示
  16. BRD、MRD、PRD
  17. SAP那些事-理论篇-1- SAP初次亲密接触
  18. 【菠萝狗四足机器人】二次开发教程--第一章 【简介与开发环境搭建】
  19. 为什么我们求职 找工作 一定要写好简历?
  20. SD NAND flash使用说明

热门文章

  1. ROS中launch文件和参数设置
  2. 如何在Excel中少犯二(I)
  3. java 俄罗斯方块原理,俄罗斯方块设计原理
  4. 关于python通过pyautocad操作cad的2021-06-10
  5. s3c2440芯片累加汇编语言,S3C2440—3.用点亮LED来熟悉裸机开发的详细流程
  6. Java读取ID卡卡号源码
  7. 用python实现人脸识别毕设_用Python实现一个简单的人脸识别,原来我和这个明星如此相似...
  8. 猿辅导揭秘听课小窍门,掌握这些技巧让你的学习事半功倍
  9. office2016激活后仍然出现输入激活码
  10. 人工智能、大数据和云计算之间,它们之间主要有什么关系?