重新学习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类

 

 1 package org.shangxiaofei.bjsxt.shang;
 2 import java.util.ArrayList;
 3 import java.util.List;
 4
 5 import javax.xml.bind.annotation.XmlElement;
 6 import javax.xml.bind.annotation.XmlRootElement;
 7 /**
 8  * Beans.xml中相当于根节点对应的java对象
 9 * @ClassName: Bean
10 * @Description: TODO(这里用一句话描述这个类的作用)
11 * @author 尚晓飞
12 * @date 2014-8-27 下午4:55:19
13 *
14  */
15 @XmlRootElement
16 public class Beans {
17     //根节点下多有bean对象的集合
18     private List<Bean> list=new ArrayList<Bean>();
19
20     public Beans() {
21         super();
22     }
23
24     //name定义的是beans.xml中节点的名字
25     @XmlElement(name="bean")
26     public List<Bean> getList() {
27         return list;
28     }
29
30     public void setList(List<Bean> list) {
31         this.list = list;
32     }
33
34
35 }

View Code

 

bean节点对应的java类

 1 package org.shangxiaofei.bjsxt.shang;
 2
 3 import java.util.ArrayList;
 4 import java.util.List;
 5
 6 import javax.xml.bind.annotation.XmlAttribute;
 7 import javax.xml.bind.annotation.XmlElement;
 8
 9 /**
10  * 相当于beans.xml中<beans></beans>根节点下每一个<bean id="" className=""></bean>节点对应的java对象
11 * @ClassName: Bean
12 * @Description: TODO(这里用一句话描述这个类的作用)
13 * @author 尚晓飞
14 * @date 2014-8-27 下午5:00:58
15 *
16  */
17 public class Bean {
18     //<bean></bean>节点中的属性
19     private String id;
20
21
22     //<bean></bean>节点中的属性
23     private String className;
24
25
26     //<bean></bean>节点下的<property></property>节点对应java对象的集合
27     private List<Property> list=new ArrayList<Property>();
28     public Bean() {
29         super();
30     }
31
32     //<bean></bean>节点中的属性
33     @XmlAttribute
34     public String getId() {
35         return id;
36     }
37     public void setId(String id) {
38         this.id = id;
39     }
40
41     //<bean></bean>节点中的属性
42     @XmlAttribute
43     public String getClassName() {
44         return className;
45     }
46     public void setClassName(String className) {
47         this.className = className;
48     }
49
50     //<bean></bean>节点下的<property></property>节点集合
51     @XmlElement(name="property")
52     public List<Property> getList() {
53         return list;
54     }
55     public void setList(List<Property> list) {
56         this.list = list;
57     }
58
59
60 }

View Code

property节点对应的java类

 

 1 package org.shangxiaofei.bjsxt.shang;
 2
 3 import javax.xml.bind.annotation.XmlAttribute;
 4
 5 /**
 6  * <beans>节点下<bean>节点中<property>节点在java中对应的对象
 7 * @ClassName: Property
 8 * @Description: TODO(这里用一句话描述这个类的作用)
 9 * @author 尚晓飞
10 * @date 2014-8-27 下午5:11:43
11 *
12  */
13 public class Property {
14     //<property>节点中的属性
15     private String name;
16
17     //<property>节点中的属性
18     private String require;
19     public Property() {
20         super();
21     }
22
23     //<property>节点的属性
24     @XmlAttribute
25     public String getName() {
26         return name;
27     }
28     public void setName(String name) {
29         this.name = name;
30     }
31
32     //<property>节点的属性
33     @XmlAttribute
34     public String getRequire() {
35         return require;
36     }
37     public void setRequire(String require) {
38         this.require = require;
39     }
40
41
42 }

View Code

 

【2】beans.xml的配置内容

 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans>
 3
 4     <bean id="MyAction" className="com.bjsxt.shang.action.MyAction">
 5         <property name="studentService" require="StudentService"></property>
 6         <property name="teacherService" require="TeacherService"></property>
 7     </bean>
 8
 9     <bean id="StudentService" className="com.bjsxt.shang.service.impl.StudentServiceImp"></bean>
10     <bean id="TeacherService" className="com.bjsxt.shang.service.impl.TeacherServiceImp"></bean>
11
12 </beans>

View Code

 

【3】BeansFactory工厂类解析beans.xml来实现对象的生成和关系的建立

