java-spring 图灵 02 手写spring

01.idea中创建一个maven管理的空项目
在这里插入图片描述
02.模拟创建出spring容器类,这里叫wzpApplicationContext,创建的时候会自动加载配置类的数据

public class wzpApplicationContext {private Class configClass;public wzpApplicationContext(Class configClass) {this.configClass = configClass;}
}

模拟出容器类要扫描的配置类Appconfig

public class Appconfig {
}

在test中去测试这些创建的类

public class Mytest {public static void main(String[] args) {wzpApplicationContext wzpApplicationContext=new wzpApplicationContext(Appconfig.class);
}
}

03.在wzpApplicationContext 添加getbean函数,获取spring容器中的bean

  public Object getBean(String beanName) {return null;}

创建服务类UserService

public class UserService {
}

在这里插入图片描述

在测试test中运行getbean方法

public class Mytest {public static void main(String[] args) {wzpApplicationContext wzpApplicationContext=new wzpApplicationContext(Appconfig.class);UserService userService=   (UserService)wzpApplicationContext.getBean("UserService");
}
}

04.在服务类中写一些方法,等会看一下是不是可以运行

public class UserService {public void test(){System.out.println("test");}
}

此时在test中:

public class Mytest {public static void main(String[] args) {wzpApplicationContext wzpApplicationContext=new wzpApplicationContext(Appconfig.class);UserService userService=   (UserService)wzpApplicationContext.getBean("UserService");userService.test();}}

05.写几个自定义的注解
比如说,spring容器中的扫描,需要注解@ComponentScan
在这里插入图片描述

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {String value() default "";
}

解释一下:
Target 注解是说,这个注解主要用在哪一个区域,TYPE表示类,FIELD表示属性,METHOD表示方法。
Rentention 注解是说,这个注解在那个阶段使用,RUNTIME是在类加载阶段使用

然后模仿spring去用:

@ComponentScan("org.example.wzp.service")
public class Appconfig {}

再创建一个注解:@Component

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {String value() default "";
}

在服务类中去使用:

@Component
public class UserService {public void test(){System.out.println("test");}
}

06.实现扫描的功能
现在只是写了几个注解,具体的功能代码还没有写,接下来就是扫描的代码
回想spring框架,是创建spring容器的时候,就会自动创建bean
所以,扫描的具体实现代码就应该在构造函数中写

//判断类上是不是有注解ComponentScanif(configClass.isAnnotationPresent(ComponentScan.class)){//获取注解对象ComponentScan componentScan = (ComponentScan)configClass.getAnnotation(ComponentScan.class);//获取注解对象上的value,这里也就是pathString path = componentScan.value();//文件的路径是/,而获取到的是带有.的包名path=path.replace(".","/");//获取当前的类加载器ClassLoader classLoader = wzpApplicationContext.class.getClassLoader();//根据类加载器获取编译完成的target的class文件夹的路径URL resource = classLoader.getResource(path);//根据路径,获取文件File file=new File(resource.getFile());//因为扫描的是包,所以大概率是一个目录if (file.isDirectory()){//获取目录中的文件集合for (File f:file.listFiles()){//获取文件的绝对路径String absolutePath = f.getAbsolutePath();//截取从org到classString org = absolutePath.substring(absolutePath.indexOf("org"), absolutePath.indexOf(".class"));//由于是文件路径,要转换回来,把\变成 . 包名,好让类加载器加载得到类的对象String classpath = org.replace("\\", ".");//加载器加载后,得到一个类对象Class<?> aClass = classLoader.loadClass(classpath);//判断是不是类上存在Component注解if(aClass.isAnnotationPresent(Component.class)){//判断是不是单例模式,要看自定义的注解Scopeif (aClass.isAnnotationPresent(Scope.class)){Scope scopeAnnotation = aClass.getAnnotation(Scope.class);String value = scopeAnnotation.value();if (value.equals("singleton")){//创建单例模式的bean}else{//多例模式}}}}}}}

创建一个注解 Scope

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {String value() default "";
}

在服务类上使用,如果是单例,就写singleton,如果是多例,就写prototype

例如:服务类UserService ,这里声明是单例模式

@Component("UserService")
@Scope("singleton")
public class UserService {public void test(){System.out.println("test");}
}

07.优化设计,把类上注解的许多信息都放入到一个对象中的话,直接去读取这个类的属性就好了

创建一个BeanDefinition

public class BeanDefinition {private Class type;private String scope;private Boolean isLazy;public Class getType() {return type;}public void setType(Class type) {this.type = type;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}public Boolean getLazy() {return isLazy;}public void setLazy(Boolean lazy) {isLazy = lazy;}}

