手写模拟Spring的基本功能

文章目录

  • 1. Spring的基本功能
  • 2. 容器启动+ 容器启动,即创建容器对象并赋予配置对象
  • 3. BeanDefinition扫描
  • 4. Bean的生命周期
  • 5. 单例Bean与多例Bean
  • 6. 依赖注入
  • 7. AOP
  • 8. Aware 回调
  • 9. 初始化
  • 10. BeanPostProcessor
  • 附录:

1. Spring的基本功能

在这里插入图片描述

2. 容器启动+ 容器启动,即创建容器对象并赋予配置对象

// 自定义的 IOC 容器对象
GyhApplicationContext gyhApplicationContext =new GyhApplicationContext(AppConfig.class);

3. BeanDefinition扫描

  • 对于基于注解的方式,会在构造方法中扫描 @ConponentScan 的 value 值对应其下的所有类对应的 .class 文件(存在于 out 文件夹下)
  • 将 扫描到的bean信息(Class, scope)封装至 BeanDefinition 对象中并由 一个 Map (beanDefinitionMap) 保存 beanName ---> BeanDefinition

4. Bean的生命周期

在这里插入图片描述

createBean 中:

  1. 利用 Bean 的空构造器通过反射创建
  2. 设置对象属性(伴随着依赖注入)
  3. 执行前置处理器
  4. 执行初始化方法
  5. 执行后置处理器
  6. 调用使用
  7. 执行 destory 方法

5. 单例Bean与多例Bean

  • 对于 单例Bean 是在初始化容器时(扫描过程中)创建并由 一个 Map(singletonObjects)管理 beanName —> beanInstance
  • 对于 多例Bean 是在 getBean() 方法中实时创建的

6. 依赖注入

  • 在 createBean 方法中,扫描所有 bean 被 @Autowire 标注的属性为其注入容器中的 bean
  • 若当前容器中还没有所依赖bean,则会创建该bean,然后再注入

7. AOP

  • spring是基于 动态代理
  • 初始化后,通过动态代理生成实现了指定接口的代理类
  • 使用了AOP对应的 bean 会被代理类的对象所替换

8. Aware 回调

  • 对应自定义的bean的类实现了Spring中指定的 Aware接口。可以在创建 bean 的过程中被检索到,并在定制的顺序中执行 Aware接口中定义的方法(即调用bean中实现的Aware接口的方法)

9. 初始化

  • 是spring的Aware接口中的一种,spring会检索实现了 InitializationBean 接口的 Bean。在创建这些bean是会调用其实现的 afterPropertiesSet 方法

10. BeanPostProcessor

  • 后置处理器,也是Aware回调接口中的一种,其定义的前置与后置方法会被用在所有bean的创建过程中

附录:

GyhApplicationContext