BeansFactory工厂类

  1 package com.bjsxt.shang.util;
  2
  3
  4 import java.lang.reflect.Field;
  5 import java.lang.reflect.InvocationTargetException;
  6 import java.lang.reflect.Method;
  7 import java.util.HashMap;
  8 import java.util.Iterator;
  9 import java.util.List;
 10 import java.util.Map;
 11
 12 import javax.xml.bind.JAXBContext;
 13 import javax.xml.bind.JAXBException;
 14 import javax.xml.bind.Unmarshaller;
 15
 16 import org.shangxiaofei.bjsxt.shang.Bean;
 17 import org.shangxiaofei.bjsxt.shang.Beans;
 18 import org.shangxiaofei.bjsxt.shang.Property;
 19
 20 import com.bjsxt.shang.action.MyAction;
 21 /**
 22  * 此类是解析bens.xml文件,在解析过程中生成项目中配置好的类的对象,并根据配置的关系,建立项目中类与类之间的关联关系
 23  *
 24  * 面向接口编程,就是降低了代码的耦合度。
 25  *
 26  * 我们只要修改配置中接口对应的实现类,我们就可以改变功能。
 27 * @ClassName: BeansFactory
 28 * @Description: TODO(这里用一句话描述这个类的作用)
 29 * @author 尚晓飞
 30 * @date 2014-8-28 上午11:12:25
 31 *
 32  */
 33 public class BeansFactory {
 34     //创建一个容器,用来存放xml解析过来的所有对象
 35     private Map<String, Object> contaniner=new HashMap<String, Object>();
 36
 37     //利用空构造器。来解析xml,并将解析过来的对象存放入容器中
 38     public BeansFactory() throws JAXBException, ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException{
 39         //解析xml jaxb
 40         JAXBContext context=JAXBContext.newInstance(Beans.class);
 41
 42         //context.createMarshaller() 编码  java-->XmlAccessOrder
 43         //context.createUnmarshaller() 解码 xml-->java
 44
 45         Unmarshaller unmarshaller=context.createUnmarshaller();
 46
 47         Beans beans=(Beans) unmarshaller.unmarshal(BeansFactory.class.getClassLoader().getResourceAsStream("beans.xml"));
 48
 49         //获取bens.xml中所有bean节点转换成的java对象
 50         List<Bean> listBean=beans.getList();
 51
 52         //将beans.xml中所有配置好的程序需要用的java对象生成,并将生成的对象存放入容器中,对应的key-value 为id-object
 53         for (Iterator iterator = listBean.iterator(); iterator.hasNext();) {
 54             Bean bean = (Bean) iterator.next();
 55
 56             //获取bean对象中的属性值   配置的id和id对应的类名
 57             String id=bean.getId();
 58             String className=bean.getClassName();
 59
 60             //利用反射生成配置类名的对象
 61             Class cls=Class.forName(className);
 62             Object obj=cls.newInstance();
 63
 64             //将每个类的对象存放到容器中
 65             this.contaniner.put(id, obj);
 66         }
 67
 68
 69         //根据bean节点的下的配置,将java的对象与对象之间的关系建立起来,依赖注入set注入
 70         for (Iterator iterator = listBean.iterator(); iterator.hasNext();) {
 71             Bean bean = (Bean) iterator.next();
 72
 73             //获取当前bean节点下的property节点的集合
 74             List<Property> listProperty=bean.getList();
 75             //迭代当前bean下的property节点集合
 76             for (Iterator iterator2 = listProperty.iterator(); iterator2.hasNext();) {
 77                 Property property = (Property) iterator2.next();
 78                 //获取bean对象需要进行关联的属性名和对象引用的id
 79                 String name=property.getName();
 80                 String require=property.getRequire();
 81
 82                 //获取当前的bean对象
 83                 Object obj1=contaniner.get(bean.getId());//当前宿主对象
 84                 Object obj2=contaniner.get(require);//当前从属对象
 85
 86                 //拼接set方法的方法名
 87                 String methodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);
 88                 //获取set方法的参数类型
 89                 Field field=obj1.getClass().getDeclaredField(name);
 90                 //获取属性的类型
 91                 field.getType();
 92
 93                 //获取set方法
 94                 Method method=obj1.getClass().getMethod(methodName, field.getType());
 95
 96                 //执行set方法,将需要关联的对象进行set注入 执行obj对象的set放入,注入obj2
 97                 method.invoke(obj1, obj2);
 98
 99
100
101             }
102
103         }
104
105     }
106
107
108     public Map<String, Object> getContaniner() {
109         return contaniner;
110     }
111
112     public void setContaniner(Map<String, Object> contaniner) {
113         this.contaniner = contaniner;
114     }
115
116
117
118
119     //测试方法
120     public static void main(String[] args) throws SecurityException, IllegalArgumentException, JAXBException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {
121
122         /**
123          * myAction类中引用了两个接口的引用。添加setget方法
124          *
125          * 两个接口各自有一个实现类。
126          *
127          */
128         BeansFactory beansFactory=new BeansFactory();
129         Map<String, Object> contaninerMap=beansFactory.getContaniner();
130         MyAction myAction=(MyAction) contaninerMap.get("MyAction");
131         myAction.add();
132
133
134         //打印结果,是实现类中的方法中的打印语句:
135         //我需要添加一个学生在数据库
136         //我需要添加一个老师在数据库中
137     }
138 }

