Spring容器IOC解析
Spring有两大核心特性 IOC和AOP,今天我们来聊的是IOC。相信很多同学每天都在使用Spring的IOC特性,但对其原理及实现理解比较模糊,那么今天就借助Spring容器实现原理,简单说说IOC。说到IOC 就涉及到两个概念控制反转(Inversion of Control )、依赖注入(Dependency Injection) 。
首先来看什么是控制反转
在介绍控制反转之前呢我们看一段最早的代码Public class PersonServiceBean{ Private PersonDaoBean personDao = new PersonDaoBean(); Public void save(Personperson){ personDao.insert(person); } }
PersonDaoBean 是在应用内部创建及维护的 。所谓控制反转就是应用本身不负责依赖对象的创建及维护 ,依赖对象的创建及维护是由外部容器负责的 。这样控制反转权就由应用转到了外部容器,控制权的转移就是所谓反转。
用Spring的写法:把依赖对象交给外部容器去负责Public class PersonServiceBean{ Private PersonDaoBean personDao; //把容器创建好的对象依赖注入进PersonServiceBean,通过构造方法或 set方法 Public PersonServiceBean(PersonDaoBean personDao){ this.personDao = personDao; } 或 Public void setPersonDao(PersonDaoBean personDao){ this.personDao = personDao; } Public void save(Personperson){ personDao.insert(person); } }
其次来看什么是依赖注入
所谓依赖注入:就是在运行期间 ,由外部容器动态的将依赖对象注入到组件中。
简单的说,Spring就是通过工厂+反射将我们的bean放到它的容器中,当我们想用某个bean的时候,只需要调用 getBean("beanId")方法。
依赖注入的方式:
第一.构造器注入;
第二.set方法注入;
第三.使用Field注入(用于注解方式)
然后我们写一段简单的模拟Spring的代码来实现IOC容器
思路:Spring容器的原理实现主要依赖于反射。过程其实就是通过解析xml文件,获取到用户配置的bean,然后通过反射将这些bean进行存储(放到集合中),然后对我提供一个getBean方法,以便我们获取到这些bean。下面是一段简单的模拟代码:package com.spring.factory; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; public class ClassPathXmlApplicationContext implements BeanFactory { //容器的核心,用来存放注入的Bean private Map container = new HashMap(); //解析xml文件,通过反射将配置的bean放到container中 public ClassPathXmlApplicationContext(String fileName) throws Exception { SAXBuilder sb = new SAXBuilder(); Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream(fileName)); Element root = doc.getRootElement(); List list = XPath.selectNodes(root, "/beans/bean"); //扫描配置文件中的bean for (int i = 0; i < list.size(); i++) { Element bean = (Element) list.get(i); String id = bean.getAttributeValue("id"); String clazz = bean.getAttributeValue("class"); // 反射 Object o = Class.forName(clazz).newInstance(); container.put(id, o); } } @Override public Object getBean(String id) { return container.get(id); } }
说明:首先声明一个存放bean的Map,然后通过jdom解析配置文件,循环遍历所有的节点,并通过反射将它们放到我们之前声明的Map中.然后提供一个getBean的方法,让我们可以通过beanId来获取到我们想要的bean。
下面是一个简单的xml配置文件:<?xml version="1.0" encoding="UTF-8"?>
客户端通过调用前面的ClassPathXmlApplicationContext,来加载上面的配置文件,然后就可以通过Id来获得我们需要的bean了:package com.spring.factory; public class Test { public static void main(String[] args) throws Exception { //加载配置文件 BeanFactory f = new ClassPathXmlApplicationContext("applicationContext.xml"); //英格兰 Object oe = f.getBean("E"); Team e = (Team)oe; e.say(); //西班牙 Object os = f.getBean("S"); Team s = (Team)os; s.say(); //葡萄牙 Object op = f.getBean("P"); Team p = (Team)op; p.say(); } }
输出结果:England:我们是欧洲的中国队,不在乎这次小组没出线... Spain :我们是两届欧洲杯冠军、一届世界杯冠军! Portugal:我们的C罗一个顶十个!
其它代码://工厂接口 package com.spring.factory; public interface BeanFactory { Object getBean(String id); } //Team接口 package com.spring.factory; public interface Team { void say(); } //英格兰 package com.spring.factory; public class England implements Team{ public void say() { System.out.println("England:我们是欧洲的中国队,不在乎这次小组没出线..."); } } //西班牙 package com.spring.factory; public class Spain implements Team{ @Override public void say() { System.out.println("Spain:我们是两届欧洲杯冠军、一届世界杯冠军!"); } } //葡萄牙 package com.spring.factory; public class Portugal implements Team { @Override public void say() { System.out.println("Portugal:我们的C罗一个顶十个!"); } }
以上内容是对Spring的一个简单模拟,当然Spring远比这个要复杂的多,也强大的多,而且获取bean的方式也不止通过工厂这一种。这里只是做一个粗略的Demo说说对容器的简单理解,向Spring致敬。
扩展,那么如果有 property属性的bean该如何初始化呢?(依赖注入)
如xml配置方式: bean有 property属性, 包含name和ref。
这里提供思路,感兴趣的同学可以自行实现,也可参看spring的源码。
思路:
1. 获取Bean的set方法 setA --- 反射
2. 获取Bean的声明的属性.equals(propertyDefine.getName())
3. 获取Bean的ref 通过ref作为Key从Map中获取到实例对象
4. setA.invoke(Bean,实例对象) --- 反射
整个原理大致分三步:
1.读取xml文件
2.实例化bean 保存到map中
3.为有property 的Bean注入Bean0对象
说了这么多,那么IOC有什么好处呢
降低组件的耦合,使各层解耦。bean对象交于容器管理。
小结
相信读完此篇会对Spring IOC的概念和实现原理更加清晰。
控制反转:就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器Spring负责。
依赖注入:由外部容器Spring动态的将依赖对象注入到组件中。
实现原理:JAVA反射机制。
逛市场更了解当地人的生活吃得还便宜非游客视角带你看南浔我是一个非常喜欢旅游的人,去到一个地方总是要了解当地人的生活习俗,风土人情,饮食习惯,我觉得这样才算是真正地去过一个地方。每去到一个地方,只要条件允许,我都会去逛逛本地的市场,这是
万物互联的世界,是怎样的?一物联网的世界长什么样子秋高气爽的某天清晨,第一缕阳光暖暖地透过窗子,映入窗帘并唤醒了它,窗帘又悄悄地唤醒了床头的智能音箱。缓缓地,音箱中响起了轻柔舒缓的声音,轻轻地唤醒了床上的你
东京奥运会的神评论,笑死我了1。奥运会放中国国歌的时候,很多外国人不愿意起立,但他们不知道,中国国歌的第一句是起来,不愿做奴隶的人们。2。看了几天奥运会,奥利匹克精神没看到,抗日精神倒是给我唤醒了!3。东京奥
鸿星尔克的回应,才是教科书级别大家有没有发现,鸿星尔克在这次捐款事件所有的表现都非常得体?他们在低谷期有大爱,在高潮时也有底线,没有因为网友的疯狂追捧,就表现得洋洋得意,让人反感,让我们再好好品一下,鸿星尔克的
自改燃气阀门现在新房安装燃气表已经不需要个人在花初装费了,以前我记得申请挂表要花个三千多才行,现在只要去市政网点填个表就可以,真是越来越方便申请两天后就有燃气公司的工作人员来挂表,我本来以为要
创业为什么会失败,真正的原因找到了多数初创企业大都以失败收场,超过三分之二的初创公司从未向投资者有过正向的回报,从浩浩荡荡的创业大军中,成功率为什么会如此的低。在中国创业为什么会这么难?是市场环境不行还是人为因素?
将temi机器人编程融入常规课程培养运算思维能力创新科技是二十一世纪发展的趋势,作为孕育人才的地方,学校亦需要与时并进,为学生装备科技知识和技能,助他们在未来社会立足。香港的天主教慈幼会伍少梅中学深深明白这一点,特别为学生全新打
LuminT2,Lumin最热卖的超级机器其实由我来评测LuminT2或许不是最客观的选择,毕竟我本身就是LuminT2的用户,目前使用八个月了,Runin时间超过300个小时。但换个角度想,由我来评测,或许您可以最直观地
自然声DAC1做一台可换芯片,无瓶颈的实用解码机器几个月前,自己给自己的NS16配套了一台LM3886功放,电路布局合理,整体用料十分讲究到位。同时支持3路输入,功率40瓦8欧。售价却十分的便宜,仅售728元,搭配自己的NS16音
内啥精选会撒娇卖萌的机器狗视频加载中如果机器有了那么点人情味,是好事还是坏事?这可能是BostonDynamics在被母上Google贴上待售标签后的一个转型力作。转型前,他们家的机器人都是这样的这个平衡力
从蔚来NOP事故看辅助自动驾驶OTA的紧箍咒这是一场安全效率与自由的博弈。文东篱8月14日,美一好公司发布了一则讣告,该公司创始人林文钦驾驶蔚来ES8汽车启用自动驾驶功能(NOP领航状态)后,在沈海高速涵江段发生交通事故,于