package com.gyh.spring;import com.gyh.service.UserService;import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @author Gao YongHao* @version 1.0* 模拟Spring的javaConfig的容器启动方式*/public class GyhApplicationContext {private Class<?> configClass;// 用于保存Bean对象的信息(class 对象, 作用域信息)private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();// 用于保存单例的对象private ConcurrentHashMap<String, Object> singletonObjects =new ConcurrentHashMap<>();// 用于保存 BeanPostProcessor 的集合private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();public GyhApplicationContext(Class<?> configClass) {this.configClass = configClass;// 扫描,单例的对象被直接创建,多例的对象在使用时创建if (configClass.isAnnotationPresent(ComponentScan.class)) {ComponentScan annotation = configClass.getAnnotation(ComponentScan.class);String packagePath = annotation.value(); // 扫描路径 "com.gyh.service"packagePath = packagePath.replace(".", "/");// 在 out 文件夹中定位 .class 文件的路径ClassLoader classLoader = GyhApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(packagePath);File file = new File(resource.getFile());
//            System.out.println(file);// 如果是文件夹if (file.isDirectory()) {File[] files = file.listFiles();for (File f : files) {String absolutePath = f.getAbsolutePath();// 筛选出 .class 结尾的字节码文件if (absolutePath.endsWith(".class")) {String loadClassPath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));loadClassPath = loadClassPath.replace("\\", ".");// loadClassPath == "com\gyh\service\UserService"
//                        System.out.println(loadClassPath);try {// 利用类加载器加载指定文件夹下的 .class 文件Class<?> aClass = classLoader.loadClass(loadClassPath);// 查看是否有标注 Bean 对应的的注解if (aClass.isAnnotationPresent(Component.class)) {// 扫描出实现了 BeanPostProcessor 的 bean,将其实例化对象放置于 集合 中if (BeanPostProcessor.class.isAssignableFrom(aClass)) {beanPostProcessors.add((BeanPostProcessor) aClass.newInstance());}// 设置的Bean名称(若为""或null)则设置为首字母小写的类名String beanName = aClass.getAnnotation(Component.class).value();if ("".equals(beanName)) {beanName = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);}// 创建保存Bean信息的对象BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(aClass); // 该对象类型if (aClass.isAnnotationPresent(Scope.class)) {Scope annotation1 = aClass.getAnnotation(Scope.class);String value = annotation1.value();beanDefinition.setScope(value);} else { // 默认是单例的beanDefinition.setScope("Singleton");}// 放置于 beanDefinitionMap 中管理beanDefinitionMap.put(beanName, beanDefinition);}// 填充单例对象for (Map.Entry<String, BeanDefinition> s : beanDefinitionMap.entrySet()) {BeanDefinition value = s.getValue();if (value.getScope().equals("Singleton")) {// 存有依赖注入的单例对象生成singletonObjects.put(s.getKey(), createBean(s.getKey(), value));}}} catch (Exception e) {e.printStackTrace();}}}}}}/*** 创建Bean对象,** @param beanName       bean 对象名称* @param beanDefinition bean 对象的信息* @return*/public Object createBean(String beanName, BeanDefinition beanDefinition) {Class<?> type = beanDefinition.getType();Object o = null;try {o = type.getConstructor().newInstance();// 依赖注入// 遍历属性对属性进行依赖注入for (Field f : type.getDeclaredFields()) {if (f.isAnnotationPresent(Autowired.class)) {f.setAccessible(true); // 关闭访问权限// 将容器中管理的bean注入到该属性中(可能先于当前类创建,也可能后于当前类创建)f.set(o, getBean(beanName, type));}}// 回调机制,查看当前的Bean是否实现了指定的接口// 如果实现则执行相关方法(BeanPostProcessor即是如此实现)if (o instanceof BeanNameAware) {((BeanNameAware) o).setBeanName(beanName);}for(BeanPostProcessor b:beanPostProcessors){b.beforePostProcess(beanName, o);}// 初始化也使用回调实现// 基于AOP会在后置处理器中创建 bean 的动态代理对象,并封装切面逻辑for(BeanPostProcessor b:beanPostProcessors){b.afterPostProcess(beanName, o);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return o;}/*** 用于返回 Bean 对象的方法** @param beanName Bean 的名称* @param clazz    Bean 对应的 Class 对象* @param <T>* @return*/public <T> T getBean(String beanName, Class<T> clazz) {BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (beanDefinition == null) {throw new NullPointerException();} else {String scope = beanDefinition.getScope();if (scope.equals("Singleton")) {// 从单例池中获取对象Object o = singletonObjects.get(beanName);if (o == null) { // 对应依赖注入时可能会用到o = createBean(beanName, beanDefinition);singletonObjects.put(beanName, o); // 放入单例池中}return (T) o;} else { // 多例则实时创建Object o = null;try {o = beanDefinition.getType().newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return (T) o;}}}
}

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

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

相关文章

VSCode图标的含义,以及DataLoader代码的使用

1 问题 vscode中的那些图标的含义分别是什么Dataloader代码怎么做 2 方法 去网站里面搜索各种图形代表的含义然后进行理解和记忆 长方体&#xff1a;变量 紫色立方体&#xff1a; 库中预定义的枚举&#xff1a; 两个矩形块&#xff1a;枚举 自定义的枚举 橙色树状结构&#xff…

LinkedList和链表(上)