View Code

【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;
    }

}

View Code

 

 

 

 

 

     

时间: 2024-09-24 12:46:36

重新学习Spring之核心IOC容器的底层原理的相关文章

Spring源码学习之:模拟实现BeanFactory,从而说明IOC容器的大致原理

spring的IOC容器能够帮我们自动new对象,对象交给spring管之后我们不用自己手动去new对象了.那么它的原理是什么呢?是怎么实现的呢?下面我来简单的模拟一下spring的机制,相信看完之后就会对spring的原理有一定的了解. spring使用BeanFactory来实例化.配置和管理对象,但是它只是一个接口,里面有一个getBean()方法.我们一般都不直接用BeanFactory,而是用它的实现类ApplicationContext,这个类会自动解析我们配置的applicatio

浅析Java的Spring框架中IOC容器容器的应用_java

Spring容器是Spring框架的核心.容器将创建对象,它们连接在一起,配置它们,并从创建到销毁管理他们的整个生命周期.在Spring容器使用依赖注入(DI)来管理组成应用程序的组件.这些对象被称为Spring Beans. 容器获得其上的哪些对象进行实例化,配置和组装通过阅读提供的配置元数据的说明.配置元数据可以通过XML,Java注释或Java代码来表示.下面的图是Spring如何工作的高层次图. Spring IoC容器是利用Java的POJO类和配置元数据的产生完全配置和可执行的系统或

一个比Spring简单的IoC容器

Spring 虽然比起EJB轻量了许多,但是因为它需要兼容许多不同的类库,导致现在Spring还是相当的庞大的,动不动就上40MB的jar包, 而且想要理解Spring的内部运行机制,阅读它的代码非常重要, 但是往往它的代码非常的"多". 现在根据Spring对Bean的生命周期的处理, 编写出一款非常小的IoC容器, 没有了对XML的解析,而是通过对Config对象的构造而完成IoC配置文件的声明, 相比较XML的方式, 对重构软件非常具有好处, 并且这个IoC大部分的实现是依据Sp

Spring的核心之IoC容器创建对象

Spring的Ioc容器,是Spring的核心内容: 作用:对象的创建和处理对象的依赖关系. Spring容器创建对象有以下几种方式: 1:调用无参数的构造器  <!-- 默认无参的构造器 --><bean id="user1" class="com.bie.po.User"></bean> 2:调用有参数构造器  <!-- 带参的构造器 ,基本数据类型直接写如int,引用数据类型写全名如java.lang.String--

Spring的IoC容器实现原理(一)#loadBeanDefinition

Spring有十几个组件,核心组件为bean(演员)-context(舞台)-core(道具) bean包装的是object,而object中肯定要有数据,如何给这些数据提供生存环境就是context要解决的问题,对于context来说他就是要发现每个bean之间的关系,为他们建立起来并维护好这些关系.所以context就是一个bean关系的集合,这个关系集合就是我们常说的IOC容器.core组件就是发现.建立和维护每个bean之间的关系所需要的一些工具,把core叫做util更为贴切.   

Spring源代码解析(一):IOC容器

在认真学习Rod.Johnson的三部曲之一:< >,顺便也看了看源代码想知道个究竟,抛砖引玉,有兴趣的同志一起讨论研究吧! 以下内容引自博客:http://jiwenke-spring.blogspot.com/,欢迎指导:) 在Spring中,IOC容器的重要地位我们就不多说了,对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就是我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,这样可以方便我们从不同的层面,不同的资源位置,

Spring IOC容器源码浅析

控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心.      控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找.依赖注入应用比较广泛.      将控制权从具体的对象手中交给平台或者是框架. BeanFactory是基本的功能接口 public interface BeanFactory { //这里是对FactoryBean的转义定

《Spring技术内幕》——2.2节IoC容器系列的设计与实现:BeanFactory和ApplicationContext

2.2 IoC容器系列的设计与实现:BeanFactory和ApplicationContext在Spring IoC容器的设计中,我们可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能:另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在.应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配.有了这两种基本的容器系列,基本上可以满足用户对IoC容器使用的大部分需求了.下面

Spring.net(二)----初探IOC容器

我在上一篇关于Spring.net的文章"Spring.NET框架简介及模块说明 "中很详细的介绍了,本文就不旧话从提.我门就直奔主题吧. 1.首先了解两个接口. IObjectFactory接口和IApplicationContext接口:他两个称为"容器"或"IOC容器". Spring.net框架的核心原则是非侵入性. IObjectFactory接口是初始化.配置及管理对象的实际容器. IObjectFactory全限定名为Spring.