Spring中使用到的设计模式及其源码分析

news2024/11/18 7:44:33

前言

众所周知,Spring框架是一个强大而灵活的开发框架。这不,上次的面试刚问到这些,没防住!!!因此下来总结一下。这篇文章主要介绍Spring中使用到的设计模式,自己做个面试复盘,同时希望能帮助到其他小伙伴儿们。

在这里插入图片描述

工厂模式

相信大家面试题都背过,Spring通过工厂模式来创建和管理Bean的实例。工厂模式主要定义了一个用于创建对象的接口,让子类决定实例化哪一个类。在Spring中,BeanFactoryApplicationContext接口是实现工厂模式的关键。

那么什么是BeanFactoryApplicationContext呢???👇👇👇

BeanFactory是Spring中最底层的容器接口,它提供了基础的依赖注入功能。ApplicationContext扩展了BeanFactory,并添加了更多高级功能,比如国际化、事件传播、资源加载等(这个也是面试重点!!!)。

我们以ApplicationContext为例,它提供了getBean(String name)方法来获取Bean实例。当调用这个方法的时候,ApplicationContext会根据配置信息创建或获取Bean实例。

	ApplicationContext context = new ClassPathXmlApplicationContext("springDemo.xml");  

	MyBean myBean = context.getBean("myBean", MyBean.class);

AbstractApplicationContextgetBean方法通过调用getBeanFactory().getBean()来实际获取Bean实例。而BeanFactory的实现类(比如DefaultListableBeanFactory)负责根据Bean的定义和依赖关系来创建和管理Bean实例。

单例模式

Spring中的Bean默认都是单例的,因此在整个Spring IoC容器中,每个Bean只会有一个实例。这是通过Bean的scope属性来进行控制的,当scopesingleton时,就表示使用单例模式。

翻阅了Spring的源码发现:👇👇👇

Spring通过DefaultSingletonBeanRegistry类中的singletonObjects(类型为ConcurrentHashMap)来管理单例Bean的实例。当请求一个Bean时,Spring会首先检查这个Map中是否已存在该Bean的实例,如果存在则直接返回,否则创建新的实例并添加到Map中。

	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);  
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {  
	    Assert.notNull(beanName, "Bean name must not be null");  
	    synchronized (this.singletonObjects) {  
	        Object singletonObject = this.singletonObjects.get(beanName);  
	        if (singletonObject == null) {  
	            // 创建新的Bean实例
	            singletonObject = singletonFactory.getObject();  
	            // 添加到单例注册表中
	            this.singletonObjects.put(beanName, singletonObject);  
	        }  
	        return singletonObject;  
	    }  
	}

代理模式

这道题相信大家都会,面试经常被问到哈哈。Spring的AOP功能中使用了代理模式。AOP通过在目标方法执行前后添加额外的行为(比如日志、事务管理这些),而这些额外的行为是通过代理对象来实现的。Spring提供了两种代理方式:JDK动态代理和CGLIB代理。

Spring的AOP实现主要在DefaultAopProxyFactory类中。这个类负责根据配置决定使用哪种代理方式,并创建代理对象。

	if (isProxyTargetClass()) {  
	    // 使用CGLIB代理  
	    return createCglibProxy(beanClassLoader, beanFactory, beanClass, beanName, targetSource, interceptedMethods, proxyTargetClass);  
	} else {  
	    // 使用JDK动态代理  
	    return createJdkDynamicProxy(beanClassLoader, beanFactory, beanClass, interfaces, interceptedMethods, proxyTargetClass);  
	}

createJdkDynamicProxy这个方法中,Spring通过Proxy.newProxyInstance方法创建一个实现了目标对象接口的代理对象,并将所有调用转发到目标对象,同时还可以在调用前后插入额外的行为。

模板方法模式

谈论到模板方法模式,相信大家都较为熟悉。比如在前面提过的AQS中也有模板方法模式的影子。

在Spring的JdbcTemplateHibernateTemplate这些类中,都使用了模板方法模式。这些类定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。

JdbcTemplate为例,它定义了如queryupdate等方法,这些方法包含了数据库操作的通用流程(打开连接、执行SQL、处理结果集、关闭连接等),而具体的SQL语句和参数则由调用者提供。

观察者模式

Spring的事件驱动模型使用了观察者模式。当某个事件发生时,所有注册为该事件监听器的对象都会收到通知,并且根据需要作出响应。

Spring的ApplicationEvent和ApplicationListener接口是实现观察者模式的关键。ApplicationEvent是事件对象,包含了事件的信息;ApplicationListener是监听器接口,定义了处理事件的方法。

public class CustomEvent extends ApplicationEvent {  
    private final String message;  
    public CustomEvent(Object source, String message) {  
        super(source);  
        this.message = message;  
    }  
  
