手写spring笔记

news/2024/9/16 17:45:50/

手写spring笔记

《Spring 手撸专栏》笔记

IoC部分

Bean初始化和属性注入

Bean的信息封装在BeanDefinition

/*** 用于记录Bean的相关信息*/
public class BeanDefinition {/*** Bean对象的类型*/private Class beanClass;/*** Bean对象中的属性信息*/private PropertyValues propertyValues;/*** 初始化方法的名称*/private String initMethodName;/*** 销毁方法的名称*/private String destroyMethodName;/*** 默认为单例模式*/private String scope;
}

Bean注入过程中有一下几个主要接口:

  • BeanFactory:Bean工厂接口,其中声明了获取Bean对象的方法
  • SingletonBeanRegistry: Bean的单例模式创建接口,声明了单例对象的创建方法和销毁方法
  • InstantiationStrategy:实例化Bean对象的策略接口,申明了Bean对象使用何种方式实例化对象的方法,在实现类中使用反射的方式获取构造方法来得到Bean对象,有JDK和Cglib两种实现
  • BeanDefinitionRegistry:管理BeanDefinition的注册,其实现类中包含存有BeanDefinition的Map

其具体流程为:
BeanDefinitionRegistry得到BeanDefinition信息,调用BeanFactorygetBean()方法,判断是否为单例模式,若为单例模式则调用SingletonBeanRegistrygetSingleton()方法,如果容器中存在Bean则直接返回,不存在则调用InstantiationStrategyinstantiate()方法,使用反射的方式生成Bean对象

在属性注入中,需要注入的属性信息封装在BeanDefinitionPropertyValues中,其本质为一个PropertyValue列表。

在创建Bean对象时,若存在无参构造方法,则使用无参构造方法,若没有,则从PropertyValues去除构造方法需要的属性。

/*** Bean对象中的属性值*/
public class PropertyValue {/*** Bean对象属性的名称*/private String name;/*** Bean对象中属性的实例化对象*/private Object value;
}

资源加载器

Spring需要解析配置文件,对此,定义了一下接口:

  • Resource:资源信息接,用于处理资源加载流,其实现类根据配置文件地址得到资源信息,并向外声明有得到输入流的接口,其包含XML文件配置和URL文件配置等方式
  • ResourceLoader:资源加载器接口,通过该接口获取路径对应的资源对象,用于获得资源对象
  • BeanDefinitionReader:BeanDefinition读取接口,用于读取配置文件并调用BeanDefinitionRegistry加载BeanDefinition

Bean生命周期

Bean的初始化操作,提供了Bean的初始化和销毁等方法接口,其包括:

  • InitializingBean:提供了初始化方法的Bean,如果Bean实现了该接口,则会在创建Bean时调用初始化方法
  • DisposableBean:提供了Bean销毁方法,若实现了该接口,则在容器销毁时调用其销毁方法

此外,在BeanDefinition中包含有initMethodNamedestroyMethodName两个属性,用于指派Bean的初始化方法和销毁方法,可以在不实现上述接口的情况下使用反射的方式实现初始化和销毁方法,在XML中配置init-methoddestroy-method两个属性即可

同时,定义有一下两个接口,来管理Bean的初始化操作

/*** Bean实例化前对其进行预处理的接口,提供修改BeanDefinition的方法*/
public interface BeanFactoryPostProcessor {/*** 所有的BeanDefinition加载完成后而Bean对象实例化之前调用,提供修改BeanDefinition的机制** @param beanFactory* @throws BeansException*/void postProcessorBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
/*** 对Bean对象初始化前后进行处理的接口,提供Bean初始化前后对其进行操作的方法*/
public interface BeanPostProcessor {/*** 在Bean对象执行初始化前对Bean实例对象进行操作** @param bean     被操作的Bean对象* @param beanName 被操作的Bean对象的名称* @return* @throws BeansException*/Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;/*** 在Bean对象执行初始化后对Bean实例对象进行操作** @param bean     被操作的Bean对象* @param beanName 被操作的Bean对象的名称* @return* @throws BeansException*/Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

Bean工厂接口

对于复杂类型的Bean,其提供了FactoryBean<T>接口,对于实现了该接口的类,spring在创建Bean对象时,不是直接生成该对象,而是调用getObject方法来生成Bean对象

/*** Bean对象的工厂接口,声明了从工厂获得Bean对象的方法*/
public interface BeanFactory {/*** 有参方式获取Bean** @param name Bean名称* @return Bean对象实例* @throws BeansException Bean创建时异常*/Object getBean(String name) throws BeansException;/*** 有参方式获取Bean** @param name Bean名称* @param args 参数* @return Bean对象实例* @throws BeansException Bean创建时异常*/Object getBean(String name, Object... args) throws BeansException;/*** 按类型获取Bean对象** @param name         Bean对象名称* @param requiredType Bean对象类型* @param <T>          Bean对象类型* @return Bean对象实例*/<T> T getBean(String name, Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;
}

Aware感知接口

对于实现了Aware接口的Bean,在spring创建实例时,会将对应的信息注入到Bean中,方便使用者对spring进行自定义扩展开发,其包括如下几类接口

