基于注解手写Spring的IOC(上)

一、思路

先要从当前类出发找到对应包下的所有类文件,再从这些类中筛选出类上有@MyComponent注解的类;把它们都装入Map中,同时类属性完成@MyValue的赋值操作。

二、具体实现

 测试类结构:

 测试类:myse、mycontor、BigStar、MyAnneTest结构都一致

@MyComponent("BigStar")
public class BigStar{@MyValue("张三")private String name;@Overridepublic String toString() {return "BigStar{" +"name='" + name + '\'' +'}';}
}

自定义注解类(MyComponent--扫描类)

@Target({ElementType.TYPE}) // 作用范围:类上
@Retention(RetentionPolicy.RUNTIME) // 运行时候生效
public @interface MyComponent {String value() default "";
}

数据注入(MyValue)

@Target({ ElementType.FIELD}) // 使用的范围 字段上
@Retention(RetentionPolicy.RUNTIME) // 生效时候 运行时候
public @interface MyValue {String value() default "";
}

三、代码编写

首先处理获得项目的包路径:也是IOC启动方法

在junit4 中编写:

MyIOC()方法

   private Map<Object,Object> IOC=new HashMap<>(); // 创建 IOC容器@Testpublic void MyIOC() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {ClassLoader contextClassLoader =Thread.currentThread().getContextClassLoader(); //当前线程中获得类加载器// System.out.println("包路径:"+ BigStar.class.getPackage()); // 获得包数据// 获得包资源// BigStar.class.getPackage().getName()获得包 名字// contextClassLoader.getResources() 获得资源相关的路径Enumeration<URL> resources = contextClassLoader.getResources( BigStar.class.getPackage().getName());// 如果有存在没有被读取过的--包只有一个,所有数据只有一条while (resources.hasMoreElements()){// 获得数据URL url = resources.nextElement();String path = url.getPath(); // 获取包的绝对路径// 包的绝对地址:/C:/Users/kk/IdeaProjects/IOCTest/target/classes/beanSystem.out.println("包的绝对地址:"+ path);// 获得地址: /C:/Users/kk/IdeaProjects/IOCTest/target/classes/beanDirectoryToClass(path); // 把包路径传入System.out.println("容器中的数据:"+IOC);}}

对路径进行处理:

只需要 “包名.类名字” 即可

DirectoryToClass()方法

    // 处理类路径--获得 包名字+类名字private  void DirectoryToClass(String Mypath) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {// 获得类路径//  String myclassPath=myclass.getPath();List<Object> list=new ArrayList<>();String dgtoPath=""; //递归路径File files=new File(Mypath); //打开文件if (files.isDirectory()) { //如果是目录for (File myclass : files.listFiles()) { // 遍历目录中的文件String  directoryPath=myclass.getPath(); //获得单个文件路径路径// 路径例如: C:\Users\kk\IdeaProjects\IOCTest\target\classes\bean\Star.class// System.out.println("类文件路径:" + directoryPath);dgtoPath=directoryPath;String path1 = directoryPath.replace("\\", "."); // 把 \替换成 .String path = path1.replace("/", "."); // 把 /替换成 .String[] split = path.split("classes\\."); // 根据classes 切割字符串String classpath = split[split.length - 1]; // 获得包路径路径 com.xx.cc.classif (classpath.contains(".class")) { //  是 .class后缀String[] name = classpath.split("\\.class");//  根据.class切割 ---类加载器只需要包名字+类名字//例如: bean.BigStar 或者bean.test.test2.myse 等System.out.println("包名.类名字:"+name[0]);getToClass(name[0]);  //参数传入:获得对象} // TODO 如果是目录的话?递归else {DirectoryToClass(dgtoPath); // 如果是目录就--递归}}}}

难点已经解决了,剩下的就是根据"包名.类名"使用反射创建对象。

getToClass()方法

 // 获得类对象属性private void getToClass(String classPath) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> clazz = Class.forName(classPath); // 获得类加载器// System.out.println("创建成功的类:"+clazz);try { // 异常处理 即使clazz.getDeclaredConstructor().newInstance(); 遇到接口不能创建对象--程序也不会停止Object bean = clazz.getDeclaredConstructor().newInstance(); // 创建对象--暴力创建MyComponent beanName = clazz.getAnnotation(MyComponent.class); // 获得类上注解if(!Objects.isNull(beanName)){ // 类上有注解的时候String key=beanName.value(); // 获得注解中的value值--类名字//    System.out.println("key名字:"+key);Field[] declaredFields = clazz.getDeclaredFields(); // 获得字段for (Field field:declaredFields){  // 遍历字段MyValue value = field.getAnnotation(MyValue.class); // 获得字段上的注解field.setAccessible(true); // 打开权限 暴力注入 狠狠地注入field.set(bean,value.value()); // 设置当前bean对象的字段}IOC.put(key,bean); // 存储到IOC中}}catch (Exception e){System.out.println("不是类:"+e); // 如果遇到其他类型文件、接口等}}