    public String getMessage() {  
        return message;  
    }  
}  
  
// 实现监听器  
@Component  
public class CustomEventListener implements ApplicationListener<CustomEvent> {  
    @Override  
    public void onApplicationEvent(CustomEvent event) {  
        // 处理事件  
        System.out.println("Received custom event - " + event.getMessage());  
    }  
}

在Spring的AbstractApplicationContext中,通过ApplicationEventMulticaster来管理事件的发布和监听。当事件被发布时,ApplicationEventMulticaster会通知所有注册的监听器。

策略模式

策略模式在Spring中主要用于定义一系列的算法,并将每一个算法封装起来,使它们可以互相替换。相信大家看过Spring中bean的生命周期这道面试题。Spring的BeanFactoryPostProcessorBeanPostProcessor这些接口可以被视为策略模式的应用,因为它们允许开发者在Bean的创建和初始化过程中插入自定义的逻辑。

BeanFactoryPostProcessor允许在BeanFactory标准初始化之后,修改BeanFactory的内容。这个时候我们可以实现这个接口来定义自己的策略,然后在Spring的配置文件中注册这个Bean。

Spring还有一些其他的设计模式,看到这里面试以及能防得住了,后续再介绍其他的设计模式。

本篇文章到这里就结束了,感谢各位小伙伴们的支持!

在这里插入图片描述

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

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

相关文章

51单片机嵌入式开发:19、STC89C52R控制LCD1602码表+数码管+后台数显(串口)

STC89C52R控制LCD1602码表数码管后台数显&#xff08;串口&#xff09; 1 概述1.1 项目概述1.2 项目组成部分1.3 功能描述 2 开发环境2.1 支持设备2.2 硬件电路 3 软件代码工程4 演示4.1 Proteus仿真4.2 实物演示 5 总结 1 概述 1.1 项目概述 本项目旨在利用STC89C52R单片机实…

C语言程序设计结构(未完待续...)

文章目录 **C**语言设计的核心&#xff08;灵魂&#xff09;**C**语言程序设计的设计结构顺序结构选择结构循环结构 **C**语言的语句 C语言设计的核心&#xff08;灵魂&#xff09; 程序 数据结构 算法 算法&#xff1a;对于问题解决的方法思路或者步骤 算法的特征&#x…

mac|安装PostgreSQL

1、官网下载&#xff1a;EDB: Open-Source, Enterprise Postgres Database Management 选择需要的版本&#xff1a; 双击得到的.dmg文件 双击&#xff0c;弹窗选择打开&#xff0c;一路next&#xff0c;然后输入你要设置的密码&#xff0c;默认账号名字为&#xff1a;postgres…

vite构建vue3项目hmr生效问题踩坑记录

vite构建vue3项目hmr生效问题踩坑记录 hmr的好处 以下是以表格形式呈现的前端开发中HMR&#xff08;热模块替换&#xff09;带来的好处&#xff1a; 好处描述提升开发效率允许开发者在不刷新整个页面的情况下实时更新修改的代码&#xff0c;减少等待时间保持应用状态在模块替…

一起学Java(1)-新建一个Gradle管理的Java项目

一时兴起&#xff0c;也为了便于跟大家同步学习进展和分享样例代码&#xff0c;遂决定创建一个全新的Java项目&#xff0c;并通过Github与大家分享。本文就是记录该项目的创建过程以及其中的一些知识要点&#xff08;如Gradle等&#xff09;。为了紧跟技术潮流和提高操作效率&a…

怎么给PDF文件加密码?关于PDF文件加密的四种方法推荐

怎么给PDF文件加密码&#xff1f;给PDF文件加上密码是保护文件安全的一种重要方法&#xff0c;特别是当需要在不受授权的访问下保护敏感信息时。这个过程不仅仅是简单地设置密码&#xff0c;而是涉及到对文档内容和访问控制的深思熟虑。加密PDF文件可以有效防止未经授权的用户查…

electron TodoList网页应用打包成linux deb、AppImage应用

这里用的是windows的wsl的ubuntu环境 electron应用打包linux应用需要linux下打包&#xff0c;这里用windows的wsl的ubuntu环境进行操作 1&#xff09;linux ubuntu安装nodejs、electron 安装nodejs&#xff1a; sudo apt update sudo apt upgrade ##快捷安装 curl -fsSL http…

数据缺失补全方法综述

数据缺失补全方法综述 摘要1. 引言2. 数据缺失的类型3. 数据缺失补全方法3.1 简单插补方法3.1.1 均值插补3.1.2 中位数插补3.1.3 众数插补3.1.4 前向填充和后向填充3.1.5 线性插值3.1.6 多重插补 3.2 基于模型的插补方法3.2.1 线性回归插补3.2.2 加权回归插补3.2.3 主成分分析&…

