[SSM]手写Spring框架

目录

十一、手写Spring框架

第一步:创建模块myspring

第二步:准备好要管理的Bean

第三步:准备myspring.xml配置文件

第四步:核心接口实现

第五步:实例化Bean

第六步:给Bean属性赋值

第七步:测试

第八步:打包发布

第十一步:使用myspring框架


十一、手写Spring框架

  • Spring IoC容器的实现原理:工厂模式+解析XML+反射机制。

第一步:创建模块myspring

配置pom.xml文件

 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion>
​<groupId>org.myspringframework</groupId><artifactId>myspring</artifactId><version>1.0.0</version><packaging>jar</packaging>
​<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--使用dom4j解析XML配置文件--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency><dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.2.0</version></dependency></dependencies>
​<properties><maven.compiler.source>20</maven.compiler.source><maven.compiler.target>20</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
​
</project>

 

第二步:准备好要管理的Bean

  • 这些Bean在将来开发完框架之后是要删除的。

User

package com.hhb.myspring.bean;
​
public class User {private String name;private int age;
​public void setName(String name) {this.name = name;}
​public void setAge(int age) {this.age = age;}
​@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

UserDao

package com.hhb.myspring.bean;
​
public class UserDao {public void insert() {System.out.println("保存用户信息");}
}

UserService

package com.hhb.myspring.bean;
​
public class UserService {private UserDao userDao;
​public void setUserDao(UserDao userDao) {this.userDao = userDao;}
​public void save() {userDao.insert();}
}

第三步:准备myspring.xml配置文件

  • 将来在框架开发完毕之后,这个文件也是要删除的。