四、运行结果

包的绝对地址:/C:/Users/kk/IdeaProjects/IOCTest/target/classes/bean
包名.类名字:bean.BigStar
包名.类名字:bean.MyAnneTest
包名.类名字:bean.MyComponent
不是类:java.lang.NoSuchMethodException: bean.MyComponent.<init>()
包名.类名字:bean.MyValue
不是类:java.lang.NoSuchMethodException: bean.MyValue.<init>()
包名.类名字:bean.test.mycontor
包名.类名字:bean.test.test2.myse
容器中的数据:{mycontor=mycontor{hobb='李四'}, MyAnneTest=MyAnneTest{name='张三', hobby='打篮球'}, BigStar=BigStar{name='张三'}, myse=myse{name='后悔'}}

五、后言

大多少自之定义注解都需要扫描包这一步,把getToClass()方法换一下就是其他的功能。ioc真正关键的还是@Autowired注解的实现,我放到下篇讲解。

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

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

相关文章

2023牛客暑期多校-J-Qu‘est-ce Que C‘est?(DP)

题意&#xff1a; 给定长度为n的数列,要求每个数都在的范围&#xff0c;且任意长度大于等于2的区间和都大于等于0&#xff0c;问方案数。。 思路&#xff1a; 首先要看出是dp题&#xff0c;用来表示遍历到第i位且后缀和最小为x的可行方案数&#xff08;此时的后缀可以只有最…

IT技术面试必备:如何做好IT类技术面试?

博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;&#x1f3fb; 《java 面试题大全》 &#x1f369;惟余辈才疏学浅&#xff0c;临摹之作或有不妥之处&#xff0c;还请读者海涵指正。☕&#x1f36d; 《MYSQL从入门到精通》数据库是开发者必会基础之…

【Linux】多线程的补充

1 线程安全的单例模式 1.1 什么是单例模式 单例模式是一种 "经典的, 常用的, 常考的" 设计模式. 1.2 什么是设计模式 IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些…

04-导数判断凹(concave)凸(convex)性_导数用于泰勒展开

导数与函数凹凸性的关系 函数的二阶导数是和函数的凹凸性是有关系的&#xff0c;凹凸性怎么定义的&#xff1f; 先来做简单的回顾&#xff0c;更多的会在最优化方法里面给大家讲&#xff0c;这里先记住凸函数是向下凸的&#xff0c; 反正就是凹的&#xff0c;是否是凸函数可以…

秒级体验本地调试远程 k8s 中的服务

点击上方蓝色字体&#xff0c;选择“设为星标” 回复”云原生“获取基础架构实践 背景 在这个以k8s为云os的时代&#xff0c;程序员在日常的开发过程中&#xff0c;肯定会遇到各种问题&#xff0c;比如&#xff1a;本地开发完&#xff0c;需要部署到远程k8s集群&#xff0c;本地…

【设计模式】详解观察者模式

文章目录 1、简介2、观察者模式简单实现抽象主题&#xff08;Subject&#xff09;具体主题&#xff08;ConcreteSubject&#xff09;抽象观察者&#xff08;Observer&#xff09;具体观察者&#xff08;ConcrereObserver&#xff09;测试&#xff1a; 观察者设计模式优缺点观察…

十八章:用于弱监督语义分割的自监督等变注意力机制

0.摘要 图像级弱监督语义分割是一个具有挑战性的问题&#xff0c;近年来得到了深入研究。大多数先进的解决方案利用类激活图&#xff08;CAM&#xff09;。然而&#xff0c;由于全监督和弱监督之间存在差距&#xff0c;CAM几乎无法用作对象掩码。在本文中&#xff0c;我们提出了…

[JAVAee]定时器

目录 定时器的含义 定时器的使用 定时器的解析 ①TaskQueue ​②TimerThread ③Timer 定时器的模拟实现 ①创建Task自定义类型 ②创建TimerThread类 ③Timer类 完整代码 定时器的含义 从名字上看,就是我们通俗理解的那个定时器.设置一定的时间,并在一定的时间后发生…