再次优化扫描

 //判断是不是类上存在Component注解if(aClass.isAnnotationPresent(Component.class)){Component componentAnnotation = aClass.getAnnotation(Component.class);String name = componentAnnotation.value();BeanDefinition beanDefinition=new BeanDefinition();beanDefinition.setType(aClass);//判断是不是单例模式,要看自定义的注解Scopeif (aClass.isAnnotationPresent(Scope.class)){Scope scopeAnnotation = aClass.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);if (value.equals("singleton")){//创建单例模式的beanbeanDefinition.setScope("singleton");}else{//多例模式}}}

在wzpApplicationContext 中添加一个属性,map集合

public class wzpApplicationContext {
//配置类private Class configClass;
//存放BeanDefinitionprivate Map<String,BeanDefinition> BeanDefinitionMap =new HashMap<>();}

把刚刚创建的BeanDefinition放入到map集合中:

if(aClass.isAnnotationPresent(Component.class)){Component componentAnnotation = aClass.getAnnotation(Component.class);String name = componentAnnotation.value();BeanDefinition beanDefinition=new BeanDefinition();beanDefinition.setType(aClass);//判断是不是单例模式,要看自定义的注解Scopeif (aClass.isAnnotationPresent(Scope.class)){Scope scopeAnnotation = aClass.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);if (value.equals("singleton")){//创建单例模式的beanbeanDefinition.setScope("singleton");}else{//多例模式}BeanDefinitionMap.put(name,beanDefinition);}}

最后总的代码抽象此外一个方法:
在这里插入图片描述

   public wzpApplicationContext(Class configClass) throws ClassNotFoundException {this.configClass = configClass;//判断类上是不是有注解ComponentScanscan(configClass);}private void scan(Class configClass) throws ClassNotFoundException {if(configClass.isAnnotationPresent(ComponentScan.class)){//获取注解对象ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);//获取注解对象上的value,这里也就是pathString path = componentScan.value();//文件的路径是/,而获取到的是带有.的包名path.replace(".","/");//获取当前的类加载器ClassLoader classLoader = wzpApplicationContext.class.getClassLoader();//根据类加载器获取编译完成的target的class文件夹的路径URL resource = classLoader.getResource(path);//根据路径,获取文件File file=new File(resource.getFile());//因为扫描的是包,所以大概率是一个目录if (file.isDirectory()){//获取目录中的文件集合for (File f:file.listFiles()){//获取文件的绝对路径String absolutePath = f.getAbsolutePath();//截取从org到classString org = absolutePath.substring(absolutePath.indexOf("org"), absolutePath.indexOf(".class"));//由于是文件路径,要转换回来,把\变成 . 包名,好让类加载器加载得到类的对象String classpath = org.replace("\\", ".");//加载器加载后,得到一个类对象Class<?> aClass = classLoader.loadClass(classpath);//判断是不是类上存在Component注解if(aClass.isAnnotationPresent(Component.class)){Component componentAnnotation = aClass.getAnnotation(Component.class);String name = componentAnnotation.value();BeanDefinition beanDefinition=new BeanDefinition();beanDefinition.setType(aClass);//判断是不是单例模式,要看自定义的注解Scopeif (aClass.isAnnotationPresent(Scope.class)){Scope scopeAnnotation = aClass.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);if (value.equals("singleton")){//创建单例模式的beanbeanDefinition.setScope("singleton");}else{//多例模式}BeanDefinitionMap.put(name,beanDefinition);}}}}}}

08.扫描完了,开始写createbean方法了
在扫描之后调用:
用for循环

public class wzpApplicationContext {private Class configClass;private Map<String,BeanDefinition> BeanDefinitionMap =new HashMap<>();public wzpApplicationContext(Class configClass) throws ClassNotFoundException {this.configClass = configClass;//判断类上是不是有注解ComponentScanscan(configClass);for (Map.Entry<String, BeanDefinition> entry : BeanDefinitionMap.entrySet()){BeanDefinition beanDefinition = entry.getValue();String beanName = entry.getKey();if (beanDefinition.getScope().equals("singleton")){//在这里调用createbean,创建单例Object bean=  createBean(beanName,beanDefinition);}}
}

09.在wzpApplicationContext 创建createBean

  private Object createBean(String beanName, BeanDefinition beanDefinition) {return null;}

10.创建的bean要保存到容器

在wzpApplicationContext 创建一个属性 Map<String,Object> singletonObjectsMap,这个用来保存创建的单例bean

  //保存单例的地方,Map集合private Map<String,Object> singletonObjectsMap =new HashMap<>();

此时的for循环

 for (Map.Entry<String, BeanDefinition> entry : BeanDefinitionMap.entrySet()){BeanDefinition beanDefinition = entry.getValue();String beanName = entry.getKey();if (beanDefinition.getScope().equals("singleton")){//创建单例Object  bean=  createBean(beanName,beanDefinition);//保存单例到容器中 singletonObjectsMap.put(beanName,bean);}}

11.什么时候调用这个getbean方法

先从BeanDefinitionMap获取已经扫描完了beanDefinition,如果有的话,那表示在扫描的包中,有这个类,再判断是不是单例模式,如果没有的话,那就说明没有这样的类,抛出异常。

  public Object getBean(String beanName) throws Exception {if (!BeanDefinitionMap.containsKey(beanName)){throw new NullPointerException();}BeanDefinition beanDefinition = BeanDefinitionMap.get(beanName);if (beanDefinition.getScope().equals("singleton")){//单例}else{//原型}return null;}

这里是获取bean,单例从容器中获取

singletonObjectsMap.get(beanName)

原型(多例)就马上创建一个bean

createBean(beanName, beanDefinition);

这个时候的getBean方法

    public Object getBean(String beanName) throws Exception {if (!BeanDefinitionMap.containsKey(beanName)){throw new NullPointerException();}BeanDefinition beanDefinition = BeanDefinitionMap.get(beanName);if (beanDefinition.getScope().equals("singleton")){//单例return     singletonObjectsMap.get(beanName);}else{//原型Object bean = createBean(beanName, beanDefinition);return bean;}}

12.如何创建bean呢,用反射 newInstance()

   private Object createBean(String beanName, BeanDefinition beanDefinition) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class clazz = beanDefinition.getType();Object o = clazz.getConstructor().newInstance();return o;}

13.测试
在这里插入图片描述
14.创建一个多例

@Component("OrderService")
@Scope("prototype")
public class OrderService
{
}
public class Mytest {public static void main(String[] args) throws Exception {wzpApplicationContext wzpApplicationContext=new wzpApplicationContext(Appconfig.class);UserService userService=   (UserService)wzpApplicationContext.getBean("UserService");System.out.println((UserService)wzpApplicationContext.getBean("UserService"));System.out.println((UserService)wzpApplicationContext.getBean("UserService"));System.out.println((UserService)wzpApplicationContext.getBean("UserService"));System.out.println((OrderService)wzpApplicationContext.getBean("OrderService"));System.out.println((OrderService)wzpApplicationContext.getBean("OrderService"));System.out.println((OrderService)wzpApplicationContext.getBean("OrderService"));userService.test();}}

在这里插入图片描述

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

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

相关文章

【Qt 学习笔记】QWidget的windowOpacity属性 | cursor属性 | font属性

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ QWidget的windowOpacity属性 | cursor属性 | font属性 文章编号&#…

解决 MSYS2 Qt 6.7 默认 stylesheet 在 windows 11 下的显示故障

项目场景&#xff1a; MSYS2 升级到 Qt6.7.0&#xff0c;发现显示故障&#xff0c;所有Qt6程序以及 QtCreator的SpinBox都显示不全&#xff0c;Combox的底色不对。 问题描述 2024年4月1日&#xff0c;pacman升级MSYS2后&#xff0c;Qt6遇到风格错误。 msys环境&#xff1a; …

ThingsBoard实现告警规则创建并生成报警信息

一、概述 1.概念 2.告警规则 3.简单报警条件 步骤1. 打开设置配置 ​步骤2. 单击警报规则 ​步骤3. 单击警报条件 ​步骤4. 单击过滤条件 ​步骤5. 选择数据键 ​步骤6. 设置条件 ​步骤7. 保存条件 ​步骤8. 应用更改 4.测试告警 1、使用MQTT发送遥测属性 2、查看…

数据结构:双向链表

一.双向链表的结构 最常用的链表就是单链表和双向链表。我们首先要知道&#xff0c;链表有八种分类。单链表是不带头单向不循环链表。而此篇博客要讲的是带头双向循环链表。 结构如下&#xff1a; 注意&#xff1a;带头链表里的头节点&#xff0c;实际为“哨兵位”&#xff0…

【python】python饮料销售数据分析可视化(源码+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

机器人瓶胚检测工作站(H3U脉冲轴控制)

1、变量定义 2、程序监控1 2、 程序监控2 3、程序监控3 机器人输送料和机构的动作安全尤为重要&#xff0c;下面我们讨论下安全联锁控制逻辑 4、相机拍照触发信号 5、相机拍照触发时序

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测 目录 回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测预测效果基本介绍程序设计参考资料预测效果 基本介绍

【SpringBoot】获取参数

获取参数 传递单个参数传递多个参数传递对象后端参数重命名传递数组传递 json 数据获取 URL 中参数上传文件获取 cookie 和 session获取cookie获取session 传递单个参数 RequestMapping("/user") RestController public class UserController {// 传递单个参数Reque…

简单好用的SaaS知识库工具都在这了,看完赶紧收藏!

在信息飞速发展的今天&#xff0c;企业如何有效地管理海量的信息和知识成为了提高工作效率的关键。SaaS知识库工具正成为企业寻求的解决方案&#xff0c;它们不仅能够帮助团队组织文档&#xff0c;而且优化知识分享流程。现在就让我们来看看市场上几款简单又好用的SaaS知识库工…

华为云配置安全组策略开放端口

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C &#x1f525;座右铭&#xff1a;“不要等到什么都没有了&#xff0c;才下…

C语言 | 内存函数memcpy,memmove,memset,memcmp

目录&#xff1a; 1. memcpy使用和模拟实现 2. memmove使用和模拟实现 3. memset函数的使用 4. memcmp函数的使用 头文件&#xff1a;<string.h> 1. memcpy使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); • 从source的…

【CPA考试】2024注册会计师报名照片尺寸要求解读及手机拍照方法

随着2024年注册会计师考试的临近&#xff0c;众多会计专业人士和学生都开始准备报名参加这一行业的重要考试&#xff0c;报名时间为4月8日至4月30日。报名过程中&#xff0c;一张符合要求的证件照是必不可少的。本文将为您详细解读2024年注册会计师考试报名照片的尺寸要求&…

Git以及Gitlab的快速使用文档

优质博文&#xff1a;IT-BLOG-CN 安装git 【1】Windows为例&#xff0c;去百度下载安装包。或者去官网下载。安装过秳返里略过&#xff0c;一直下一步即可。丌要忉记设置环境发量。 【2】打开cmd&#xff0c;输入git –version正确输出版本后则git安装成功。 配置ssh Git和s…

C++ 之 【类与对象】 从入门到精通一条龙服务 进阶篇(类的6个默认成员函数,构造,析构。。。)

以后把闹钟换成唢呐&#xff0c;醒了就起床&#xff0c;不醒就上天堂 一、类的6个默认成员函数 二、构造函数 1.概念 2.特性 三、析构函数 1.概念 2.特性 四、拷贝构造函数 1.概念 2.特征 五、赋值运算符重载 1.运算符重载 2.赋值运算符重载 3.前置和后置重载 六…

rancher踩坑日志:prometheus访问kubelet 10250端口提示鉴权失败

该原因是因为kubectl禁止了非授权用户访问10250端口来获取node的数据。 解决思路&#xff1a; 添加prometheus访问kubelet时带上证书进行验证匹配 --> 由于我的prometheus是rancher安装的&#xff0c;不知道要怎么修改所以研究了一会没研究明白就放弃了。设置prometheus访问…

关于Ribbon在SpringCloudAlibaba2021.1版本中,找不到服务实例

关于Ribbon在SpringCloudAlibaba2021.1版本中&#xff0c;找不到服务实例 放个妹子 SpringCloudAlibaba在2021.1版本中,spring-cloud-starter-alibaba-nacos-discovery默认已经移除了ribbon模块 手动加上spring-cloud-starter-netflix-ribbon依赖后&#xff0c;项目能正常启动…

如何将CSDN的文章以PDF文件形式保存到本地

1.F12 打开开发者工具窗口 2.console下输入命令 (function(){$("#side").remove();$("#comment_title, #comment_list, #comment_bar, #comment_form, .announce, #ad_cen, #ad_bot").remove();$(".nav_top_2011, #header, #navigator").remove…

蓝桥杯 前一晚总结 模板 新手版

《准备实足&#xff0c;冲冲冲 省一》https://www.yuque.com/lenyan-svokd/hi7hp2/hfka297matrtsxy2?singleDoc# 《准备实足&#xff0c;冲冲冲 省一》 #include<bits/stdc.h> // 包含标准库头文件using namespace std; using ll long long; // 定义 long long 数据类…

iOS开发如何更改xcode中的Apple ID

在Xcode中更改Apple ID是一项常见的任务&#xff0c;尤其是当你需要切换到另一个开发者账号或者团队时。下面是一个简单的步骤指南&#xff0c;帮助你更改Xcode中的Apple ID&#xff1a; 步骤一&#xff1a;退出当前的Apple ID 1.打开Xcode应用程序。 2.在菜单栏中&#xff0c;…

Spring Validation解决后端表单校验

NotNull&#xff1a;从前台传递过来的参数不能为null,如果为空&#xff0c;会在控制台日志中把message打印出来 Range&#xff1a;范围&#xff0c;最大多少&#xff0c;最小多少 Patten&#xff0c;标注的字段值必须符合定义的正则表达式&#xff08;按照业务规则&#xff0…