重新学习Spring之核心IOC容器的底层原理
一:IOC容器的定义
控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找。依赖注入应用比较广泛。
二:Ioc容器相关含义
许多强大的功能都是由两个或是更多的类通过彼此的合作来实现业务逻辑,这使得每个对象和其他的对象产生依赖或者关联。(也就是对象持有其他对象的引用)。如果这个获取过程要靠自身实现,那么如你所见,这将导致代码高度耦合并且难以测试。
工厂模式只是一定程度上降低了这种代码的耦合性,
IoC模式可以彻底解决这种耦合,它把耦合从代码中移出去,放到统一的XML 文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口实现注入到需要它的类中。这可能就是“依赖注入”说法的来源了。
优点:因为把对象生成放在了XML里定义,所以当我们需要换一个实现子类将会变成很简单,只要修改XML就可以了,这样我们甚至可以实现对象的热插拨(象USB)
缺点:1.创建对象的过程变得复杂,对于不习惯这种方式的人,会觉得有些别扭和不直观。
2.对象生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高
三:IOC容器实现原理
----->ioc容器实现原理项目图
----->beans.xml对应的java类
【1】一个xml节点在可以映射成一个java类。
beans根节点对应的java类
package org.shangxiaofei.bjsxt.shang;
import java.util.ArrayList;
import java.util.List; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Beans.xml中相当于根节点对应的java对象
* @ClassName: Bean
* @Description: TODO(这里用一句话描述这个类的作用)
* @author 尚晓飞
* @date 2014-8-27 下午4:55:19
*
*/
@XmlRootElement
public class Beans {
//根节点下多有bean对象的集合
private List<Bean> list=new ArrayList<Bean>(); public Beans() {
super();
} //name定义的是beans.xml中节点的名字
@XmlElement(name="bean")
public List<Bean> getList() {
return list;
} public void setList(List<Bean> list) {
this.list = list;
} }
bean节点对应的java类
package org.shangxiaofei.bjsxt.shang; import java.util.ArrayList;
import java.util.List; import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement; /**
* 相当于beans.xml中<beans></beans>根节点下每一个<bean id="" className=""></bean>节点对应的java对象
* @ClassName: Bean
* @Description: TODO(这里用一句话描述这个类的作用)
* @author 尚晓飞
* @date 2014-8-27 下午5:00:58
*
*/
public class Bean {
//<bean></bean>节点中的属性
private String id; //<bean></bean>节点中的属性
private String className; //<bean></bean>节点下的<property></property>节点对应java对象的集合
private List<Property> list=new ArrayList<Property>();
public Bean() {
super();
} //<bean></bean>节点中的属性
@XmlAttribute
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
} //<bean></bean>节点中的属性
@XmlAttribute
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
} //<bean></bean>节点下的<property></property>节点集合
@XmlElement(name="property")
public List<Property> getList() {
return list;
}
public void setList(List<Property> list) {
this.list = list;
} }
property节点对应的java类
package org.shangxiaofei.bjsxt.shang; import javax.xml.bind.annotation.XmlAttribute; /**
* <beans>节点下<bean>节点中<property>节点在java中对应的对象
* @ClassName: Property
* @Description: TODO(这里用一句话描述这个类的作用)
* @author 尚晓飞
* @date 2014-8-27 下午5:11:43
*
*/
public class Property {
//<property>节点中的属性
private String name; //<property>节点中的属性
private String require;
public Property() {
super();
} //<property>节点的属性
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} //<property>节点的属性
@XmlAttribute
public String getRequire() {
return require;
}
public void setRequire(String require) {
this.require = require;
} }
【2】beans.xml的配置内容
<?xml version="1.0" encoding="UTF-8"?>
<beans> <bean id="MyAction" className="com.bjsxt.shang.action.MyAction">
<property name="studentService" require="StudentService"></property>
<property name="teacherService" require="TeacherService"></property>
</bean> <bean id="StudentService" className="com.bjsxt.shang.service.impl.StudentServiceImp"></bean>
<bean id="TeacherService" className="com.bjsxt.shang.service.impl.TeacherServiceImp"></bean> </beans>
【3】BeansFactory工厂类解析beans.xml来实现对象的生成和关系的建立
BeansFactory工厂类
package com.bjsxt.shang.util; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller; import org.shangxiaofei.bjsxt.shang.Bean;
import org.shangxiaofei.bjsxt.shang.Beans;
import org.shangxiaofei.bjsxt.shang.Property; import com.bjsxt.shang.action.MyAction;
/**
* 此类是解析bens.xml文件,在解析过程中生成项目中配置好的类的对象,并根据配置的关系,建立项目中类与类之间的关联关系
*
* 面向接口编程,就是降低了代码的耦合度。
*
* 我们只要修改配置中接口对应的实现类,我们就可以改变功能。
* @ClassName: BeansFactory
* @Description: TODO(这里用一句话描述这个类的作用)
* @author 尚晓飞
* @date 2014-8-28 上午11:12:25
*
*/
public class BeansFactory {
//创建一个容器,用来存放xml解析过来的所有对象
private Map<String, Object> contaniner=new HashMap<String, Object>(); //利用空构造器。来解析xml,并将解析过来的对象存放入容器中
public BeansFactory() throws JAXBException, ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException{
//解析xml jaxb
JAXBContext context=JAXBContext.newInstance(Beans.class); //context.createMarshaller() 编码 java-->XmlAccessOrder
//context.createUnmarshaller() 解码 xml-->java Unmarshaller unmarshaller=context.createUnmarshaller(); Beans beans=(Beans) unmarshaller.unmarshal(BeansFactory.class.getClassLoader().getResourceAsStream("beans.xml")); //获取bens.xml中所有bean节点转换成的java对象
List<Bean> listBean=beans.getList(); //将beans.xml中所有配置好的程序需要用的java对象生成,并将生成的对象存放入容器中,对应的key-value 为id-object
for (Iterator iterator = listBean.iterator(); iterator.hasNext();) {
Bean bean = (Bean) iterator.next(); //获取bean对象中的属性值 配置的id和id对应的类名
String id=bean.getId();
String className=bean.getClassName(); //利用反射生成配置类名的对象
Class cls=Class.forName(className);
Object obj=cls.newInstance(); //将每个类的对象存放到容器中
this.contaniner.put(id, obj);
} //根据bean节点的下的配置,将java的对象与对象之间的关系建立起来,依赖注入set注入
for (Iterator iterator = listBean.iterator(); iterator.hasNext();) {
Bean bean = (Bean) iterator.next(); //获取当前bean节点下的property节点的集合
List<Property> listProperty=bean.getList();
//迭代当前bean下的property节点集合
for (Iterator iterator2 = listProperty.iterator(); iterator2.hasNext();) {
Property property = (Property) iterator2.next();
//获取bean对象需要进行关联的属性名和对象引用的id
String name=property.getName();
String require=property.getRequire(); //获取当前的bean对象
Object obj1=contaniner.get(bean.getId());//当前宿主对象
Object obj2=contaniner.get(require);//当前从属对象 //拼接set方法的方法名
String methodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);
//获取set方法的参数类型
Field field=obj1.getClass().getDeclaredField(name);
//获取属性的类型
field.getType(); //获取set方法
Method method=obj1.getClass().getMethod(methodName, field.getType()); //执行set方法,将需要关联的对象进行set注入 执行obj对象的set放入,注入obj2
method.invoke(obj1, obj2); } } } public Map<String, Object> getContaniner() {
return contaniner;
} public void setContaniner(Map<String, Object> contaniner) {
this.contaniner = contaniner;
} //测试方法
public static void main(String[] args) throws SecurityException, IllegalArgumentException, JAXBException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { /**
* myAction类中引用了两个接口的引用。添加setget方法
*
* 两个接口各自有一个实现类。
*
*/
BeansFactory beansFactory=new BeansFactory();
Map<String, Object> contaninerMap=beansFactory.getContaniner();
MyAction myAction=(MyAction) contaninerMap.get("MyAction");
myAction.add(); //打印结果,是实现类中的方法中的打印语句:
//我需要添加一个学生在数据库
//我需要添加一个老师在数据库中
}
}
【4】MyAction类,此处省略了接口,和接口实现类的代码(在接口中定义一个方法,实现类实现,并在方法中打印一句话)
MyAction类
package com.bjsxt.shang.action; import com.bjsxt.shang.service.StudentService;
import com.bjsxt.shang.service.TeacherService; public class MyAction {
private StudentService studentService;
private TeacherService teacherService; /**
* 一个测试方法
* @Title: add
* @Description: TODO(这里用一句话描述这个方法的作用)
* @return
* @return String 返回类型
* @author 尚晓飞
* @date 2014-8-27 下午5:29:33
*/
public String add(){
studentService.addStudent();
teacherService.addTeacher();
return null;
} public StudentService getStudentService() {
return studentService;
} public void setStudentService(StudentService studentService) {
this.studentService = studentService;
} public TeacherService getTeacherService() {
return teacherService;
} public void setTeacherService(TeacherService teacherService) {
this.teacherService = teacherService;
} }
重新学习Spring之核心IOC容器的底层原理的更多相关文章
- IoC容器(底层原理)
IoC(概念和原理) 1,什么是IoC (1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理 (2)使用IoC目的:为了降低耦合度 (3)做入门案例就是IoC实现 2,IoC底层原 ...
- 转 Spring源码剖析——核心IOC容器原理
Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...
- 学习Spring5必知必会(3)~Spring的核心 IoC 和 DI
一.Spring的核心 IoC(基于XML) 1.IoC容器 (1)BeanFactory容器创建对象: //使用BeanFactory @Test void testBeanFactory() th ...
- Spring之一:IoC容器体系结构
温故而知心. Spring IoC概述 常说spring的控制反转(依赖反转),看看维基百科的解释: 如果合作对象的引用或依赖关系的管理要由具体对象来完成,会导致代码的高度耦合和可测试性降低,这对复杂 ...
- 比Spring简单的IoC容器
比Spring简单的IoC容器 Spring 虽然比起EJB轻量了许多,但是因为它需要兼容许多不同的类库,导致现在Spring还是相当的庞大的,动不动就上40MB的jar包, 而且想要理解Spring ...
- 使用Spring.NET的IoC容器
使用Spring.NET的IoC容器 0. 辅助类库 using System; using System.Collections.Generic; using System.Linq; using ...
- Spring.NET的IoC容器(The IoC container)——简介(Introduction)
简介 这个章节介绍了Spring Framework的控制反转(Inversion of Control ,IoC)的实现原理. Spring.Core 程序集是Spring.NET的 IoC 容器实 ...
- Spring框架中IoC(控制反转)的原理(转)
原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...
- git的核心命令使用和底层原理解析
文章目录: GIT体系概述 GIT 核心命令使用 GIT 底层原理 一.GIT体系概述 GIT 与 svn 主要区别: 存储方式不一样 使用方式不一样 管理模式不一样 1.存储方式区别 GIT把内容按 ...
随机推荐
- Core Java 4
p272~p273 1.除捕获异常外的另一种异常处理方式:将异常继续传递给方法调用者. 即:在方法首部添加throws说明符号,取代 try catch语句. 对于方法的调用者而言:要么处理异常,要么 ...
- MySQL事务之-2
在上一篇中我们提到了MySQL的事务特性,这一片主要讲述事务的实现. 事务的隔离性由锁来实现.原子性,一致性,持久性通过数据库的redo和undo log来实现. redo恢复提交事务修改页的操作,而 ...
- 20145311实验二 "Java面向对象程序设计"
20145311实验二 "Java面向对象程序设计" 程序设计过程 实验内容 使用单元测试.TDD的方式设计实现复数类 Complex 编写代码: 1.首先设计实现复数类 Comp ...
- HBase参数优化
zookeeper.session.timeout默认值:3分钟(180000ms)说明:RegionServer与Zookeeper间的连接超时时间.当超时时间到后,ReigonServer会被Zo ...
- POJ 1325 Machine Schedule(最小点覆盖)
http://poj.org/problem?id=1325 题意: 两种机器A和B.机器A具有n种工作模式,称为mode_0,mode_1,...,mode_n-1,同样机器B有m种工作模式mode ...
- mysql Alter 的问题
转自:https://blog.csdn.net/c_enhui/article/details/50903351 -- 设置或删除列的默认值.该操作会直接修改.frm文件而不涉及表数据. 此操作很快 ...
- 2016"百度之星" - 资格赛(Astar Round1) A 逆元
Problem A Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem ...
- vapply
尽管 sapply 非常方便和智能,但有时智能可能隐藏着风险.假如我们有一个数字列表:x <- list(c(1, 2), c(2, 3), c(1, 3))如果我们想得到一个向量,其中每个元素 ...
- Android中的代理模式
代理的概念:为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代.代理类负责请求的预处理.过滤.将请求分派给委托类处 ...
- [学习笔记]ST表
ST表 给定一个数列$a,O(nlogn)$预处理,$O(1)$查询数列在区间$[l,r]$的最值. 本文介绍求最大值. 实现 预处理 $st[i][j]$表示$max\{a_k\}(k\in[i,i ...