安卓抓包神奇黄鸟HttpCanary安装配置及使用教程

1、下载安装包 黄鸟抓包下载地址 2、安装下载的apk 3、证书安装问题 vivo手机我安装时打开黄鸟app&#xff0c;会直接弹出&#xff0c;直接安装即可 其他手机&#xff0c;需要去系统设置中安装 3.1 搜索 证书&#xff0c;选择CA证书 3.2 进行本人操作验证 3.3 安装HttpCa…

黄东旭:The Future of Database,掀开 TiDB Serverless 的引擎盖

在 PingCAP 用户峰会 2023 上&#xff0c; PingCAP 联合创始人兼 CTO 黄东旭 分享了“The Future of Database”为主题的演讲&#xff0c; 介绍了 TiDB Serverless 作为未来一代数据库的核心设计理念。黄东旭 通过分享个人经历和示例&#xff0c;强调了数据库的服务化而非服务化…

C语言假期作业 DAY 01

题目 1.选择题 1、执行下面程序&#xff0c;正确的输出是&#xff08; &#xff09; int x5,y7; void swap() { int z; zx; xy; yz; } int main() { int x3,y8; swap(); printf("%d,%d\n"&#xff0c;x, y)…

Android Studio 代码模板插件实现

Android Studio 代码模板插件 背景 可以跳过背景和简述&#xff0c;从模板插件实现开始看. 开发新页面时&#xff0c;原先需要写一堆模板代码。比如用Databinding写列表结构的页面&#xff0c;需要手写以下文件&#xff1a; XxActivity.ktXxFragment.ktXxViewModel.ktXxListA…

基于K8s环境·使用ArgoCD部署Jenkins和静态Agent节点

今天是「DevOps云学堂」与你共同进步的第 47天 第⑦期DevOps实战训练营 7月15日已开营 实践环境升级基于K8s和ArgoCD 本文节选自第⑦期DevOps训练营 &#xff0c; 对于训练营的同学实践此文档依赖于基础环境配置文档&#xff0c; 运行K8s集群并配置NFS存储。实际上只要有个K8s集…

CAD .NET 15.0 企业版 Crack

CAD .NET 15.0 企业版 企业版 企业版 企业版 企业版 Updated: June 14, 2023 | Version 15.0 NEW CAD .NET is a library for developing solutions in .NET environment. It supports AutoCAD DWG/ DXF, PLT and other CAD formats. The library can be used in a wide rang…

C语言之pthread_cond_t信号变化探究总结(八十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【RabbitMQ(day2)】默认(直连)交换机的应用

文章目录 一、第一种模型&#xff08;Hello World&#xff09;二、第二种模型&#xff08;work queue&#xff09;自动确认机制的后果和公平分配 三、阐述默认交换机 这篇博客是以下资料学后的总结&#xff1a; 不良人的RabbitMQ的教学视频 官方启动教程 RabbitMQ中文文档 一、…

【SQL语句】

目录 一、SQL语句类型 1.DDL 2.DML 3.DLL 4.DQL 二、数据库操作 1.查看 2.创建 2.1 默认字符集 2.2 指定字符集 3.进入 4.删除 5.更改 5.1 库名称 5.2 字符集 三、数据表操作 1.数据类型 1.1 数值类型&#xff08;常见&#xff0c;下同&#xff09; 1.1.1 T…

ChatGPT长文本对话输入方法

ChatGPT PROMPTs Splitter 是一个开源工具&#xff0c;旨在帮助你将大量上下文数据分成更小的块发送到 ChatGPT 的提示&#xff0c;并根据如何处理所有块接收到 ChatGPT&#xff08;或其他具有字符限制的语言模型&#xff09;的方法。 推荐&#xff1a;用 NSDT设计器 快速搭建可…

【QT】Day3

1. 完成闹钟的实现&#xff1a; widgt.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QTimerEvent> //定时器事件处理函数 #include <QTime> //时间类 #include <QTextToSpeech> //文本转语音类头…

Jmap-JVM(十六)

上篇文章说了ZGC是jdk11加入的&#xff0c;他是未来jvm垃圾收集器的奠定者&#xff0c;满足TB级别内存处理&#xff0c;STW时间保持在10ms以下。 Jmap 我们可以先通过jmap -histo 进程ip 来查看&#xff0c;但是这样看不太清晰&#xff0c;我们可以用这行命令生成一个文件&…