10. Spring IOC 底层原理
Spring IOC 底层原理
如何通过 IOC 容器来创建对象:
- 创建 Maven 工程,在 pom.xml 中添加 Spring 框架相关的依赖;
- 新建实体类;
- 在 resources 目录下创建配置文件,可以自定义文件名,比如:spring-ioc.xml;
- 在 spring.xml 中配置 bean 标签,IOC 容器通过加载 bean 标签来创建对象;
- 调用 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容器的底层实现分两步走,用到的技术如下:
- XML 解析:读取 spring.xml,获取
<bean>
标签的配置信息(id,全类名,属性名,属性值等); - 反射机制:根据获得的配置信息,通过反射动态地创建对象;
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 底层原理相关推荐
- Spring——IOC底层原理
目录 一.IOC底层原理 1.什么是IOC 2.IOC底层原理 二.IOC接口(BeanFanctory) 三.IOC操作Bean管理(基于XML) 1.创建对象 2.注入属性 (1)DI:依赖注入 ...
- spring 学习—spring 的ioc底层原理(02)
IOC的底层原理 1.ioc底层原理使用技术 (1) xml配置文件 (2) dom4j 解决xml (3)工厂设计模式 (4)反射 什么叫做耦合度太高了:就是关联度太紧密了 高内聚与低耦合 高内聚: ...
- Spring IOC核心原理分析
学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,本文系统分 ...
- 【JAVA SE】第十七章 反射、注解与Spring事务底层原理
第十七章 反射.注解与Spring事务底层原理 文章目录 第十七章 反射.注解与Spring事务底层原理 一.反射 1.简介 2.意义 3.缺点 4.应用场景 5.反射技术的使用 二.注解 1.概念 ...
- Spring Cloud底层原理(转载 石杉的架构笔记)
拜托!面试请不要再问我Spring Cloud底层原理 原创: 中华石杉 石杉的架构笔记 目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组 ...
- Spring Boot底层原理详解及整合
Spring Boot框架 通过Spring Boot 可以构建一个基于Spring框架的Java Application,简化配置,自动装配,开箱即用 JavaConfiguration用Java类 ...
- 还不懂spring IOC核心原理?200行代码带你手撸一个
Spring做为Java企业级应用的开源开发框架,早已成为Java后端开发事实上的行业标准,无数的公司选择Spring作为基础的开发框架. 使用Spring框架的人一定都听过Spring的IoC(控制 ...
- 面试官:说说Spring Cloud底层原理?
点击上方"蓝字", 右上角选择"设为星标" 周一至周五上午11:45!精品文章准时送上! 本文转载自公众号:石杉的架构笔记 目录 一.业务场景介绍 二.Spri ...
- 面试请不要再问我Spring Cloud底层原理
目录 一.业务场景介绍 二.Spring Cloud核心组件:Eureka 三.Spring Cloud核心组件:Feign 四.Spring Cloud核心组件:Ribbon 五.Spring Cl ...
最新文章
- linux命令之查看动态库中字符串-strings
- windows mysql提示:1045 access denied for user 'root'@'localhost' using password yes 解决方案
- win10下zookeeper的下载以及安装
- java二叉树的创建,遍历及其他方法
- 内卷时代,普通测试员的铁饭碗究竟是什么?
- 结构与表现分离的思想
- Eclipse或MyEclipse—在Eclipse或MyEclipse中如何将jar包和相应的源代码关联起来
- Linux文件解压缩
- cocos2d-x 使用BMFont生成中文字体并应用
- 计算机系统概述-为什么要学习计算机系统基础
- python做var模型_python中VAR模型的条件预测
- 计算广告系统算法与架构综述
- java Thread的start和run方法的区别
- 解析二分查找时间复杂度
- EAUML日拱一卒-微信小程序实战:位置闹铃 (10)-定时器
- 三星存储新品首销情况揭秘
- 玩转腾讯首发Linux内核源码《嵌入式开发笔记》
- 独立站站群的模式和运营思路笔记
- 晶体管的工作原理及电流关系
- Aria2 Centos7部署