Spring IOC 底层原理

如何通过 IOC 容器来创建对象:

  1. 创建 Maven 工程,在 pom.xml 中添加 Spring 框架相关的依赖;
  2. 新建实体类;
  3. 在 resources 目录下创建配置文件,可以自定义文件名,比如:spring-ioc.xml;
  4. 在 spring.xml 中配置 bean 标签,IOC 容器通过加载 bean 标签来创建对象;
  5. 调用 API 获取 IOC 创建的对象;

创建 Student 实体类

package com.trainingl.entity;public class Student {private Integer id;private String name;private Double score;public Student(){}public Student(Integer id, String name, Double score) {this.id = id;this.name = name;this.score = score;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getScore() {return score;}public void setScore(Double score) {this.score = score;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", score=" + score +'}';}
}

spring.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsd
"><bean id="student" class="com.trainingl.entity.Student"><property name="id" value="1"></property><property name="name" value="小明"></property><property name="score" value="90"></property></bean><bean id="student1" class="com.trainingl.entity.Student"><property name="id" value="2"></property><property name="name" value="小张"></property><property name="score" value="95"></property></bean></beans>

获取 IOC 创建的对象

package com.trainingl.test;import com.trainingl.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {public static void main(String[] args) {//1.加载spring.xml配置文件ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");//2.通过运行时类来获取对象Student stu = (Student)applicationContext.getBean("student");System.out.println(stu);}
}

以上是 Spring 通过 IoC 容器创建和获取对象的步骤,之前也介绍过 SpringIoC 的底层实现原理,即:先通过 XML 解析来加载 spring.xml 配置文件,然后使用反射机制调用无参构造函数动态创建对象,并调用 setter 方法完成对象属性的赋值,最后将创建好的对象放在一个类似于 HashMap 的容器里,调用 getBean 方法获取对象时,相当于 map.get(id) 返回一个对象。

很多初学者可能对以上底层的描述也似懂非懂,Spring 底层如何实现、具体使用了哪些技术也全然不知。现在通过 XML解析和反射机制,剖析实现 Spring IoC 的底层处理机制。

第一步:创建 ApplicationContext 接口

package com.trainingl.ioc;public interface ApplicationContext {public Object getBean(String id);
}

第二步:创建 ApplicationContext 接口的实现类 ClassPathXmlApplicationContext

Spring IoC容器的底层实现分两步走,用到的技术如下:

  1. XML 解析:读取 spring.xml,获取 <bean> 标签的配置信息(id,全类名,属性名,属性值等);
  2. 反射机制:根据获得的配置信息,通过反射动态地创建对象;
package com.trainingl.ioc;import com.trainingl.entity.Bean;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;public class ClassPathXmlApplicationContext implements ApplicationContext {private Map<String,Object> ioc = new HashMap();//传入文件路径,构建IOC容器public ClassPathXmlApplicationContext(String xmlPath){try {//1.通过xml解析读取spring.xml中的配置信息List<Bean> beans = parseXML(xmlPath);//2.根据这些配置信息通过反射机制创建对象createObject(beans);} catch (DocumentException e) {e.printStackTrace();}}public Object getBean(String id) {return ioc.get(id);}
}

定义类成员方法,解析 xml 文件读取 spring.xml 中的配置信息,并封装到实体类里面

package com.trainingl.entity;import lombok.Data;import java.util.List;
import java.util.Map;
@Data
public class Bean {private String id;private String classPath;private List<Map<String,String>> property;
}
private List<Bean> parseXML(String path) throws DocumentException {SAXReader saxReader = new SAXReader();Document document = saxReader.read("src/main/resources/"+path);//获取根节点Element rootElement = document.getRootElement(); //获取到<beans>//遍历根节点Iterator<Element> iterator1 = rootElement.elementIterator();List<Bean> beans = new ArrayList<Bean>();while (iterator1.hasNext()){Bean bean = new Bean();Element node = iterator1.next(); //获取到<bean>String id = node.attributeValue("id");bean.setId(id);String aClass = node.attributeValue("class");bean.setClassPath(aClass);//迭代属性Iterator<Element> iterator2 = node.elementIterator();List<Map<String,String>> propertyList = new ArrayList<Map<String, String>>();while (iterator2.hasNext()){Element property = iterator2.next();Map<String,String> map = new HashMap<String, String>();String name = property.attributeValue("name");String value = property.attributeValue("value");map.put("name",name);map.put("value",value);propertyList.add(map);}bean.setProperty(propertyList);beans.add(bean);}return beans;
}

根据 XML 实体类的配置信息,通过反射机制创建对象,并完成对象的属性赋值操作

public void createObject(List<Bean> beans){try{//通过反射机制创建对象Iterator<Bean> iterator = beans.iterator();while (iterator.hasNext()){Bean bean = iterator.next();//获取创建对象的全类名String className = bean.getClassPath();Class clazz = Class.forName(className);Object obj = clazz.getConstructor(null).newInstance(null);//遍历对象的属性值,调用set方法赋值List<Map<String,String>> properties = bean.getProperty();int i = 1;for (Map<String,String> property:properties) {//调用set方法完成属性赋值操作setProperty(obj,property,clazz);}ioc.put(bean.getId(),obj);}}catch (ClassNotFoundException e){e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}
}
public void setProperty(Object object,Map<String,String> map,Class clazz){try {String name = map.get("name");String value = map.get("value");//获取方法名String methodName = "set" + name.substring(0,1).toUpperCase() + name.substring(1);//通过反射获取方法Field declaredField = clazz.getDeclaredField(name);Method method = clazz.getMethod(methodName, declaredField.getType());//值的类型转换Object val = null;String s = declaredField.getType().getName();if ("java.lang.Integer".equals(s)) {val = Integer.parseInt(value);} else if ("java.lang.Double".equals(s)) {val = Double.parseDouble(value);} else if ("java.lang.String".equals(s)) {val = value;}//调用setter赋值method.invoke(object,val);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}
}

第三步:编写测试类 Test,测试 Spring IoC 底层实现类是否可用;

package com.trainingl.test;import com.trainingl.entity.Student;
import com.trainingl.ioc.ApplicationContext;
import com.trainingl.ioc.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");Student student = (Student)applicationContext.getBean("student");System.out.println(student);}
}

控制台的打印结果如下:

至此,Spring IoC底层代码实现解读完毕。现在才发现自己写一个框架真的很复杂,尤其是涉及到 JavaSE 一些关键技术,都必须牢固掌握(集合框架、XML解析、反射机制等)。

10. Spring IOC 底层原理相关推荐

  1. Spring——IOC底层原理

    目录 一.IOC底层原理 1.什么是IOC 2.IOC底层原理 二.IOC接口(BeanFanctory) 三.IOC操作Bean管理(基于XML) 1.创建对象 2.注入属性 (1)DI:依赖注入 ...

  2. spring 学习—spring 的ioc底层原理(02)

    IOC的底层原理 1.ioc底层原理使用技术 (1) xml配置文件 (2) dom4j 解决xml (3)工厂设计模式 (4)反射 什么叫做耦合度太高了:就是关联度太紧密了 高内聚与低耦合 高内聚: ...

  3. Spring IOC核心原理分析

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,本文系统分 ...

  4. 【JAVA SE】第十七章 反射、注解与Spring事务底层原理

    第十七章 反射.注解与Spring事务底层原理 文章目录 第十七章 反射.注解与Spring事务底层原理 一.反射 1.简介 2.意义 3.缺点 4.应用场景 5.反射技术的使用 二.注解 1.概念 ...

  5. Spring Cloud底层原理(转载 石杉的架构笔记)

    拜托!面试请不要再问我Spring Cloud底层原理 原创: 中华石杉 石杉的架构笔记 目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组 ...

  6. Spring Boot底层原理详解及整合

    Spring Boot框架 通过Spring Boot 可以构建一个基于Spring框架的Java Application,简化配置,自动装配,开箱即用 JavaConfiguration用Java类 ...

  7. 还不懂spring IOC核心原理?200行代码带你手撸一个

    Spring做为Java企业级应用的开源开发框架,早已成为Java后端开发事实上的行业标准,无数的公司选择Spring作为基础的开发框架. 使用Spring框架的人一定都听过Spring的IoC(控制 ...

  8. 面试官:说说Spring Cloud底层原理?

    点击上方"蓝字", 右上角选择"设为星标" 周一至周五上午11:45!精品文章准时送上! 本文转载自公众号:石杉的架构笔记 目录 一.业务场景介绍 二.Spri ...

  9. 面试请不要再问我Spring Cloud底层原理

    目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组件:Feign 四.Spring Cloud核心组件:Ribbon 五.Spring Cl ...

最新文章

  1. linux命令之查看动态库中字符串-strings
  2. windows mysql提示:1045 access denied for user 'root'@'localhost' using password yes 解决方案
  3. win10下zookeeper的下载以及安装
  4. java二叉树的创建,遍历及其他方法
  5. 内卷时代,普通测试员的铁饭碗究竟是什么?
  6. 结构与表现分离的思想
  7. Eclipse或MyEclipse—在Eclipse或MyEclipse中如何将jar包和相应的源代码关联起来
  8. Linux文件解压缩
  9. cocos2d-x 使用BMFont生成中文字体并应用
  10. 计算机系统概述-为什么要学习计算机系统基础
  11. python做var模型_python中VAR模型的条件预测
  12. 计算广告系统算法与架构综述
  13. java Thread的start和run方法的区别
  14. 解析二分查找时间复杂度
  15. EAUML日拱一卒-微信小程序实战:位置闹铃 (10)-定时器
  16. 三星存储新品首销情况揭秘
  17. 玩转腾讯首发Linux内核源码《嵌入式开发笔记》
  18. 独立站站群的模式和运营思路笔记
  19. 晶体管的工作原理及电流关系
  20. Aria2 Centos7部署

热门文章

  1. 制作PPT学习笔记(1)
  2. 开博第一篇,申请博客的理由
  3. 学习方法学习方法学习方法
  4. PPT学习整理(一)默认设置
  5. 一文读懂PMP项目管理资格认证考试
  6. 朋友圈爆款背后的计算机视觉技术与应用
  7. php的视频怎么保存,premiere怎么保存剪辑好的视频
  8. 16bit 180MS/s 高速数据采集卡的性能介绍
  9. 嵌入式Linux系统中U盘挂载
  10. Kotlin for 循环写法整理