一、程序实例

  假设一个简单地实例,我们有一个人,人可能有姓名,年龄等属性,每天上下班的时候需要坐车,他可能做小轿车,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 {

    @Override
public 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(){
//定义person
BeanDefinition 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);
//定义car
BeanDefinition 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=car car.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 block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.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;
//判断如果不是基础类型,那么应该是需要注入其他bean
if(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等一系列内容,这个都将在我学习源码过程中再仔细体会。

[spring源码学习]一、IOC简介的更多相关文章

  1. Spring源码学习之IOC容器实现原理(一)-DefaultListableBeanFactory

    从这个继承体系结构图来看,我们可以发现DefaultListableBeanFactory是第一个非抽象类,非接口类.实际IOC容器.所以这篇博客以DefaultListableBeanFactory ...

  2. Spring源码学习之IOC实现原理(二)-ApplicationContext

    一.Spring核心组件结构 总的来说Spring共有三个核心组件,分别为Core,Context,Bean.三大核心组件的协同工作主要表现在 :Bean是包装我们应用程序自定义对象Object的,O ...

  3. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

  4. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

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

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

  6. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

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

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

  8. Spring 源码学习——Aop

    Spring 源码学习--Aop 什么是 AOP 以下是百度百科的解释:AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程通过预编译的方式和运行期动态代理实 ...

  9. Spring 源码学习 04:初始化容器与 DefaultListableBeanFactory

    前言 在前一篇文章:创建 IoC 容器的几种方式中,介绍了四种方式,这里以 AnnotationConfigApplicationContext 为例,跟进代码,看看 IoC 的启动流程. 入口 从 ...

  10. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

随机推荐

  1. Werewolf流程分析

    werewolf大致流程 首先是房主创建房间,创建成功以后房主开启web socket连接. 其他成员加入房间,加入房间后新成员和老成员的游戏玩家列表都会更新,然后新成员也要开启web socket连 ...

  2. linux 下向github上传代码

    上传代码: cd TPS/devices/M8 git init                      #//初始化 git add .                    #如果是.表示上传全 ...

  3. HDU 2204Eddy's爱好(容斥原理)

    Eddy's爱好 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Sta ...

  4. mysql 查询当天的数据库

    时间存储格式是时间戳 SELECT *  FROM 表名  WHERE 时间字段 BETWEEN UNIX_TIMESTAMP( CURDATE( ) )  AND UNIX_TIMESTAMP( N ...

  5. IP地址,子网掩码、默认网关,DNS服务器是什么意思?

    (一)  问题解析001.   问:  IP地址,子网掩码,默认网关,DNS服务器,有什么区别呀?我知道没有IP地址就不能上网,我也知道没设DNS就不能上外网,可它们都有什么功能,有什么区别呢?还有真 ...

  6. 大熊君学习html5系列之------XHR2(XMLHttpRequest Level 2)

    一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会" ...

  7. Solr的主界面加登录权限

    如题:效果如下图zu 只需两步: 1.tomcat-users.xml   下添加 <user username="admin" password="new-pas ...

  8. UIScrollView的代理(delegate)

    很多时候,我们想在UIScrollView正在滚动 或 滚动到某个位置 或者 停止滚动 时做一些特定的操作 要想完成上述功能,前提条件就是能够监听到UIScrollView的整个滚动过程 当UIScr ...

  9. [Hadoop] Hadoop学习笔记之Hadoop基础

    1 Hadoop是什么? Google公司发表了两篇论文:一篇论文是“The Google File System”,介绍如何实现分布式地存储海量数据:另一篇论文是“Mapreduce:Simplif ...

  10. shell--2.shell数组

    shell 数组 (1)定义数组 shell中,用括号表示数组,数组元素用空格分开,定义数组的一般形式 arrt_name=(val1 val2 val3) 或者 arry_name=(val1 va ...