Spring4-IoC3-手写IoC

Spring框架的IoC是基于Java反射机制实现的

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息

要想解剖一个类,必须先要获取到该类的Class对象,而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect,所以,Class对象是反射的根源

package com.qcby;import org.junit.Test;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class TestCar {//1.获取Class对象多种方式@Testpublic void test01() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1)类名.classClass<Car> clazz1 = Car.class;//2)对象.getClass()Class clazz2 = new Car().getClass();//3.Class.forName("全路径")Class clazz3 = Class.forName("com.qcby.Car");//实例化Car car = (Car) clazz3.getDeclaredConstructor().newInstance();System.out.println(car);}//2.获取构造方法@Testpublic void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<Car> clazz = Car.class;//获取所有public的构造方法
//        Constructor[] constructors = clazz.getConstructors();//获取所有构造方法(public、private)Constructor[] constructors = clazz.getDeclaredConstructors();for (Constructor c : constructors) {System.out.println("名称:"+c.getName()+" 参数个数:"+c.getParameterCount());}//指定有参构造创造对象//1)构造方法是public
//        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
//        Car car1 = (Car) c1.newInstance("奥迪", 10, "黑色");
//        System.out.println(car1);//2)构造privateConstructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);c2.setAccessible(true); //允许访问私有构造Car car2 = (Car) c2.newInstance("宝马", 10, "白色");System.out.println(car2);}//3.获取属性@Testpublic void test03() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class clazz = Car.class;Car car = (Car) clazz.getDeclaredConstructor().newInstance();//获取所有public属性
//        Field[] fields = clazz.getFields();//获取所有属性(包含私有属性)Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if(field.getName().equals("name")){//设置允许访问field.setAccessible(true);field.set(car,"五菱宏光");}System.out.println(field.getName());System.out.println(car);}}//4.获取方法@Testpublic void test04() throws InvocationTargetException, IllegalAccessException {Car car = new Car("奔驰",10,"黑色");Class clazz = car.getClass();//1)public方法Method[] methods = clazz.getMethods();for (Method method : methods) {
//            System.out.println(method.getName());//执行方法if(method.getName().equals("toString")){String invoke = (String) method.invoke(car);System.out.println("toString执行了:"+invoke);}}//2)private方法Method[] methods1 = clazz.getDeclaredMethods();for (Method method : methods1) {//执行方法if(method.getName().equals("run")){method.setAccessible(true);method.invoke(car);}}}}

手写IoC

1.创建子模块spring-ioc

2.创建测试类 service dao

3.创建两个注解

  • @Bean 创建对象
  • @Di 属性注入

4.创建bean容器接口 ApplicationContext

  • 定义方法
  • 返回对象

5.实现bean容器接口

  • 返回对象
  • 根据包规则加载bean

扫描com.qcby这个包和它的子包里面的所有类,看类上面是否有@Bean注解,如果有则把这个类通过反射实例化

package com.qcby.dao;public interface UserDao {void add();
}
package com.qcby.dao.impl;import com.qcby.anno.Bean;
import com.qcby.dao.UserDao;
import org.springframework.stereotype.Repository;@Bean
public class UserDaoImpl implements UserDao {@Overridepublic void add() {System.out.println("dao...");}
}
package com.qcby.service;public interface UserService {void add();
}
package com.qcby.service.impl;import com.qcby.anno.Bean;
import com.qcby.anno.Di;
import com.qcby.dao.UserDao;
import com.qcby.service.UserService;
import org.springframework.stereotype.Service;@Bean
public class UserServiceImpl implements UserService {@Diprivate UserDao userDao;@Overridepublic void add() {System.out.println("service...");//调用dao的方法userDao.add();}
}
package com.qcby.bean;public interface ApplicationContext {Object getBean(Class clazz);
}
package com.qcby.anno;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 Bean {
}
package com.qcby.anno;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 Di {
}
package com.qcby.bean;import com.qcby.anno.Bean;
import com.qcby.anno.Di;import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class AnnotationApplicationContext implements ApplicationContext{//创建一个map集合,放bean对象private Map<Class,Object> beanFactory = new HashMap<>();private static String rootPath;@Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}//设置包扫描规则//当前包及其子包,哪个类有@Bean注解,把这个类通过反射实例化public AnnotationApplicationContext(String basePackage) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {//1.把.替换成\String packagePath = basePackage.replaceAll("\\.", "\\\\");//2.获取包的绝对路径Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);while (urls.hasMoreElements()){URL url = urls.nextElement();String filePath = URLDecoder.decode(url.getFile(), "utf-8");//获取包前面路径部分,字符串截取rootPath = filePath.substring(0, filePath.length() - packagePath.length());//包扫描loadBean(new File(filePath));}//属性注入loadDi();}//包扫描过程,实例化private void loadBean(File file) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1.判断当前是否是文件夹if(file.isDirectory()){//2.获取文件夹里的所有内容File[] childrenFiles = file.listFiles();//3.判断文件夹里面为空,直接返回if(childrenFiles == null || childrenFiles.length == 0){return;}//4.如果文件夹不为空,遍历文件夹所有内容for (File child : childrenFiles) {//1)遍历得到每个File对象,继续判断,如果还是文件夹,递归if(child.isDirectory()){loadBean(child);}else {//2)遍历得到File对象不是文件夹,是文件//3)得到包路径+类名称部分  字符串截取String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);//4)判断当前文件类型是否是.classif(pathWithClass.contains(".class")){//5)如果是.class类型,把路径\替换成.,把.class去掉String allName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");//6)判断类上是否有注解@Bean,如果有,实例化过程//6.1获取类的ClassClass<?> clazz = Class.forName(allName);//6.2判断不是接口,实例化if(!clazz.isInterface()){//6.3判断类上面是否有注解@BeanBean annotation = clazz.getAnnotation(Bean.class);if(annotation != null){//6.4实例化Object instance = clazz.getConstructor().newInstance();//7)把对象实例化之后,放到map集合beanFactory//7.1判断当前类如果有接口,让接口class作为map的keyif (clazz.getInterfaces().length>0){beanFactory.put(clazz.getInterfaces()[0],instance);}else {beanFactory.put(clazz,instance);}}}}}}}}//属性注入private void loadDi() throws IllegalAccessException {//实例化对象在beanFactory的map集合里面//1.遍历beanFactory的map集合Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();for (Map.Entry<Class, Object> entry : entries) {//2.获取map集合每个对象(value),每个对象属性获取到Object obj = entry.getValue();//获取对象ClassClass<?> clazz = obj.getClass();//获取每个对象属性Field[] declaredFields = clazz.getDeclaredFields();//3.遍历得到每个对象属性数组,得到每个属性for (Field field : declaredFields) {//4.判断属性上面是否有@Di注解Di annotation = field.getAnnotation(Di.class);if(annotation != null){//私有属性,设置:可以设置值field.setAccessible(true);//5.如果有@Di注解,把对象进行设置(注入)field.set(obj,beanFactory.get(field.getType()));}}}}}

测试:

package com.qcby;import com.qcby.bean.AnnotationApplicationContext;
import com.qcby.bean.ApplicationContext;
import com.qcby.service.UserService;import java.io.IOException;
import java.lang.reflect.InvocationTargetException;public class TestUser {public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {ApplicationContext context =new AnnotationApplicationContext("com.qcby");UserService userService = (UserService) context.getBean(UserService.class);System.out.println(userService);userService.add();}
}

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

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

相关文章

学习大数据DAY57 新的接口配置

作业  完成 API 接口和文件的接入, 并部署到生产调度平台, 每个任务最后至少 要有两条 不报错 的日志, 报错就驳回作业  作业不需要复制日志 API Appliation Program Interface 应用程序接口 > JSON 的地址 客户需求: 把 https://zhiyun.pub:9099/site/c-class…

【QT】定时器使用

文章目录 关于 Qt 定时器使用的注意细节总结实例-检查工具使用周期时间是否合理UI设计头文件 remind.h源文件 remind.cpp实现效果 关于 Qt 定时器使用的注意细节总结 一、创建与初始化 使用 QTimer 类来创建定时器。可以在构造函数中指定父对象&#xff0c;确保定时器在正确的…

电子电气架构——中央计算的软件定义汽车架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

台风,也称为热带气旋,是一种在热带海洋上形成的强烈风暴系统。台风的形成需要满足以下几个条件:

台风&#xff0c;也称为热带气旋&#xff0c;是一种在热带海洋上形成的强烈风暴系统。台风的形成需要满足以下几个条件&#xff1a; 1. **温暖的海水**&#xff1a;台风通常在海面温度至少达到26.5C&#xff08;79.7F&#xff09;的海域形成&#xff0c;因为温暖的海水能够提供…

XShell快速连接虚拟机(Ubuntu系统)

目录 前言 一 (XShell)(虚拟机 )(Ubuntu)下载 二 虚拟机的ip查找 三 虚拟机中安装连接环境 四 开启ssh-server服务 五 验证是Ubuntu是否开启ssh-server服务 六 连接XShell软件 前言 对于刚开始探索 Linux 世界的新手来说&#xff0c;拥有一台自己的服务器可能并不现实。幸运的…

学习大数据DAY58 增量抽取数据表

作业 1 SQL 优化的常见写法有哪些 - 面试经常被问 使用索引&#xff1a;合理创建和使用索引是提高查询效率的关键。索引可以加速数据的检 索速度&#xff0c;但是索引也会占用额外的存储空间&#xff0c;并且在插入、删除和更新操作时会 有额外的开销。 避免全表扫描&…

【ARM】中断术语介绍

外设产生中断给到gic&#xff0c;gic通过内部判断此中断是FIQ还是IRQ&#xff0c;这个过程就称为assert&#xff08;断言&#xff09; 此中断被发到哪里面去叫target cpu跳转到此中断的中断向量表中叫做taken 整个过程就做routing distribute决定将中断发给哪个cpu&#xff08…

【STM32】DAC数字模拟转换

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 前言 DAC简介 DAC配置 DAC时钟使能 GPIO初始化 DAC配置 DAC使能 读写DAC值 驱动代码 MyDAC.h MyDAC.c main.c 前言 大容量的STM32F101xx和STM32F103xx产品才有DAC外设 大容量…

基于SpringBoot的在线考试系统【附源码】

基于SpringBoot的在线考试系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1 系统概述 4.2系统功能结构设计 4.3.2 数据库表结构设计 5 系统实现 5.1管理员功能介绍 5.1.1管理员登录 5.1.2 试卷管理 5.1.3 公告信息管理 5.1.…

_Array类,类似于Vector,其实就是_string

例子&#xff1a; using namespace lf; using namespace std;int main() {_Array<int> a(10, -1);_Array<_string> s { _t("one"), _t("two") };_pcn(a);_pcn(s);} 结果&#xff1a; 源代码_Array.h&#xff1a; /***********************…

基础物理-直线运动2

2-1 位置、位移和平均速度 位置与位移 为了确定物体的位置&#xff0c;通常需要相对于某个参考点来测量&#xff0c;这个参考点通常是某个坐标轴的原点&#xff08;或零点&#xff09;&#xff0c;如图 2-1 中的 x 轴。坐标轴的正方向是坐标增大的方向&#xff0c;在图 2-1 中…

掌握远程管理的艺术:揭秘Python的pywinrm库

文章目录 &#x1f525; 掌握远程管理的艺术&#xff1a;揭秘Python的pywinrm库 &#x1f525;背景&#xff1a;为何选择pywinrm&#xff1f;pywinrm库简介安装pywinrm库简单库函数使用方法场景应用常见问题与解决方案总结 &#x1f525; 掌握远程管理的艺术&#xff1a;揭秘Py…

【ARM】Cache深度解读

Cache的基本概念和使用场景 不同的Master硬件共享数据时—invalid cache 外设和DDR之间没有cache&#xff0c;所以外设直接把数据写入DDR中&#xff0c;但是cpu和DDR之间有cache&#xff0c;cpu会首先访问cache&#xff0c;如果命中直接从cache中拿数据&#xff0c;但是此时的…

浪潮信息首推3秒智能控温!告别服务器开机噪音

在当前的数据中心运维实践中&#xff0c;运维人员在部署服务器时常被“飞机起飞”般的开机噪音所困扰。服务器刚刚接通电源&#xff0c;其内部元件尚处于预热待命状态&#xff0c;而风扇却已全速运转&#xff0c;这不仅加剧了噪音污染&#xff0c;还拖慢了启动速度&#xff0c;…

[数据集][目标检测]智慧交通铁路人员危险行为躺站坐检测数据集VOC+YOLO格式3766张4类别

图片数量(jpg文件个数)&#xff1a;3766 标注数量(xml文件个数)&#xff1a;3766 标注数量(txt文件个数)&#xff1a;3766 标注类别数&#xff1a;4 标注类别名称:["sitting","sleeping","standing","track"] 每个类别标注的框数&…

OpenCore Legacy Patcher 2.0.0 发布,83 款不受支持的 Mac 机型将能运行最新的 macOS Sequoia

在不受支持的 Mac 上安装 macOS Sequoia (OpenCore Legacy Patcher v2.0.0) Install macOS on unsupported Macs 请访问原文链接&#xff1a;https://sysin.org/blog/install-macos-on-unsupported-mac/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主…

《深度学习》PyTorch 手写数字识别 案例解析及实现 <下>

目录 一、回顾神经网络框架 1、单层神经网络 2、多层神经网络 二、手写数字识别 1、续接上节课代码&#xff0c;如下所示 2、建立神经网络模型 输出结果&#xff1a; 3、设置训练集 4、设置测试集 5、创建损失函数、优化器 参数解析&#xff1a; 1&#xff09;para…

一篇文章带你入门机器学习 Part1 -->Machine Learning from Scratch

学习网站&#xff1a;Machine Learning from Scratch Machine Learning from Scratch (Part1神经网络&#xff09; 神经网络——Neural Networks神经网络是如何工作的&#xff1f;训练神经网络 神经网络——Neural Networks 在人工神经网络的背景下&#xff1a;一个神经元是一…

全面理解tensor编程中矩阵的行和列

经常会在编程中遇到理解矩阵行和列的事情。 1、要明确无论这个张量有多少维度&#xff0c;它的矩阵乘法都只能作用于最后两个维度。 例如&#xff1a; import torcha torch.rand([64, 32, 3, 4]) b torch.rand([64, 32, 3, 4])c torch.matmul(a, b.transpose(2, 3)) # 交…

备战软考Day02-数据结构与算法

1.基本概念与三要素 1.什么是数据 数据是信息的载体&#xff0c;是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。数据是计算机程序加工的原料。 2.数据元素、数据项 数据元素是数据的基本单位&#xff0c;通常作为一个整体进行…