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

news2024/9/24 21:28:14

一、思路

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

二、具体实现

 测试类结构:

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

@MyComponent("BigStar")
public class BigStar{

    @MyValue("张三")
    private String name;

    @Override
    public 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容器

    @Test
    public 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/bean
            System.out.println("包的绝对地址:"+ path);
          // 获得地址: /C:/Users/kk/IdeaProjects/IOCTest/target/classes/bean
            DirectoryToClass(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.class

                if (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.coloradmin.cn/o/810402.html

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

相关文章

hcq1-1300-d

禾川的产品&#xff1a;版本V3.22 网口1&#xff1a; IPV4&#xff1a;192.168.188.100 子网掩码&#xff1a;255.255.255.0 网口2&#xff1a; IPV4&#xff1a;192.168.88.100 子网掩码&#xff1a;255.255.255.0 功能按键&#xff1a; 旋转拨码0 切换 SYS\IN\OUT 指示灯及…

NLP From Scratch: 基于注意力机制的 seq2seq 神经网络翻译

NLP From Scratch: 基于注意力机制的 seq2seq 神经网络翻译 这是关于“从头开始进行 NLP”的第三篇也是最后一篇教程&#xff0c;我们在其中编写自己的类和函数来预处理数据以完成 NLP 建模任务。 我们希望在完成本教程后&#xff0c;您将继续学习紧接着本教程的三本教程&…

C#,数值计算——对数正态分布(logarithmic normal distribution)的计算方法与源程序

对数正态分布&#xff08;logarithmic normal distribution&#xff09;是指一个随机变量的对数服从正态分布&#xff0c;则该随机变量服从对数正态分布。对数正态分布从短期来看&#xff0c;与正态分布非常接近。但长期来看&#xff0c;对数正态分布向上分布的数值更多一些。 …

【机器学习】Gradient Descent

Gradient Descent for Linear Regression 1、梯度下降2、梯度下降算法的实现(1) 计算梯度(2) 梯度下降(3) 梯度下降的cost与迭代次数(4) 预测 3、绘图4、学习率 首先导入所需的库&#xff1a; import math, copy import numpy as np import matplotlib.pyplot as plt plt.styl…

Pytest学习教程_装饰器(二)

前言 pytest装饰器是在使用 pytest 测试框架时用于扩展测试功能的特殊注解或修饰符。使用装饰器可以为测试函数提供额外的功能或行为。   以下是 pytest 装饰器的一些常见用法和用途&#xff1a; 装饰器作用pytest.fixture用于定义测试用例的前置条件和后置操作。可以创建可重…

读发布!设计与部署稳定的分布式系统(第2版)笔记26_安全性上

1. 安全问题 1.1. 系统违规并不总是涉及数据获取&#xff0c;有时会出现植入假数据&#xff0c;例如假身份或假运输文件 1.2. 必须在整个开发过程中持续地把安全内建到系统里&#xff0c;而不是把安全像胡椒面那样在出锅前才撒到系统上 2. OWASP 2.1. Open Web Application…

DataStructure--Basic

程序设计数据结构算法 只谈数据结构不谈算法就跟去话剧院看梁山伯与祝英台结果只有梁山伯在演&#xff0c;祝英台生病了没来一样。 本文的所有内容都出自《大话数据结构》这本书中的代码实现部分&#xff0c;建议看书&#xff0c;书中比我本文写的全。 数据结构&#xff0c;直…

论文笔记——Influence Maximization in Undirected Networks

Influence Maximization in Undirected Networks ContributionMotivationPreliminariesNotations Main resultsReduction to Balanced Optimal InstancesProving Theorem 3.1 for Balanced Optimal Instances Contribution 好久没发paper笔记了&#xff0c;这篇比较偏理论&…

【笔试强训选择题】Day32.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01; 文章目录 前言 一、Da…

线性代数(应用篇):第五章:特征值与特征向量、第六章:二次型

文章目录 第5章 特征值与特征向量、相似矩阵(一) 特征值与特征向量1.定义2.性质3.求解(1)具体型矩阵试根法、多项式带余除法&#xff1a;三阶多项式分解因式 (2)抽象型矩阵 (二) 相似1.矩阵相似(1)定义(2)性质 2.相似对角化(1)定义(2)相似对角化的条件&#xff08;n阶矩阵A可相…

自动化运维工具——Ansible

自动化运维工具——Ansible 一、Ansible概述二、ansible 环境安装部署1.管理端安装 ansible2.ansible 目录结构3.配置主机清单4.配置密钥对验证 三、ansible 命令行模块1.command 模块2.shell 模块3.cron 模块4.user 模块5.group 模块6.copy 模块7.file 模块8.hostname 模块9&a…

LeetCode102.Binary-Tree-Level-Order-Traversal<二叉树的层序遍历>

题目&#xff1a; 思路&#xff1a; 写过N叉树的层序遍历&#xff0c;(8条消息) LeetCode429.N-Ary-Tree-Level-Order-Traversal&#xff1c;N 叉树的层序遍历&#xff1e;_Eminste的博客-CSDN博客 使用栈保存每一层的结点。然后每次当前层结束。将这一层的值添加进去res中。…

【Jetpack 之 Lifecycle】

Jetpack 之 Lifecycle 在本系列文章中&#xff0c;我们准备分析Jetpack 架构组件。首先我们从最基础的组件开始&#xff1a; Lifecycle&#xff0c; 可以说Jetpack 大部分架构组件都是基于Lifecycle 建立的&#xff0c;此也为Jetpack 架构组件的基础。 关于此此组件的介绍和简…

回答网友 修改一个exe

网友说&#xff1a;他有个很多年前的没有源码的exe&#xff0c;在win10上没法用&#xff0c;让俺看一下。 俺看了一下&#xff0c;发现是窗体设计的背景色的问题。这个程序的背景色用的是clInactiveCaptionText。clInactiveCaptionText 在win10之前的系统上是灰色&#xff0c;但…

【Ajax】笔记-原生jsonp跨域请求案例

原生jsonp跨域请求 输入框&#xff1a;输入后&#xff0c;鼠标移开向服务端发送请求&#xff0c;返回用户不存在(直接返回不存在&#xff0c;不做判断) JS <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><me…

ubuntu22.04 DNSSEC(加密DNS服务) configuration

/etx/systemd/resolved.conf是ubuntu下DNS解析服务配置文件&#xff0c;systemd为ubuntu下system and service配置目录 step 1——修改resolved.conf参数 管理员权限打开 /systemd/resolved.conf sudo nano /etc/systemd/resolved.conf修改如下&#xff1a; # This file i…

17-C++ 数据结构 - 栈

&#x1f4d6; 1.1 什么是栈 栈是一种线性数据结构&#xff0c;具有后进先出&#xff08;Last-In-First-Out&#xff0c;LIFO&#xff09;的特点。可以类比为装满盘子的餐桌&#xff0c;每次放盘子都放在最上面&#xff0c;取盘子时也从最上面取&#xff0c;因此最后放进去的盘…

68. 文本左右对齐

题目链接&#xff1a;力扣 解题思路&#xff1a;遍历单词数组&#xff0c;确定每一行的单词数量&#xff0c; 之后就可以得到每一个需要补充的空格数量。从而得到单词之间需要补充的空格数量。具体算法如下&#xff1a; 确定每一行的单词数量 初始值&#xff1a; num 0&…

基于springboot+mybatis+jsp日用品商城管理系统

基于springbootmybatisjsp日用品商城管理系统 一、系统介绍二、功能展示1.主页(客户)2.登陆、注册&#xff08;客户&#xff09;3.我的购物车(客户)4.我的订单&#xff08;客户&#xff09;5.我的商铺&#xff08;商家&#xff09;6.商品管理&#xff08;商家&#xff09;7.订单…

【编程规范】一文讲解开发中的命名规范

命名规范 好的代码本身就是注释, 所以我们需要统一命名风格。 ​ 在本文中&#xff0c;将从大到小&#xff0c;从外到内&#xff0c;总结Java编程中的命名规范。文中将会涉及到日常工作中常见的命名示例&#xff0c;如包命名&#xff0c;类命名&#xff0c;接口命名&#xff0c…