如何改桥接模式

桥接模式主要是解决 路由功能的 因为NAT多层 主要是网络连接数太多时 然后路由器要好 不然光猫 比差路由要强的 光猫 请注意&#xff0c;对光猫的任何设置进行修改前&#xff0c;请一定要备份光猫的配置文件&#xff0c;并在每次修改前都截图保存原始设置信息&#xff01;不要…

Jacoco 单元测试配置

前言 编写单元测试是开发健壮程序的有效途径&#xff0c;单元测试写的好不好可以从多个指标考量&#xff0c;其中一个就是单元测试的覆盖率。单元测试覆盖率可以看到我们的单元测试覆盖了多少代码行、类、分支等。查看单元测试覆盖率可以使用一些工具帮助我们计算&#xff0c;…

pytest结合allure-pytest插件生成测试报告

目录 一、安装allure-pytest插件 二、下载allure 三、生成allure报告 四、效果展示 一、安装allure-pytest插件 二、下载allure 下载之后解压&#xff0c;解压之后还要配置环境变量&#xff08;把allure目录下bin目录配置到系统变量的path路径&#xff09;&#xff0c;下…

AcWing1维差分

输入数据a数组 a[i]a0a1a2 … \dots …anb[i]b0b1b2 … \dots …bn b1a1 b2a2-a1 … \dots … bnan-an-1 以上各式累加相消得到 b1b2 … \dots …bnan 也就是说任一an可以由b数组累加求和得到并且任一个bi加上元素c等于在an上面c。 对于区间[L,R], aLb1b2 … \dots …bL aL1…

【短视频矩阵系统源码如何构建?】

在数字化时代&#xff0c;短视频已成为信息传播的重要载体。针对这一趋势&#xff0c;短视频矩阵系统的构建应运而生&#xff0c;集混剪、发布、数据分析及线索跟进于一体&#xff0c;旨在为内容创作者和品牌提供全方位的服务支持。 系统通过混剪功能&#xff0c;能够将长视频或…

接口测试 ★ ✔【接口测试理论、http协议、接口测试文档解析、Postman使用、接口测试用例设计、Request库、UnitTest框架、】

接口测试 接口测试-第01天&#xff08;接口测试理论、HTTP协议、接口测试流程、接口文档解析&#xff09;学习⽬标能够分析HTTP协议的请求和响应数据完成ihrm系统指定接⼝的API⽂档解析接⼝测试理论概念作用 ★实现⽅式 ★HTTP协议 ★HTTP协议简介URL格式 ★练习 HTTP请求 ★整…

A Comprehensive Study of Knowledge Editing for Large Language Models

大型语言模型&#xff08;LLMs&#xff09;在理解和生成与人类交流密切相关的文本方面表现出了非凡的能力。然而&#xff0c;一个主要的限制在于训练期间的大量计算需求&#xff0c;这是由于它们的广泛参数化而产生的。世界的动态性质进一步加剧了这一挑战&#xff0c;需要经常…

Java面试八股之Spring-boot-starter-parent的作用是什么

Spring-boot-starter-parent的作用是什么 spring-boot-starter-parent 是Spring Boot项目中的一个特殊POM&#xff08;Project Object Model&#xff09;&#xff0c;它主要的作用是提供一系列默认的配置和依赖管理&#xff0c;以便简化项目的构建过程。以下是spring-boot-sta…

【Python Web】Flask扩展开发指南

Flask是一个轻量级的Python Web框架&#xff0c;它提供了丰富的扩展库和工具&#xff0c;可以帮助开发者快速构建Web应用。本篇博客将介绍如何进行Flask扩展开发&#xff0c;包括扩展的创建、配置、使用等方面的内容。 目录 Flask扩展开发指南 一、Flask扩展简介 二、创建Fl…

java面向对象进阶进阶篇--《成员、静态、局部、匿名内部类》

个人主页→VON 收录专栏→java从入门到起飞 接口和接口与抽象类综合案例 目录 一、成员内部类 特性&#xff1a; 定义方式&#xff1a; 访问规则&#xff1a; 实例化&#xff1a; 生命周期&#xff1a; 静态成员&#xff1a; 使用场景&#xff1a; 示例&#xff1a; O…

快速入门了解Ajax

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Ajax的初识 意义&#xff1a;AJAX&#xff08;Asynchronous JavaScript and…

C语言 | Leetcode C语言题解之第287题寻找重复数

题目&#xff1a; 题解&#xff1a; int findDuplicate(int* nums, int numsSize){int *b(int*)calloc(100001,sizeof(int));for(int i0;i<numsSize;i){ b[nums[i]];if(b[nums[i]]2) return nums[i];}return 0;}