1. 顺序表ArrayList的缺点和优点 优点: 1> 在给定下标进行查找的时候,时间复杂度是O(1) 缺点: 1> 插入数据必须移动其他数据,最坏情况下,插入到0位置,时间复杂度为O(N) 2> 删除数据也需要移动数据,最坏情况下,就是删除0位置.时间复杂度为O(N) 3> 扩容之后(1.5倍扩容…

SQL JOIN的学习

SQL JOIN (w3school.com.cn) 之前跟着老师学数据库的时候学过&#xff0c;最近又比较频繁的在使用。 再复习一下。 Id_P是主键 Id_O是主键 1. SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons, Orders WHERE Persons.Id_P Orders.Id_P 2. SEL…

【JVM】—深入理解G1回收器——概念详解

深入理解G1回收器——概念详解 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; 文章目录 深入理解G1回收器…

保护企业终端安全,天锐DLP帮助企业智能管控终端资产

为有效预防员工非法调包公司的软硬件终端资产&#xff0c;企业管理员必须建立高效的企业终端安全管控机制&#xff0c;确保能够即时洞察并确认公司所有软硬件资产的状态变化。这要求企业要有一套能够全面管理终端资产的管理系统&#xff0c;确保任何未经授权的资产变动都能被迅…

Shiro认证 -- (Authentication)

Apache Shiro是一个功能强大的Java安全框架&#xff0c;提供了身份验证&#xff08;Authentication&#xff09;、授权&#xff08;Authorization&#xff09;、加密&#xff08;Cryptography&#xff09;、会话管理&#xff08;Session Management&#xff09;、与Web集成、缓…

【WEB应用安全测试指南–蓝队安全测试2】--超详细-可直接进行实战!!!亲测-可进行安全及渗透测试

安全基础理论入门知识参考上一篇《WEB应用安全测试指南蓝队安全测试1》 WEB应用安全测试指南2 一、文件 I/O 类1.1、任意文件上传1.2、任意文件下载1.3、文件包含 二、接口安全类2.1、短信炸弹2.2、邮件炸弹2.3、短信内容可控2.4、邮件内容可控 三、逻辑流程类3.1、越权3.2、未…

深度学习论文: EfficientCrackNet: A Lightweight Model for Crack Segmentation

深度学习论文: EfficientCrackNet: A Lightweight Model for Crack Segmentation EfficientCrackNet: A Lightweight Model for Crack Segmentation PDF: https://arxiv.org/pdf/2409.18099v1 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https:/…

红日安全vulnstack (一)

目录 环境搭建 本机双网卡 Kali IP 靶机IP Web GetShell 前期信息收集 Yxcms后台模板 Getshell PHPMyAdmin日志 Getshell into outfile写入一句话 X phpmyadmin 日志写入一句话 后渗透 MSF 生成木马上线 提取用户hash值 **hash**加密方式 MSF权限Shell至CS CS …

光标在单词中间,如何通过快捷键选择当前单词?

工具》选项>环境》键盘 &#xff1a;把应用修改成visual studio 6或者 visual assist就可以了

IO编程--单字符、字符串、格式化、模块化实现文件拷贝以及登录注册

一、完成标准io的单字符、字符串、格式化、模块化实现两个文件的拷贝 代码如下&#xff1a; 1.单字符 #include <myhead.h> int main(int argc, const char *argv[]) {//打开文件FILE* fpfopen("test.txt","r"); FILE* fqfopen("copy_test.txt&…

第九课:Python学习之函数基础

函数基础 目标 函数的快速体验函数的基本使用函数的参数函数的返回值函数的嵌套调用在模块中定义函数 01. 函数的快速体验 1.1 快速体验 所谓函数&#xff0c;就是把 具有独立功能的代码块 组织为一个小模块&#xff0c;在需要的时候 调用函数的使用包含两个步骤&#xff…

基于GRNN广义回归网络和MFCC的语音情绪识别matlab仿真,对比SVM和KNN

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) filePath Test_data\悲伤1.wav 类型&#xff1a;悲伤 识别置信度 Vmax 0.9559 2.算法运行软件版本 matlab2022a 3.部…

Vue2路由

1.路由 1.1.Vue路由基础 Vue属于单页应用&#xff08;SPA&#xff09;&#xff0c;即整个应用程序中只有一个html页面。 在单页应用中&#xff08;SPA&#xff09;&#xff0c;由于只是更改DOM来模拟多页面&#xff0c;所以页面浏览历史记录的功能就丧失了。此时&#xff0c…

nextjs项目中,使用postgres的完整案例

目的 通过此案例&#xff0c;可以简单快速的过一下数据库的操作&#xff0c;熟悉app-router这种模式下&#xff0c;client component和server component的两种组件中基本的接口使用。 技术栈 nextjs14.2.* app-routervercel/postgres0.10.*typescript5 重要事情说三遍1 ap…

uni-app写的微信小程序如何体积太大如何处理

方法一&#xff1a;对主包进行分包处理&#xff0c;将使用url: /pages/components/equipment/equipment跳转页面的全部拆分为分包&#xff0c;如url: /pagesS/components/equipment/equipment 在pages.json中添加 "subPackages": [{ "root"…

antd样式修改

1.Tab添加竖线 .ant-tabs .ant-tabs-tab {&::before {position: absolute;top: 50%;inset-inline-end: 0;width: 1px;height: 24px;background-color: #e1e1e1;transform: translateY(-50%);transition: background-color 0.2s;content: "";}} 像这样&#xff…

基于SSM的药品商城系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

科研绘图系列:R语言柱状图(histogram)

文章目录 介绍加载R包数据画图系统信息介绍 柱状图(Bar Chart),也称为条形图(Bar Graph),是一种常用的统计图表,用于展示不同类别的数据量。它由一系列垂直或水平的条形组成,每个条形的长度或高度代表相应类别的数值大小。 加载R包 library(tidyverse)# 显示中文 li…

增量知识 (Incremental Knowledge, IK)

在语义通信系统中&#xff0c;增量知识&#xff08;IK, Incremental Knowledge&#xff09;是一种增强数据传输效率和可靠性的技术&#xff0c;特别是用于混合自动重传请求&#xff08;HARQ, Hybrid Automatic Repeat reQuest&#xff09;机制时。它的核心思想是在传输失败后&a…