  • 文件放在类的根路径下。

myspring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
​<bean id="user" class="com.hhb.myspring.bean.User"><property name="name" value="张三"/><property name="age" value="23"/></bean>
​<bean id="userDaoBean" class="com.hhb.myspring.bean.UserDao"/>
​<bean id="userService" class="com.hhb.myspring.bean.UserService"><property name="userDao" ref="userDaoBean"/></bean>
</beans>
  • 使用value给简单属性赋值,使用ref给非简单属性赋值。

第四步:核心接口实现

ApplicationContext

package org.myspringframework.core;
​
/*** MySpring框架应用上下文接口。*/
​
public interface ApplicationContext {/*** 根据bean的名称获取对象的bean对象** @param beanName myspring配置文件中bean标签的id* @return 对应的单例bean对象*/Object getBean(String beanName);
}

ClassPathXmlApplicationContext

package org.myspringframework.core;
​
import java.util.HashMap;
import java.util.Map;
​
public class ClassPathXmlApplicationContext implements ApplicationContext {
​private Map<String, Object> singletonObjects = new HashMap<>();
​/*** 解析myspring的配置文件,然后初始化所有的Bean对象** @param configLocation spring配置文件的路径*/public ClassPathXmlApplicationContext(String configLocation) {//解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中
​}
​@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

第五步:实例化Bean

ClassPathXmlApplicationContext

package org.myspringframework.core;
​
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​
public class ClassPathXmlApplicationContext implements ApplicationContext {
​private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);
​private Map<String, Object> singletonObjects = new HashMap<>();
​/*** 解析myspring的配置文件,然后初始化所有的Bean对象** @param configLocation spring配置文件的路径*/public ClassPathXmlApplicationContext(String configLocation) {try {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中。// 这是dom4j解析XML文件的核心对象。SAXReader reader = new SAXReader();// 获取一个输入流,指向配置文件InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);// 读文件Document document = reader.read(in);// 获取所有的bean标签List<Node> nodes = document.selectNodes("//bean");// 遍历bean标签nodes.forEach(node -> {try {// 向下转型的目的是为了使用Element接口里更加丰富的方法。Element beanElt = (Element) node;// 获取id属性String id = beanElt.attributeValue("id");// 获取class属性String className = beanElt.attributeValue("class");logger.info("beanName=" + id);logger.info("beanClassName=" + className);//通过反射机制创建对象,将其放到Map集合中,提前曝光//获取ClassClass<?> aClass = Class.forName(className);//获取无参数构造方法Constructor<?> defaultCon = aClass.getDeclaredConstructor();//调用无参数构造方法实例化BeanObject bean = defaultCon.newInstance();//将Bean曝光,加入到Map集合singletonObjects.put(id, bean);//记录日志logger.info(singletonObjects.toString());} catch (Exception e) {e.printStackTrace();}});} catch (DocumentException e) {e.printStackTrace();}}
​@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

第六步:给Bean属性赋值

package org.myspringframework.core;
​
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
/*** @author 动力节点* @version 1.0* @className ClassPathXmlApplicationContext* @since 1.0**/
public class ClassPathXmlApplicationContext implements ApplicationContext{
​private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);
​private Map<String, Object> singletonObjects = new HashMap<>();
​/*** 解析myspring的配置文件,然后初始化所有的Bean对象。* @param configLocation spring配置文件的路径。注意:使用ClassPathXmlApplicationContext,配置文件应当放到类路径下。*/public ClassPathXmlApplicationContext(String configLocation) {try {// 解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中。// 这是dom4j解析XML文件的核心对象。SAXReader reader = new SAXReader();// 获取一个输入流,指向配置文件InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);// 读文件Document document = reader.read(in);// 获取所有的bean标签List<Node> nodes = document.selectNodes("//bean");// 遍历bean标签nodes.forEach(node -> {try {// 向下转型的目的是为了使用Element接口里更加丰富的方法。Element beanElt = (Element) node;// 获取id属性String id = beanElt.attributeValue("id");// 获取class属性String className = beanElt.attributeValue("class");logger.info("beanName=" + id);logger.info("beanClassName="+className);// 通过反射机制创建对象,将其放到Map集合中,提前曝光。// 获取ClassClass<?> aClass = Class.forName(className);// 获取无参数构造方法Constructor<?> defaultCon = aClass.getDeclaredConstructor();// 调用无参数构造方法实例化BeanObject bean = defaultCon.newInstance();// 将Bean曝光,加入Map集合singletonObjects.put(id, bean);// 记录日志logger.info(singletonObjects.toString());} catch (Exception e) {e.printStackTrace();}});
​// 再次重新把所有的bean标签遍历一次,这一次主要是给对象的属性赋值。nodes.forEach(node -> {try {Element beanElt = (Element) node;// 获取idString id = beanElt.attributeValue("id");// 获取classNameString className = beanElt.attributeValue("class");// 获取ClassClass<?> aClass = Class.forName(className);// 获取该bean标签下所有的属性property标签List<Element> propertys = beanElt.elements("property");// 遍历所有的属性标签propertys.forEach(property -> {try {// 获取属性名String propertyName = property.attributeValue("name");// 获取属性类型Field field = aClass.getDeclaredField(propertyName);logger.info("属性名:" + propertyName);// 获取set方法名String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);// 获取set方法Method setMethod = aClass.getDeclaredMethod(setMethodName, field.getType());// 获取具体的值String value = property.attributeValue("value"); // "30"Object actualValue = null; // 真值String ref = property.attributeValue("ref");if (value != null) {// 说明这个值是简单类型// 调用set方法(set方法没有返回值)// 我们myspring框架声明一下:我们只支持这些类型为简单类型// byte short int long float double boolean char// Byte Short Integer Long Float Double Boolean Character// String// 获取属性类型名String propertyTypeSimpleName = field.getType().getSimpleName();switch (propertyTypeSimpleName) {case "byte":actualValue = Byte.parseByte(value);break;case "short":actualValue = Short.parseShort(value);break;case "int":actualValue = Integer.parseInt(value);break;case "long":actualValue = Long.parseLong(value);break;case "float":actualValue = Float.parseFloat(value);break;case "double":actualValue = Double.parseDouble(value);break;case "boolean":actualValue = Boolean.parseBoolean(value);break;case "char":actualValue = value.charAt(0);break;case "Byte":actualValue = Byte.valueOf(value);break;case "Short":actualValue = Short.valueOf(value);break;case "Integer":actualValue = Integer.valueOf(value);break;case "Long":actualValue = Long.valueOf(value);break;case "Float":actualValue = Float.valueOf(value);break;case "Double":actualValue = Double.valueOf(value);break;case "Boolean":actualValue = Boolean.valueOf(value);break;case "Character":actualValue = Character.valueOf(value.charAt(0));break;case "String":actualValue = value;}
​setMethod.invoke(singletonObjects.get(id), actualValue);}if (ref != null) {// 说明这个值是非简单类型// 调用set方法(set方法没有返回值)setMethod.invoke(singletonObjects.get(id), singletonObjects.get(ref));}} catch (Exception e) {e.printStackTrace();}});} catch (Exception e) {e.printStackTrace();}});} catch (Exception e) {e.printStackTrace();}}
​@Overridepublic Object getBean(String beanName) {return singletonObjects.get(beanName);}
}

第七步:测试

@Test
public void test1(){ApplicationContext applicationContext=new ClassPathXmlApplicationContext("myspring.xml");Object user = applicationContext.getBean("user");System.out.println(user);
​UserService userService = (UserService) applicationContext.getBean("userService");userService.save();
}

第八步:打包发布

 

 

 

第十一步:使用myspring框架

配置pom.xml

<dependencies><!--用myspring框架,需要引入依赖--><dependency><groupId>org.myspringframework</groupId><artifactId>myspring</artifactId><version>1.0.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency>
</dependencies>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/6492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用nginx和ffmpeg搭建HTTP FLV流媒体服务器(摄像头RTSP视频流->RTMP->http-flv)

名词解释 RTSP &#xff08;Real-Time Streaming Protocol&#xff09; 是一种网络协议&#xff0c;用于控制实时流媒体的传输。它是一种应用层协议&#xff0c;通常用于在客户端和流媒体服务器之间建立和控制媒体流的传输。RTSP允许客户端向服务器发送请求&#xff0c;如…

【Java基础教程】(四十二)多线程篇 · 上:多进程与多线程、并发与并行的关系,多线程的实现方式、线程流转状态、常用操作方法解析~

Java基础教程之多线程 上 &#x1f539;本节学习目标1️⃣ 线程与进程&#x1f50d;关于多进程、多线程、并发与并行之间的概念关系&#xff1f; 2️⃣ 多线程实现2.1 继承 Thread 类2.2 实现 Runnable 接口2.3 多线程两种实现方式的区别2.4 利用 Callable 接口实现多线程2.5 …

00_ubuntu_开发环境的搭建

ubuntu 的版本22.04 2023-07-21 1.卸载firefox dpkg --get-selections |grep firefox // 查看安装包的信息 sudo apt-get purge firefox firefox-locale-en firefox-locale-zh-hans // 卸载相应的包 2.下载google安装包并安装 wget https://dl.google.com/linux/direct/goo…

深度学习——过拟合和Dropout

基本概念 什么是过拟合&#xff1f; 过拟合&#xff08;Overfitting&#xff09;是机器学习和深度学习中常见的问题之一&#xff0c;它指的是模型在训练数据上表现得很好&#xff0c;但在未见过的新数据上表现较差的现象。 当一个模型过度地学习了训练数据的细节和噪声&#…

【多模态】17、CORA | 将 CLIP 使用到开集目标检测

文章目录 一、背景二、方法2.1 总体结构2.2 region prompting2.3 anchor pre-matching 三、效果 论文&#xff1a;CORA: Adapting CLIP for Open-Vocabulary Detection with Region Prompting and Anchor Pre-Matching 代码&#xff1a;https://github.com/tgxs002/CORA 出处…

Qt/C++音视频开发48-推流到rtsp服务器

一、前言 之前已经打通了rtmp的推流&#xff0c;理论上按照同样的代码&#xff0c;只要将rtmp推流地址换成rtsp推流地址&#xff0c;然后格式将flv换成rtsp就行&#xff0c;无奈直接遇到协议不支持的错误提示&#xff0c;网上说要换成rtp&#xff0c;换了也没用&#xff0c;而…

Linux 学习记录54(ARM篇)

Linux 学习记录54(ARM篇) 本文目录 Linux 学习记录54(ARM篇)一、框图分析1. 芯片手册内部框图2. 操作GPIO过程 二、通过汇编完成GPIO操作1. 常用的汇编指令2. GPIO初始化流程3. 查找相关寄存器(1. RCC寄存器(2. GPIO寄存器>1. 模式配置寄存器>2. 输出模式配置寄存器>3…

Jenkins常用管理功能配置 - 插件管理

Jenkins插件介绍 Jenkins是一个流行的开源持续集成/持续交付(CI/CD)工具&#xff0c;它有大量的插件来扩展其功能。这些插件可以用于构建、测试、部署和监控软件项目。下面是一些常用的Jenkins插件及其简单介绍和使用方法&#xff1a; 1. Git插件&#xff1a;允许Jenkins从Gi…

vue2如何将页面生成 pdf 导出 html2Canvas + jspdf

1.引入两个依赖 npm i html2canvas npm i jspdf 2.在utils文件夹下新建html2pdf.js文件 import html2canvas from html2canvas; import jsPDF from jspdf export const htmlToPDF async (htmlId, title "报表", bgColor "#fff") > { let pdfDom do…

【LeetCode每日一题合集】2023.7.17-2023.7.23(离线算法 环形子数组的最大和 接雨水)

文章目录 415. 字符串相加&#xff08;高精度计算、大数运算&#xff09;1851. 包含每个查询的最小区间⭐⭐⭐⭐⭐解法1——按区间长度排序 离线询问 并查集解法2——离线算法 优先队列 874. 模拟行走机器人&#xff08;哈希表 方向数组&#xff09;918. 环形子数组的最大和…

sentinel深入讲解流量控制/熔断降级

文章目录 sentinelsentinel介绍重要的核心概念引入依赖限流的规则熔断规则yaml 项目配置使用注解 SentinelResource讲解类的静态方法 sentinel sentinel介绍 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构…

【深度学习之YOLO8】环境部署

目录 一、确定版本CUDA toolkit、cuDNN版本Python、PyTorch版本 二、安装Python下载环境变量验证安装 三、安装Anaconda安装环境变量验证安装创建conda虚拟环境常用命令 四、安装CUDA toolkit下载环境变量验证安装 五、配置cuDNN下载 六、安装PyTorch(torchtorchversiontorchau…

华为、阿里巴巴、字节跳动 100+ Python 面试问题总结(五)

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python面试专栏&#xff1a;《Python面试》此专栏面向准备面试的2024届毕业生。欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; …

RUST腐蚀基因种植

RUST腐蚀基因种植 试验地址:www.xiaocao.cloud RUST基因: RUST基因计算器&#xff0c;腐蚀基因计算器&#xff0c;前后端分离架构&#xff0c;前端目录/resouce/ui/rust&#xff0c;欢迎大佬评价&#xff0c;

算法笔记(java)——回溯篇

回溯算法解决问题最有规律性&#xff0c;借用一下卡哥的图&#xff1a; 只要遇到上述问题就可以考虑使用回溯&#xff0c;回溯法的效率并不高&#xff0c;是一种暴力解法&#xff0c;其代码是嵌套在for循环中的递归&#xff0c;用来解决暴力算法解决不了的问题&#xff0c;即…

Tensorflow无人车使用移动端的SSD(单发多框检测)来识别物体及Graph的认识

环境是树莓派3B&#xff0c;当然这里安装tensorflow并不是一定要在树莓派环境&#xff0c;只需要是ARM架构就行&#xff0c;也就是目前市场上绝大部分的嵌入式系统都是用这套精简指令集。 在电脑端的检测&#xff0c;有兴趣的可以查阅SSD(Single Shot MultiBox Detector)系列&a…

19 QListWidget控件

Tips: 对于列表式数据可以使用QStringList进行左移一块输入。 代码&#xff1a; //listWidget使用 // QListWidgetItem * item new QListWidgetItem("锄禾日当午"); // QListWidgetItem * item2 new QListWidgetItem("汗滴禾下土"); // ui->…

十、正则表达式详解:掌握强大的文本处理工具(二)

文章目录 &#x1f340;多字符匹配&#x1f340;匹配规则的代替&#x1f340;特殊的匹配&#x1f340;特殊的匹配plus&#x1f340;总结 &#x1f340;多字符匹配 星号&#xff08;*&#xff09;&#xff1a;匹配0个或者多个字符 import retext 111-222-333 result re.matc…

苹果的Apple GPT要来了?

据外媒消息&#xff0c;苹果正在内部开发类 ChatGPT 的产品&#xff0c;与微软、OpenAI、谷歌、Meta 等科技巨头在生成式 AI 赛道展开竞争。该消息使得苹果股价上涨了 2%。据苹果工程师透露&#xff0c;苹果在内部构建了代号为“Ajax”的大语言模型开发框架&#xff0c;并构建了…

Unity自定义后处理——Bloom效果

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理效果&#xff0c;这一期讲一下Bloom效果。 一、Bloom效果介绍 还是拿这个模型作为背景。 Bloom效果&#xff0c;就是一种全屏泛光的效果&#xff0c;让模型和特效有一种真的在发光的感觉。 根据参数不一样&#xff0c;可…