重新学习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把内容按 ...
随机推荐
- 系统管理命令之w
区别于who命令,w命令不仅可以看到登录服务器的用户信息,而且可以看到这些用户做了什么 1.查看该命令的帮助信息. # w --help 2.查看该命令的版本信息. # w --version 3 ...
- java之类适配器
类适配器 所谓类适配器,指的是适配器Adapter继承我们的被适配者Adaptee,并实现目标接口Target.由于Java中是单继承,所以这个适配器仅仅只能服务于所继承的被适配者Adaptee.代码 ...
- python: 随机选择
想从一个序列中随机抽取若干元素,或者想生成几个随机数. random 模块有大量的函数用来产生随机数和随机选择元素.比如,要想从一个序列中随机的抽取一个元素,可以使用random.choice() : ...
- Java之网络爬虫WebCollector2.1.2+selenium2.44+phantomjs2.1.1
Java之网络爬虫WebCollector2.1.2+selenium2.44+phantomjs2.1.1 一.简介 版本匹配: WebCollector2.12 + selenium2.44.0 ...
- 搞定PHP面试 - 正则表达式知识点整理
一.简介 1. 什么是正则表达式 正则表达式(Regular Expression)就是用某种模式去匹配一类字符串的一种公式.正则表达式使用单个字符串来描述.匹配一系列匹配某个句法规则的字符串.正则表 ...
- 20155201 2016-2017-2 《Java程序设计》第九周学习总结
20155201 2016-2017-2 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC全名JavaDataBaseConnecticity,是Jav ...
- Hadoop运维手记
1.处理hadoop的namenode宕机 处理措施:进入hadoop的bin目录,重启namenode服务 操作命令:cd path/to/hadoop/bin ./hadoop-daemon.sh ...
- (探讨贴)POJ 1463 树形DP解法的不正确性
POJ1463是一个典型的树状DP题. 通常解法如下代码所示: using namespace std; ; ]; int pre[maxn]; int childcnt[maxn]; int n; ...
- 51Nod 1686 第K大区间(离散化+尺取法)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1686 题意: 思路: 第K大值,所以可以考虑二分法,然后用尺取法去扫描, ...
- Abstract Factory(抽象工厂)
意图: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 适用性: 一个系统要独立于它的产品的创建.组合和表示时. 一个系统要由多个产品系列中的一个来配置时. 当你要强调一系列相关 ...