  • BeanFactoryAware
  • BeanClassLoaderAware
  • BeanNameAware
  • ApplicationContextAware

事件监听机制

使用观察者模式,设置了事件监听机制

  • ApplicationEvent:继承自EventObject接口,Spring Event事件抽象类,后续的所有事件类都继承自该类
  • ApplicationListener<E extends ApplicationEvent>:继承自EventListener接口,其泛型类型为该监听器关注的事件类型
  • ApplicationEventMulticaster:事件广播器接口,定义有添加和删除监听器以及广播监听事件的方法

在使用过程中,首先调用ApplicationEventMulticasteraddApplicationListener方法将自定义监听器加入到广播器中,当要发布事件时,调用multicastEvent方法,该方法会便利已注册的所有监听器,并向关注该事件的监听器发送通知,调用其onApplicationEvent方法

应用上下文

接口ApplicationContext整合了上述的各种方法,并提供了向外的操作接口。其中,ApplicationContext的实现类中定义了核心方法refresh(),其具体内容如下:

    @Overridepublic void refresh() throws BeansException {// 创建BeanFactory,并加载BeanDefinitionrefreshBeanFactory();// 获取BeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();// 添加ApplicationContextAwareProcessor对象处理ApplicationContextAwarebeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 在Bean实例化之前,执行BeanFactoryPostProcessor方法invokeBeanFactoryPostProcessors(beanFactory);// 将BeanPostProcessor提前注册到容器中registerBeanPostProcessors(beanFactory);// 提前实例化单例Bean对象beanFactory.preInstantiateSingletons();// 初始化事件发布者initApplicationEventMulticaster();// 注册事件监听器registerListeners();// 发布容器刷新完成事件finishRefresh();}

三级缓存机制

为了解决循环依赖,spring使用了三级缓存,如下所示:

    /*** Bean容器一级缓存,用于存储Bean的完整实例化对象*/private Map<String, Object> singletonObjects = new HashMap<>();/*** Bean容器二级缓存,用于存储Bean的早期非完整实例化对象*/private Map<String, Object> earlySingletonObjects = new HashMap<>();/*** Bean容器三级缓存,用于存储Bean的代理对象*/private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();/**

其中,三级缓存存储的不是Bean对象,而是一个工厂对象,其目的是为了提早暴露Bean,等到后续的Bean依赖该Bean的时候,就会调用工厂的getObject方法获取到Bean对象。三级缓存的顺序如下:

    @Overridepublic Object getSingleton(String beanName) throws BeansException {Object singletonObject = singletonObjects.get(beanName);if (singletonObject == null) {// 如果没有完整对象,则从二级缓存中获取未完整实例化的对象singletonObject = earlySingletonObjects.get(beanName);if (singletonObject == null) {// 如果二级缓存中也没有,则从代理对象处生成未完成的实例化对象,并删除代理对象ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();earlySingletonObjects.put(beanName, singletonObject);singletonFactories.remove(beanName);}}}return singletonObject;}

注解配置信息

这里给出了一下几个注解功能的实现:

  • @Component:将类注入到容器中
  • @Autowired:对Bean对象对应的该属性进行依赖注入
  • @Scope:配置该类的作用域为单例还是原型
  • @Value:注入配置文件中的信息

通过读取配置文件中<context:component-scan />指定的路径,对其下所有的类进行扫描,若标注有@Component注解,则生成对应的BeanDefinition,并读取其属性,生成对应的PropertyValue,若属性标注有@Value注解,表示属性值为配置文件中的对应数值,若标注有@Autowired注解,则表示属性值为Bean。生成好BeanDefinition后,就和原本流程一样了

AOP

切点和匹配接口定义

AOP的核心是使用代理的方式生成代理对象,其核心接口包括:

  • ClassFilter:定义类匹配类,用于切点找到给定的接口和目标类,提供了判断切入点是否应用在给定的接口或目标类中的方法
  • MethodMatcher:方法匹配类,找到表达式范围内匹配下的目标类和方法,提供了判断给定的方法是否匹配表达式的方法
  • Pointcut:切入点接口,定义用于获取ClassFilterMethodMatcher的两个类
  • AopProxy:代理接口,用于获取代理类

使用了JDK和AspectJ两种方式实现了上述接口,并通过ProxyFactory工厂类来对两种实现的选择进行了封装

AOP融入Bean生命周期

将AOP融入Bean的声明周期,其利用了BeanPostProcessor接口,使用该接口的postProcessAfterInitialization对实例化后的原对象进行包装,返回其代理对象

其定义了Advisor访问者接口,整合切面pointcut和拦截器advice

对于反射要用的advice接口,定义了继承自该接口的BeforeAdvcice等接口,提供前置方法等AOP方法接口。同样地,对于拦截器MethodInterceptor,也封装了对应的MethodBeforeAdviceInterceptor等类,来实现各种AOP操作


http://www.ppmy.cn/news/1040025.html

相关文章

【爬虫】Requests库的使用

这个库比我们上次说的 urllib 可是要牛逼一丢丢的。通过它我们可以用更少的代码&#xff0c;模拟浏览器操作。 不多说&#xff0c;直接上手代码。 requests 常见用法 mport requests# get请求网站 r requests.get(https://www.baidu.com/) # 获取服务器响应文本内容 r.text …

虚拟拍摄,如何用stable diffusion制作自己的形象照?

最近收到了某活动的嘉宾邀请&#xff0c;我将分享&#xff1a; 主题&#xff1a;生成式人工智能的创新实践 简要描述&#xff1a;从品牌营销、智能体、数字内容创作、下一代社区范式等方面&#xff0c;分享LLM与图像等生成式模型的落地应用与实践经验。 领域/研究方向&#xff…

Linux常用命令详细大全

目录 1、查看目录与文件&#xff1a;ls2、切换目录&#xff1a;cd3、显示当前目录&#xff1a;pwd4、创建空文件&#xff1a;touch5、创建目录&#xff1a;mkdir6、查看文件内容&#xff1a;cat7、分页查看文件内容&#xff1a;more8、查看文件尾内容&#xff1a;tail9、拷贝&a…

2023河南萌新联赛第(六)场:河南理工大学-F 爱睡大觉的小C

2023河南萌新联赛第&#xff08;六&#xff09;场&#xff1a;河南理工大学-F 爱睡大觉的小C https://ac.nowcoder.com/acm/contest/63602/F 文章目录 2023河南萌新联赛第&#xff08;六&#xff09;场&#xff1a;河南理工大学-F 爱睡大觉的小C题意解题思路 题意 新学期的概…

2.SpringMvc中Model、ModelMap和ModelAndView使用详解

1.前言 最近SSM框架开发web项目&#xff0c;用得比较火热。spring-MVC肯定用过&#xff0c;在请求处理方法可出现和返回的参数类型中&#xff0c;最重要就是Model和ModelAndView了&#xff0c;对于MVC框架&#xff0c;控制器Controller执行业务逻辑&#xff0c;用于产生模型数据…

❤ 全面解析若依框架vue2版本(springboot-vue前后分离--前端部分)

❤ 解析若依框架之前台修改 1、修改页面标题和logo 修改网页上的logo ruoyi-ui --> public --> favicon.ico&#xff0c;把这个图片换成你自己的logo 修改网页标题 根目录下的vue.config.js const name process.env.VUE_APP_TITLE || ‘若依管理系统’ // 网页标题 换成…

Redis与MySQL的比较:什么情况下使用Redis更合适?什么情况下使用MySQL更合适?

Redis和MySQL是两种不同类型的数据库&#xff0c;各有自己的特点和适用场景。下面是Redis和MySQL的比较以及它们适合使用的情况&#xff1a; Redis适合的场景&#xff1a; 高性能读写&#xff1a;Redis是基于内存的快速Key-Value存储&#xff0c;读写性能非常高。它适用于需要…

神经网络基础-神经网络补充概念-56-迁移学习

迁移学习&#xff08;Transfer Learning&#xff09;是一种机器学习技术&#xff0c;旨在将在一个任务上学到的知识或模型迁移到另一个相关任务上&#xff0c;以提高新任务的性能。迁移学习的核心思想是通过利用源领域&#xff08;source domain&#xff09;的知识来改善目标领…

【SA8295P 源码分析】76 - Thermal 功耗 之 /dev/thermalmgr 相关调试命令汇总

【SA8295P 源码分析】76 - Thermal 功耗 之 /dev/thermalmgr 相关调试命令汇总 1、配置文件:/mnt/etc/system/config/thermal-engine.conf2、获取当前SOC所有温度传感器的温度:cat /dev/thermalmgr3、查看所有 Thermal 默认配置和自定义配置:echo query config > /dev/th…

自动驾驶,一次道阻且长的远征|数据猿直播干货分享

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 在6月的世界人工智能大会上&#xff0c;马斯克在致辞中宣称&#xff0c;到2023年底&#xff0c;特斯拉便可实现L4级或L5级的完全自动驾驶&#xff08;FSD&#xff09;。两个月之后&#xff0c;马斯克又在X社交平台上发言&am…

线程同步条件变量

为何要线程同步 在线程互斥中外面解决了多线程访问共享资源所会造成的问题。 这篇文章主要是解决当多线程互斥后引发的新的问题&#xff1a;线程饥饿的问题。 什么是线程饥饿&#xff1f;互斥导致了多线程对临界区访问只能改变为串行&#xff0c;这样访问临界资源的代码只能…

gromacs教程练习1

gromacs能在win上运行&#xff0c;还是个开源的软件&#xff0c;这都很值得入手学习 记录下gromacs教程的练习情况&#xff1a; Lysozyme in water 水中的溶菌酶&#xff0c;嗯&#xff0c;估计就是把蛋白处理后放在显试溶剂里跑MD这个模拟。 1、文件的准备&#xff1a; 1、…

系统架构设计师---计算机基础知识之数据库系统结构与规范化

目录 一、基本概念 二、 数据库的结构 三、常用的数据模型 概念数据模型

【Redis】Redis 的主从同步

【Redis】Redis 的主从同步 很多企业都没有使用 Redis 的集群&#xff0c;但是至少都做了主从。有了主从&#xff0c;当主节点(Master) 挂掉的时候&#xff0c;运维让从节点 (Slave) 过来接管&#xff0c;服务就可以继续&#xff0c;否则主节点需要经过数据恢复和重启的过程&a…

笔记:移植xenomai到nuc972(2)

接下来的测试,出现了两个问题 第一个问题是demo程序启动不了,这是上一篇文章忘记说的事,启动不了的原因是权限问题,提示需要root, 但我是用busybox搭的文件系统,直接就是root,不存在权限问题,所以问题出在应用上,经过一番调试后发现,问题出在xenomai的应用库上,具体位置在xen…

进行 200 瓦太阳能 (PV) 模块设计以测量太阳能光伏阵列的电压、电流和功率、综合负荷频率和电压控制系统的方法研究(Simulink实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

C++ 网络编程项目fastDFS分布式文件系统(三)-Nginx部分

目录 1. 一些基本概念 1.1 Nginx初步认识 1.2 正向/反向代理 1.3 域名和IP 2. Nginx 安装和配置 2.1 安装 2.2 配置 3. Nginx的使用 3.1 部署静态网页 3.2 反向代理和负载均衡 4 课外知识导读 1. URL和URI ​编辑 2. DNS解析过程 1. 一些基本概念 1.1 Nginx初步认…

Java进阶篇--数据结构

目录 一.数组&#xff08;Array&#xff09;&#xff1a; 1.1 特点&#xff1a; 1.2 基本操作&#xff1a; 1.3 使用数组的好处包括&#xff1a; 1.4 数组也有一些限制&#xff1a; 二.集合框架&#xff08;Collections Framework&#xff09;&#xff1a; 2.1 列表…

企业为什么会加入行业协会?

行业协会是什么 行业协会是介于政府与企业之间&#xff0c;产品制造商和经营商之间的社会性中介组织。主要为协会成员提供咨询&#xff0c;沟通&#xff0c;监督&#xff0c;协调服务。行业协会属于民间组织&#xff0c;不属于政府的管理机构&#xff0c;但是会和政府有相关合…

Springboot 封装整活 Mybatis 动态查询条件SQL自动组装拼接

前言 ps&#xff1a;最近在参与3100保卫战&#xff0c;战况很激烈&#xff0c;刚刚打完仗&#xff0c;来更新一下之前写了一半的博客。 该篇针对日常写查询的时候&#xff0c;那些动态条件sql 做个简单的封装&#xff0c;自动生成&#xff08;抛砖引玉&#xff0c;搞个小玩具&a…