[spring源码学习]一、IOC简介
一、程序实例
假设一个简单地实例,我们有一个人,人可能有姓名,年龄等属性,每天上下班的时候需要坐车,他可能做小轿车,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简介相关推荐
- spring源码学习之路---深入AOP(终)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...
- 转 Spring源码剖析——核心IOC容器原理
Spring源码剖析--核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring 源码 ioc 编程 bean 更多 个人分类: Java https:// ...
- 【spring源码分析】IOC容器初始化(二)
前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...
- Spring源码学习的初步体会
Spring源码学习的初步体会: 深入学习和巩固java的基础知识,其中的java知识范围全部,可以边研究源码边巩固复习基础知识 体会其中用到的设计思想:其中包含的设计原则和设计模式. 加深对spri ...
- spring源码学习之整合Mybatis原理分析
本文主要解析spring是如何与mybatis进行整合,整合的过程中需要哪些组件的支持.以前面提到过的配置例子<spring源码学习之aop事物标签解析> 整合的过程中需要使用以下这个依赖 ...
- spring源码深度解析— IOC 之 默认标签解析(下)
默认标签中的自定义标签解析 注册解析的BeanDefinition 通过beanName注册BeanDefinition 通过别名注册BeanDefinition alias标签的解析 import标 ...
- 【Spring源码学习】Spring Bean的销毁
[Spring源码学习]Spring Bean的销毁 一.注册bean销毁的类 1.registerDisposableBeanIfNecessary() 2.DisposableBeanAdapte ...
- Spring源码学习(四) | @Configuration的cglib动态代理
文章目录 前言 例子 @Configuration :full or lite 设置 full or lite Cglib生成代理类AppConfig Where is it generated Ho ...
- 结合Spring源码学习单例设计模式
之前我学习了 Spring Ioc,明白了 Spring IoC 容器是一个管理Bean的容器,在Spring的定义中,它要求所有的IoC容器都需要实现接口 BeanFactory ,它是一个顶级容器 ...
- spring源码 — 一、IoC容器初始化
IoC容器初始化 注意:本次的spring源码是基于3.1.1.release版本 容器:具有获取Bean功能--这是最基本功能,也是BeanFactory接口定义的主要行为,在添加了对于资源的支持之 ...
最新文章
- WINCE 自绘位图按钮
- (pwn) C语言 write函数且使用write函数泄露 libc版本
- 性能优化18招提速宝典
- 简单的ViewPager了解Scroller类
- pycharm 2020 版取消鼠标悬停显示说明文档的方法
- PHP简单方法判断文件是否是图片 PHP best way to check if file is an image
- TinyFrame开篇:基于CodeFirst的ORM
- 手机存储不足怎么办?用好这份清理指南你的手机还能再战三年
- 【java】java JUC 同步器框架 AQS AbstractQueuedSynchronizer源码图文分析
- Python的matplotlib库画图不能显示中文问题解决
- CQOI2015 解题报告
- c++小游戏代码(5个) 免费
- 50 道网络面试题及答案
- 【渝粤教育】21秋期末考试中国近现代史纲要(A)10881k1
- uniapp上班考勤打卡情况日历展示
- BRD、MRD、PRD
- SAP那些事-理论篇-1- SAP初次亲密接触
- 【菠萝狗四足机器人】二次开发教程--第一章 【简介与开发环境搭建】
- 为什么我们求职 找工作 一定要写好简历?
- SD NAND flash使用说明
热门文章
- ROS中launch文件和参数设置
- 如何在Excel中少犯二(I)
- java 俄罗斯方块原理,俄罗斯方块设计原理
- 关于python通过pyautocad操作cad的2021-06-10
- s3c2440芯片累加汇编语言,S3C2440—3.用点亮LED来熟悉裸机开发的详细流程
- Java读取ID卡卡号源码
- 用python实现人脸识别毕设_用Python实现一个简单的人脸识别,原来我和这个明星如此相似...
- 猿辅导揭秘听课小窍门,掌握这些技巧让你的学习事半功倍
- office2016激活后仍然出现输入激活码
- 人工智能、大数据和云计算之间,它们之间主要有什么关系?