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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 一:IOC容器的定义   控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找。

一: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

 

 

 

 

 

     

相关文章
|
1月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
29 0
|
1天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
29 14
|
14天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
30 2
|
14天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
27 1
|
22天前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
1月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
62 9
|
26天前
|
前端开发 Java Docker
使用Docker容器化部署Spring Boot应用程序
使用Docker容器化部署Spring Boot应用程序
|
26天前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
29 0
|
28天前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
47 0
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
37 0