手写简单实现IOC

这个小demo是利用反射从最基础一步一步模拟实现了IOC的功能,所有的代码基本都给出了注释,方便大家阅读.

目录结构:

这里需要导入一下junit依赖

   <!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>

 两个工具类:

TestController类:

package com.heaboy.springioc.entity;import com.heaboy.springioc.stereotype.Autowired;
import com.heaboy.springioc.stereotype.Component;
import sun.misc.Contended;@Component
public class TestController {@Autowiredprivate UserService userService;public void test(){//通过反射拿到userService对象调用addUser方法userService.addUser("zhangsan",111);}
}

UserService类:

package com.heaboy.springioc.entity;import com.heaboy.springioc.stereotype.Component;@Component
public class UserService {//接受传参 并且输出public void addUser(String name,int age){System.out.println(name);System.out.println(age);}
}

两个注解类:

Autowired:

package com.heaboy.springioc.stereotype;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

Component:

package com.heaboy.springioc.stereotype;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}

最重要的模拟IOC类:

package com.heaboy.springioc.ioc;import com.heaboy.springioc.stereotype.Autowired;
import com.heaboy.springioc.stereotype.Component;import java.io.File;
import java.io.FileNotFoundException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;public class SpringIOC {//声明存放bean名称的列表private List<String> beanNames;//声明存放文件路径的列表private List<String> filePaths;//声明基础路径字符串private String basePath;//声明基础包名字符串private String basePackage;//声明存放bean对象的映射private Map<String,Object> beans = new HashMap<>();/*** 扫描所有的文件信息,存放到filePaths*/private void scan() throws FileNotFoundException{//创建File 对象表示基础路径File file = new File(basePath);//初始化存放文件路径的列表filePaths = new ArrayList<>();//判断文件是否存在if(file.exists()){//定义一个列表 用于逐层深入的遍历每个文件(广度优先搜索)Queue<File> queue = new LinkedList<>();//将根文件添加到队列当中queue.add(file);//判断队列是否为空while (!queue.isEmpty()){//取出 根文件赋值给poll便于逐层深入File poll = queue.poll();//如果poll是空说明他下面已经不存在文件和文件路径了 直接跳过执行下一步if(poll == null){continue;}//如果是文件夹if(poll.isDirectory()){//创建一个File类型的数组 拿到poll里面的全部文件,文件夹File[] files = poll.listFiles();for (File file1:files){//将poll里面的全部文件夹以及文件加入队列queue.add(file1);}//如果此poll是文件}else {//直接将文件的路径添加到filePaths列表中filePaths.add(poll.getPath());}}}else {//如果没找到文件//抛出文件未找到异常throw new FileNotFoundException(basePath+"not found");}}/*** 将所有的.java结尾的 全限定名放到 beanNames 列表里面*/public void initBeanNames(){//遍历 filePaths里面的每一个文件的路径for (String s :filePaths){//将文件中的 基础路径部分替换成空串(因为所有文件路径的基础路径都是一样的,// 我们需要获取的是以.java结尾的文件的全限定名 前缀需要去掉)String replace = s.replace(basePath,"");//判断文件的全限定名是不是以.java结尾if (replace.endsWith(".java")){//截取掉.javareplace = replace.substring(0,replace.length()-5);}//将字符串转换成字符数组 目的是为了方便把路径中的\\替换成.char[] chars = replace.toCharArray();for (int i=0;i<chars.length;i++){if(chars[i]=='\\'){chars[i]='.';}}//拼接字符串 拼接出文件在该项目中的源根地址beanNames.add(basePackage+"."+new String(chars));}}/*** 初始化所有的Bean对象 根据上个方法求出来的所有文件的源根地址* 遍历每一个文件(其实就是java文件) 看四否含有Component注解(也就是被标记为* 它表明这个类会被 Spring IoC 容器自动检测和注册为 Spring 的一个 bean。* 也就是把类交给spring管理)*/public void initBeans(){for (String beanName : beanNames){try {//根据路径 拿到具体的类对象Class<?> aClass = Class.forName(beanName);//拿到这个类声明的所有注解Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();//遍历所有注解 看是否存在@Component注解for (Annotation declaredAnnotation : declaredAnnotations){//如果是Component注解if(declaredAnnotation instanceof Component){//创建该类的实例化对象Object o =aClass.newInstance();//将对象放入beans映射中//aClass.getName() 类名  o 实例化对象beans.put(aClass.getName(),o);}}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}//依次遍历 查看是否有Autowired注解 如果有,给对应字段附上相应的实例化对象for (Map.Entry<String,Object> entry : beans.entrySet()){//利用反射获取到对象对应类的所有声明字段Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();//遍历所有字段 获取每个字段声明的注解看是否包含Autowired注解for (Field field : declaredFields){Annotation[] annotations = field.getDeclaredAnnotations();for (Annotation annotation : annotations){if(annotation instanceof Autowired){//是Autowired注解我们需要为对应的变量 付给他对应的对象//先获取该字段的类型对应的对象名称String name = field.getType().getName();//从beans里获取这个名字的对象Object o = beans.get(name);//设置字段可访问field.setAccessible(true);try {//给字段赋值//也就是说 原本没有赋值的时候entry对象里对应的字段的值是一个空的对象,//然后通过set方法把这个字段的值替换成相应的对象field.set(entry.getValue(),o);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}}/*** 根据bean名称获取对应的实例化对象* beanName bean的名称* 返回值:一个实例化对象*/public Object getInstance(String beanName){return beans.get(beanName);}/*** 初始化基础路径和包名*/private void initPath(){//初始化文件的路径 你项目所在电脑中的位置basePath="D:\\blog1\\ioc\\src\\main\\java\\com\\heaboy\\springioc\\";//初始化基础包名basePackage = "com.heaboy.springioc";}/*** SpringIOC类的构造方法,初始化路径和扫描文件*/public SpringIOC(){//初始化路径和包名initPath();try {scan();//扫描文件} catch (FileNotFoundException e) {e.printStackTrace();}//初始化bean名称列表beanNames = new ArrayList<>();//初始化bean名称initBeanNames();}}

测试类:

package com.heaboy.springioc.ioc;import com.heaboy.springioc.entity.TestController;
import org.junit.Test;import java.io.FileNotFoundException;public class SpringIOCTest {@Testpublic void testScan() throws FileNotFoundException {//创建SpringIOC类型的实例化对象SpringIOC springIOC = new SpringIOC();//调用SpringIOC的bean对象初始化方法springIOC.initBeans();//借用SpringIOC中的利用反射创建实例化对象方法 通过传入一个类名获取到实例化对象TestController instance = (TestController)springIOC.getInstance(TestController.class.getName());//对象调用test方法;instance.test();}
}

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

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

相关文章

解决vite 断点调试定位不准确问题

问题&#xff1a;vite构建时&#xff0c;控制台报错行数等信息定位不准确或debugger断点调试定位不准确 解决&#xff1a;F12后打开设置面板&#xff0c;把“JavaScript源代码映射”去掉可临时解决&#xff0c;如需永久解决需升级vite到最新版 还有一种&#xff1a; 参考&…

Unity--射线检测--RayCast

Unity–射线检测–RayCast 1.射线检测的含义 射线检测,根据名称而言,使用一条射线来检测是击中了某个物体/多个物体 射线检测的包含两个部分: 射线和检测 2.射线检测可以用在哪些地方 射击游戏&#xff1a; 玩家的瞄准和射击&#xff1a;检测玩家视线是否与敌人或其他目标…

JRE、JVM、JDK分别是什么。

JDK JDK的英文全称是Java Development Kit。JDK是用于制作程序和Java应用程序的软件开发环境。JDK 是 Java 开发工具包&#xff0c;它是 Java 开发者用来编写、编译、调试和运行 Java 程序的集合。JDK 包括了 Java 编译器&#xff08;javac&#xff09;、Java 运行时环境&…

首席数据官CDO证书报考指南:方式、流程、适考人群与考试难度

在信息泛滥的今天&#xff0c;数据已转变为企业不可或缺的宝贵资源。 面对海量的信息&#xff0c;如何提炼出价值&#xff0c;为企业带来实质性的收益&#xff1f;首席数据官&#xff08;CDO&#xff09;认证的出现正是为了满足这一需求&#xff0c;它不仅是个人专业能力的体现…

【网络安全】这些网络安全知识请牢记!

随着社会信息化深入发展&#xff0c;互联网对人类文明进步将发挥更大促进作用&#xff0c;但与此同时&#xff0c;互联网领域的问题也日益凸显&#xff0c;网络犯罪、网络攻击等时有发生&#xff0c;网络安全与每个人都息息相关&#xff0c;下面一起来了解网络安全知识吧&#…

如何降低电力运维成本,为企业的运维增效、能源数字化和节能降耗提供数据支持?

【电力运维存在问题】 随着全球范围内城镇化、数字化和工业化进程的加速与电力政策的改革&#xff0c;企业用电需求不断攀升&#xff0c;极大冲击了电力企业传统的运维模式&#xff0c;暴露出许多的问题&#xff1a; 变电所较为分散&#xff0c;缺乏统一管理&#xff1b;站内…

从数据仓库到数据湖(下):热门的数据湖开源框架

文章目录 一、前言二、Delta Lake三、Apache Hudi四、Apache Iceberg五、Apache Paimon六、对比七、笔者观点八、总结八、参考资料 一、前言 在上一篇从数据仓库到数据湖(上)&#xff1a;数据湖导论文章中&#xff0c;我们简单讲述了数据湖的起源、使用原因及其本质。本篇文章…

Linux:Ubuntu18.04下开机自启动QT图形化界面

Linux&#xff1a;Ubuntu18.04下开机自启动QT图形化界面 Chapter1 Linux&#xff1a;Ubuntu18.04下开机自启动QT图形化界面一、创建rc.local文件二、建立rc-local.service文件三、启动服务查看启动状态四、重启 Chapter2 将QT应用作为开机自启动&#xff08;Linux系统&#xff…

Simulink生成代码时端口名称乱码问题

写在最前&#xff1a; 在使用Simulink生成代码时发现端口名称与模型中定义的输如输出端口名称不一致&#xff0c;代码生成的端口名称为随机字符名称。 在生成的H文件中发现&#xff0c;端口定义的结构体名称与模型中实际定义的名称不符。 模型中的定义 检查后发现&#xff0c…

【已解决】腾讯云安装了redis,但是本地访问不到,连接不上

汇总了我踩过的所有问题。 查看配置文件redis.conf 1、把bind 127.0.0.1给注释掉&#xff08;前面加个#就是&#xff09;或者改成bind 0.0.0.0&#xff0c;因为刚下载时它是默认只让本地访问。&#xff08;linux查找文档里的内容可以输入/后面加需要匹配的内容&#xff0c;然后…

基于STM主题模型的主题提取分析-完整代码数据

直接看结果: 代码: import re from collections import defaultdict import random import matplotlib.pyplot as plt import numpy as npimport pandas as pd import numpy as np import re from sklearn.feature_extraction.text import CountVectorizer from nltk.corpus…

如何在 Ubuntu上搭建 LAMP

远程登录 Ubuntu系统环境 ssh (User)(IP) # 比如&#xff1a;ssh lennlouis192.168.207.128 为安全起见&#xff0c;建议你使用 root 登录 VPS 后创建一个具有 sudo 权限的帐号。 安装和配置 Apache 2 Apache Http Server 是一个开源的&#xff0c;非常流行&#xff0c;使用…

【Dell R730 折腾记录】风扇调速--在 Ubuntu 系统上开机自启动并每隔30分钟执行一次风扇定速脚本

前段时间升级了一下机柜里的服务器&#xff0c;替换掉了一台旧的 Dell 服务器&#xff0c;换上了这台 R730。但是无奈于噪音的袭扰&#xff0c;搁置了一段时间。我在这台机器上目前安装了一块 Intel Xeon E5-2630v3 芯片以及一张改过散热的 NVIDIA Tesla P4 计算卡。结果就是散…

关于ORACLE单例数据库中的logfile的切换、删除以及添加

一、有关logfile的状态解释 UNUSED&#xff1a; 尚未记录change的空白group&#xff08;一般会出现在loggroup刚刚被添加&#xff0c;或者刚刚使用了reset logs打开数据库&#xff0c;或者使用clear logfile后&#xff09; CURRENT: 当前正在被LGWR使用的gro…

K8S 上部署大数据相关组件

文章目录 一、前言二、Redis 一、前言 Artifact Hub 是一个专注于云原生应用的集中式搜索和发布平台。它旨在简化开发者在 CNCF&#xff08;Cloud Native Computing Foundation&#xff09;项目中寻找、安装和分享包与配置的过程。用户可以通过这个平台方便地发现、安装各类云原…

【CPP】CPP的命名空间输入输出缺省参数函数重载

目录 1 命名空间 -- namespace2 CPP的输入与输出(io)2.1 输入输出流的一些规定2.2 实操一下2.3 关于endl2.4 关于精度控制2.5 效率提高 3 缺省参数(默认参数)3.1 样例3.2 全缺省与半缺省3.3 缺省参数的意义 4 函数重载4.1 函数重载的基本使用4.2 函数重载调用歧义 这里是oldkin…

记录一次MySql锁等待 (Lock wait timeout exceeded)异常

[TOC](记录一次MySql锁等待 (Lock wait timeout exceeded)异常) Java执行一个SQL查询未提交&#xff0c;遇到1205错误。 java.lang.Exception: ### Error updating database. Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transactionCluster…

互联网应用主流框架整合之SpringCloud微服务治理

微服务架构理念 关于微服务的概念、理念及设计相关内容&#xff0c;并没有特别严格的边界和定义&#xff0c;某种意义上说&#xff0c;适合的就是最好的&#xff0c;在之前的文章中有过详细的阐述&#xff0c;微服务[v1.0.0][Spring生态概述]、微服务[设计与运行]、微服务[v1.…

SpringMVC--获取请求参数

1、通过的ServletAPI获取 只需要在控制器的方法的形参位置设置HTTPRequest request 类型的形参就i可以在控制器方法种使用request对象获取请求参数 RequestMapping("/servletAPI")public String getByServletAPI(HttpServletRequest request){HttpSession session…

JAVA集合Collection常用方法详解

一、Collection介绍 提到集合就不得不提一下数组&#xff0c;好多集合底层都是依赖于数组的实现。数组一旦初始化后&#xff0c;长度就确定了&#xff0c;存储数据对象不能达到动态扩展&#xff0c;其次数组存储元素不便于对数组进行添加、修改、删除操作&#xff0c;而且数组…