当前位置: 首页 > news >正文

mini-spring源码分析

IOC模块

关键解释

beanFactory:beanFactory是一个hashMap, key为beanName, Value为 beanDefination

beanDefination:

BeanDefinitionRegistry,BeanDefinition注册表接口,定义注册BeanDefinition的方法

beanReference:增加BeanReference类,包装一个bean对另一个bean的引用。实例化beanA后填充属性时,若PropertyValue#value为BeanReference,引用beanB,则先去实例化beanB。 由于不想增加代码的复杂度提高理解难度,暂时不支持循环依赖,后面会在高级篇中解决该问题

Resource:

BeanFactoryPostProcessor和BeanPostProcessor是spring框架中具有重量级地位的两个接口,理解了这两个接口的作用,基本就理解spring的核心原理了。为了降低理解难度分两个小节实现。

BeanFactoryPostProcessor是spring提供的容器扩展机制,允许我们在bean实例化之前修改bean的定义信息即BeanDefinition的信息。其重要的实现类有PropertyPlaceholderConfigurer和CustomEditorConfigurer,PropertyPlaceholderConfigurer的作用是用properties文件的配置值替换xml文件中的占位符,CustomEditorConfigurer的作用是实现类型转换。BeanFactoryPostProcessor的实现比较简单,看单元测试BeanFactoryPostProcessorAndBeanPostProcessorTest#testBeanFactoryPostProcessor追下代码。

BeanPostProcessor也是spring提供的容器扩展机制,不同于BeanFactoryPostProcessor的是,BeanPostProcessor在bean实例化后修改bean或替换bean。BeanPostProcessor是后面实现AOP的关键

//在bean实例化之前,执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);

然后重写beanFactory方法,对入参beanFactory进行interface 重写。

应用上下文ApplicationContext是spring中较之于BeanFactory更为先进的IOC容器,ApplicationContext除了拥有BeanFactory的所有功能外,还支持特殊类型bean如上一节中的BeanFactoryPostProcessor和BeanPostProcessor的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等。

BeanFactory是spring的基础设施,面向spring本身;而ApplicationContext面向spring的使用者,应用场合使用ApplicationContext。

具体实现查看AbstractApplicationContext#refresh方法即可。注意BeanFactoryPostProcessor和BeanPostProcessor的自动识别,这样就可以在xml文件中配置二者而不需要像上一节一样手动添加到容器中了。

ApplicationContext把使用者的步骤打包了

getBeanOfType 

@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {Map<String, T> result = new HashMap<>();beanDefinitionMap.forEach((beanName, beanDefinition) -> {Class beanClass = beanDefinition.getBeanClass();if (type.isAssignableFrom(beanClass)) {T bean = (T) getBean(beanName);result.put(beanName, bean);}});return result;
}

ApplicationContext容器提供了完善的事件发布和事件监听功能。

ApplicationEventMulticaster接口是注册监听器和发布事件的抽象接口,AbstractApplicationContext包含其实现类实例作为其属性,使得ApplicationContext容器具有注册监听器和发布事件的能力。在AbstractApplicationContext#refresh方法中,会实例化ApplicationEventMulticaster、注册监听器并发布容器刷新事件ContextRefreshedEvent;在AbstractApplicationContext#doClose方法中,发布容器关闭事件ContextClosedEvent。

support 比较实现类的CustomEvent

这是一种很好的泛型写法,可以运行时反射到(调用方发现是ApplicatonListerner,  使用方可以通过CustomEvent告诉兴趣事件。)

AOP引入

关键概念

Joinpoint,织入点,指需要执行代理操作的某个类的某个方法(仅支持方法级别的JoinPoint);Pointcut是JoinPoint的表述方式,能捕获JoinPoint。

最常用的切点表达式是AspectJ的切点表达式。需要匹配类,定义ClassFilter接口;匹配方法,定义MethodMatcher接口。PointCut需要同时匹配类和方法,包含ClassFilter和MethodMatcher,AspectJExpressionPointcut是支持AspectJ切点表达式的PointCut实现,简单实现仅支持execution函数。

AopProxy是获取代理对象的抽象接口,JdkDynamicAopProxy的基于JDK动态代理的具体实现。TargetSource,被代理对象的封装。MethodInterceptor,方法拦截器,是AOP Alliance的"公民",顾名思义,可以拦截方法,可在被代理执行的方法前后增加代理行为。

JDK实现

Advisor是Pointcut和Advice的组合
public class DynamicProxyTest {@Testpublic void testJdkDynamicProxy() throws Exception {WorldService worldService = new WorldServiceImpl();AdvisedSupport advisedSupport = new AdvisedSupport();TargetSource targetSource = new TargetSource(worldService);WorldServiceInterceptor methodInterceptor = new WorldServiceInterceptor();MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* org.springframework.test.service.WorldService.explode(..))").getMethodMatcher();advisedSupport.setTargetSource(targetSource);advisedSupport.setMethodInterceptor(methodInterceptor);advisedSupport.setMethodMatcher(methodMatcher);WorldService proxy = (WorldService) new JdkDynamicAopProxy(advisedSupport).getProxy();proxy.explode();}
}

三级缓存singletonFactories里的对象里面有getObject里面会调用wrapifnessary,在这里会创建新的代理对象,如果二级缓存的话,会存在引用不相等的问题。

	protected Object wrapIfNecessary(Object bean, String beanName) {//避免死循环if (isInfrastructureClass(bean.getClass())) {return bean;}Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();try {ProxyFactory proxyFactory = new ProxyFactory();for (AspectJExpressionPointcutAdvisor advisor : advisors) {ClassFilter classFilter = advisor.getPointcut().getClassFilter();if (classFilter.matches(bean.getClass())) {TargetSource targetSource = new TargetSource(bean);proxyFactory.setTargetSource(targetSource);proxyFactory.addAdvisor(advisor);proxyFactory.setMethodMatcher(advisor.getPointcut().getMethodMatcher());}}if (!proxyFactory.getAdvisors().isEmpty()) {return proxyFactory.getProxy();}} catch (Exception ex) {throw new BeansException("Error create proxy bean for: " + beanName, ex);}return bean;}

基于CGLIB的动态代理实现逻辑也比较简单,查看CglibAopProxy。与基于JDK的动态代理在运行期间为接口生成对象的代理对象不同,基于CGLIB的动态代理能在运行期间动态构建字节码的class文件,为类生成子类,因此被代理类不需要继承自任何接口。

public class DynamicProxyTest {private AdvisedSupport advisedSupport;@Beforepublic void setup() {WorldService worldService = new WorldServiceImpl();advisedSupport = new AdvisedSupport();TargetSource targetSource = new TargetSource(worldService);WorldServiceInterceptor methodInterceptor = new WorldServiceInterceptor();MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* org.springframework.test.service.WorldService.explode(..))").getMethodMatcher();advisedSupport.setTargetSource(targetSource);advisedSupport.setMethodInterceptor(methodInterceptor);advisedSupport.setMethodMatcher(methodMatcher);}@Testpublic void testCglibDynamicProxy() throws Exception {WorldService proxy = (WorldService) new CglibAopProxy(advisedSupport).getProxy();proxy.explode();}
}
		// 使用JDK动态代理advisedSupport.setProxyTargetClass(false);WorldService proxy = (WorldService) new ProxyFactory(advisedSupport).getProxy();proxy.explode();// 使用CGLIB动态代理advisedSupport.setProxyTargetClass(true);proxy = (WorldService) new ProxyFactory(advisedSupport).getProxy();proxy.explode();

增加AOP代理工厂ProxyFactory,由AdvisedSupport#proxyTargetClass属性决定使用JDK动态代理还是CGLIB动态代理(引用还是一样的)

如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP

每层缓存的意义

第三级缓存是个lamdba表达式值捕获bean引用 ,进行advisor判断,然后进行代理升级。

getBeansByType

Application refresh

	@Overridepublic void refresh() throws BeansException {//创建BeanFactory,并加载BeanDefinitionrefreshBeanFactory();ConfigurableListableBeanFactory beanFactory = getBeanFactory();//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知beanbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//在bean实例化之前,执行BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);//BeanPostProcessor需要提前与其他bean实例化之前注册registerBeanPostProcessors(beanFactory);//初始化事件发布者initApplicationEventMulticaster();//注册事件监听器registerListeners();//注册类型转换器和提前实例化单例beanfinishBeanFactoryInitialization(beanFactory);//发布容器刷新完成事件finishRefresh();}

//在bean实例化之前,执行BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(beanFactory);

	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {// 接口的妙用,用接口判断,然后传入beanMap,接口进行处理,和上面泛型接口刚好服务方和调用者做了一个翻转。beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);}}

拓展篇

TODO三级缓存,和

类型转换服务bean

spring在org.springframework.core.convert.converter包中定义了三种类型转换器接口:Converter、ConverterFactory、GenericConverter。

Converter<S,T>接口适合一对一的类型转换,如果要将String类型转换为Ineger/Long/Float/Double/Decimal等类型,就要实现一系列的StringToInteger/StringToLongConverter/StringToFloatConverter转换器,非常不优雅。

ConverterFactory接口则适合一对多的类型转换,可以将一种类型转换为另一种类型及其子类。比如将String类型转换为Ineger/Long/Float/Double/Decimal等Number类型时,只需定义一个ConverterFactory转换器:

做成一个服务的factoryBean

为了方便使用,提供了创建ConversionService的FactoryBean——ConversionServiceFactoryBean。

如果有定义ConversionService,在AbstractApplicationContext#finishBeanFactoryInitialization方法中设置到容器中。

  • 为bean填充属性时,见AbstractAutowireCapableBeanFactory#applyPropertyValues
  • 处理@Value注解时,见AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

多切面AOP

组装advisor key可以进行缓存,但最好用method作为key

MethodInvocation只是简单的将拦截器链的所有拦截器一一执行,最后再触发当前的method方法。这是很简单高效的方法,但问题是我们希望某些增强比如AfterReturningAdvice能够在方法执行完才被执行,这就涉及到不同增强的执行顺序的问题了。而MethodInvocation显然没有考虑顺序的问题,一个AfterReturningAdvice很可能在BeforeAdvice之前被调用。那么该如何保证顺序问题呢?

答案是,控制增强的调用顺序其实由每个拦截器负责,所以我们需要分析MethodBeforeAdviceInterceptorAfterReturningAdviceInterceptor

但是代理的顺序不同还是会影响返回值,但是相对于一次的方法位置是符合预期的。

三级缓存实现

三级缓存解决问题是解决三个转态转换的状态机(用于单例bean) 1.属性填充完成 2.代理完成对象 3.bean定义(lamdba表达式)

也是一种可重入的判断

也是共享引用的思想

解决有代理对象时的循环依赖问题,需要提前暴露代理对象的引用,而不是暴露实例化后的bean的引用(这是上节的遗留问题的原因,应该提前暴露A的代理对象的引用)。

spring中用singletonFactories(一般称第三级缓存)解决有代理对象时的循环依赖问题。在实例化后提前暴露代理对象的引用(见AbstractAutowireCapableBeanFactory#doCreateBean方法第6行)。

getBean()时依次检查一级缓存singletonObjects、二级缓存earlySingletonObjects和三级缓存singletonFactories中是否包含该bean。如果三级缓存中包含该bean,则挪至二级缓存中,然后直接返回该bean。见AbstractBeanFactory#getBean方法第1行。

protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {Object bean;try {bean = createBeanInstance(beanDefinition);//为解决循环依赖问题,将实例化后的bean放进缓存中提前暴露if (beanDefinition.isSingleton()) {Object finalBean = bean;addSingletonFactory(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {return getEarlyBeanReference(beanName, beanDefinition, finalBean);}});}//实例化bean之后执行boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);if (!continueWithPropertyPopulation) {return bean;}//在设置bean属性之前,允许BeanPostProcessor修改属性值applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);//为bean填充属性applyPropertyValues(beanName, bean, beanDefinition);//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}//注册有销毁方法的beanregisterDisposableBeanIfNecessary(beanName, bean, beanDefinition);Object exposedObject = bean;if (beanDefinition.isSingleton()) {//如果有代理对象,此处获取代理对象exposedObject = getSingleton(beanName);addSingleton(beanName, exposedObject);}return exposedObject;}

相关文章:

mini-spring源码分析

IOC模块 关键解释 beanFactory&#xff1a;beanFactory是一个hashMap, key为beanName, Value为 beanDefination beanDefination: BeanDefinitionRegistry&#xff0c;BeanDefinition注册表接口&#xff0c;定义注册BeanDefinition的方法 beanReference&#xff1a;增加Bean…...

RVO动态避障技术方案介绍

原文&#xff1a;RVO动态避障技术方案介绍 - 哔哩哔哩 我们在开发游戏的时候经常会遇到这样的问题&#xff0c;当我们寻路的时候&#xff0c;其它人也在寻路&#xff0c;如何避免不从其它人的位置穿过。这个叫做动态避障&#xff0c;目前主流的解决方案就是RVO。本节我们来介绍…...

HTML CSS JS基础考试题与答案

一、选择题&#xff08;2分/题&#xff09; 1&#xff0e;下面标签中&#xff0c;用来显示段落的标签是&#xff08; d &#xff09;。 A、<h1> B、<br /> C、<img /> D、<p> 2. 网页中的图片文件位于html文件的下一级文件夹img中&#xff0c;…...

【C语言】二叉树(BinaryTree)的创建、3种递归遍历、3种非递归遍历、结点度的实现

代码主要实现了以下功能&#xff1a; 二叉树相关数据结构定义 定义了二叉树节点结构体 BiTNode&#xff0c;包含节点数据值&#xff08;字符类型&#xff09;以及指向左右子树的指针。 定义了顺序栈结构体 SqStack&#xff0c;用于存储二叉树节点指针&#xff0c;实现非递归遍历…...

MySQL Workbench 数据库建模详解:从设计到实践

目录 数据库建模基础概念MySQL Workbench 简介与安装 什么是 MySQL Workbench&#xff1f;安装与环境配置 MySQL Workbench 数据库建模功能详解 EER 图&#xff08;实体关系图&#xff09;数据库反向工程数据库正向工程模型同步与版本管理 MySQL Workbench 数据库建模实战教程…...

【字体】Fire Code连字效果开启

Vscode 开启方法 1、设置字体Fire Code 放在最前面的即可&#xff1a; 2、启用连字 继续往下找到“在 settings.json 中编辑”&#xff0c;然后设置"editor.fontLigatures": true &#xff1a; 保存即可。 Sublime 开启方法 设置中设置字体后&#xff0c;启…...

springboot kafka在kafka server AUTH变动后consumer自动销毁

前言 笔者使用了kafka用来传输数据&#xff0c;笔者在今年10月写了文章&#xff0c;怎么使用配置化实现kafka的装载&#xff1a;springboot kafka多数据源&#xff0c;通过配置动态加载发送者和消费者-CSDN博客 不过在实际运行中&#xff0c;kafka broker是加密的&#xff0c…...

第六届国际科技创新(IAECST 2024)暨第四届物流系统与交通运输(LSTT 2024)

重要信息 会议官网&#xff1a;www.lstt.org 大会时间&#xff1a;2024年12月6-8日 大会地点&#xff1a;中国-广州 简介 第六届国际科技创新暨第四届物流系统与交通运输国际&#xff08;LSTT 2024&#xff09;将于2024年12月6-8日在广州举办&#xff0c;这是一个集中探讨…...

【Vue3】【Naive UI】< a >标签

【Vue3】【Naive UI】< a >标签 超链接及相关属性其他属性 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c;n-button&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c;a&#xff1e; 标签 <a> 标签HTML中的一个锚&…...

Fortran mpi在Linux的安装

最近编译一个程序需要需要 Fortran mpi 编译器&#xff0c;则需要安装 Fortran编辑器和MPI库&#xff0c;以下是具体的安装步骤&#xff1a; 一、安装 Fortran 编译器&#xff08;gfortran&#xff09; 在conda环境中安装&#xff1a; conda install -c conda-forge gfortra…...

蓝桥-希尔排序模板题

第一眼看到这个题还在想希尔排序模板不记得了&#xff0c;于是去网上了搜了一个&#xff0c;但是考虑到这种题只看测试点能不能通过&#xff0c;于是用Arrays方法试了一下&#xff0c;发现也可以。 1.希尔排序模板ac代码 package yunkePra;import java.util.Scanner;public cl…...

深入学习指针(5)!!!!!!!!!!!!!!!

文章目录 1.回调函数是什么&#xff1f;2.qsort使用举例2.1使用qsort函数排序整形数据2.2使用sqort排序结构数据 3.qsort函数的模拟实现 1.回调函数是什么&#xff1f; 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递…...

windows 应用 UI 自动化实战

UI 自动化技术架构选型 UI 自动化是软件测试过程中的重要一环&#xff0c;网络上也有很多 UI 自动化相关的知识或资料&#xff0c;具体到 windows 端的 UI 自动化&#xff0c;我们需要从以下几个方面考虑&#xff1a; 开发语言 毋庸置疑&#xff0c;在 UI 自动化测试领域&am…...

nodejs相关知识介绍

1、nodejs官方文档&#xff1a; https://nodejs.org/zh-cn nodejs可以用nvm进入安装&#xff1b; 2、npm说明&#xff1a; npm官方教程&#xff1a;https://npm.p2hp.com/ npm是 Node.js 的标准包管理器&#xff0c;也就是说nodejs安装好&#xff0c;npm也就安装好了&#…...

How to monitor Spring Boot apps with the AppDynamics Java Agent

本文介绍如何使用 AppDynamics Java 代理监视 Azure Spring Apps 中的 Spring Boot 应用程序。 使用 AppDynamics Java 代理可以&#xff1a; 监视应用程序使用环境变量配置 AppDynamics Java 代理 在 AppDynamics 仪表板中检查所有监视数据 How to monitor Spring Boot app…...

安装SQL Server 2022提示需要Microsoft .NET Framework 4.7.2 或更高版本

安装SQL Server 2022提示需要Microsoft .NET Framework 4.7.2 或更高版本。 原因是&#xff1a;当前操作系统版本为Windows Server 2016 Standard版本&#xff0c;其自带的Microsoft .NET Framework 版本为4.6太低&#xff0c;不满足要求。 根据报错的提示&#xff0c;点击链接…...

TypeScript核心语法(5)——函数

简介​ 函数的类型声明&#xff0c;需要在声明函数时&#xff0c;给出参数的类型和返回值的类型。 function hello(a: string): void {console.log("hello " txt); } 上面示例中&#xff0c;函数hello()在声明时&#xff0c;需要给出参数a的类型&#xff08;stri…...

【MyBatis】验证多级缓存及 Cache Aside 模式的应用

文章目录 前言1. 多级缓存的概念1.1 CPU 多级缓存1.2 MyBatis 多级缓存 2. MyBatis 本地缓存3. MyBatis 全局缓存3.1 MyBatis 全局缓存过期算法3.2 CacheAside 模式 后记MyBatis 提供了缓存切口&#xff0c; 采用 Redis 会引入什么问题&#xff1f;万一遇到需强一致场景&#x…...

ARIMA-神经网络混合模型在时间序列预测中的应用

ARIMA-神经网络混合模型在时间序列预测中的应用 1. 引言 1.1 研究背景与意义 时间序列预测在现代数据科学中扮演着越来越重要的角色。从金融市场的价格走势到工业生产的需求预测,从气象数据的天气预报到用电量的负荷预测,时间序列分析无处不在。传统的统计方法和现代深度学习…...

Scala关于成绩的常规操作

score.txt中的数据&#xff1a; 姓名&#xff0c;语文&#xff0c;数学&#xff0c;英语 张伟&#xff0c;87&#xff0c;92&#xff0c;88 李娜&#xff0c;90&#xff0c;85&#xff0c;95 王强&#xff0c;78&#xff0c;90&#xff0c;82 赵敏&#xff0c;92&#xff0c;8…...

【Maven】项目创建

3. Maven的应用 本章主要内容&#xff1a; 使用 Maven 创建 JavaSE 项目使用 Maven 创建 JavaWeb 项目&#xff0c;在本地部署 Tomcat 测试导入 Maven 项目 3.1 基于Maven开发JavaSE的项目 3.1.1 流程 1、File—>new—>Project—>Empty Project Location&#xff1…...

基于 LlamaFactory 的 LoRA 微调模型支持 vllm 批量推理的实现

背景 LlamaFactory 的 LoRA 微调功能非常便捷&#xff0c;微调后的模型&#xff0c;没有直接支持 vllm 推理&#xff0c;故导致推理速度不够快。 LlamaFactory 目前支持通过 VLLM API 进行部署&#xff0c;调用 API 时的响应速度&#xff0c;仍然没有vllm批量推理的速度快。 …...

Vue进阶之单组件开发与组件通信

书接上篇&#xff0c;我们了解了如何快速创建一个脚手架&#xff0c;现在我们来学习如何基于vite创建属于自己的脚手架。在创建一个新的组件时&#xff0c;要在新建文件夹中打开终端创建一个基本的脚手架&#xff0c;可在脚手架中原有的文件中修改或在相应路径重新创建&#xf…...

HCIE IGP双栈综合实验

实验拓扑 实验需求及解法 本实验模拟ISP网络结构&#xff0c;R1/2组成国家骨干网&#xff0c;R3/4组成省级网络&#xff0c;R5/6/7组成数据中 心网络。 配置所有ipv4地址&#xff0c;请自行测试直连。 R1 sysname R1 interface GigabitEthernet0/0/0ip address 12.1.1.1 255.…...

Unity 超链接文本类

注&#xff1a;该脚本在文本显示不全时会有问题。 HyperlinkText.cs using System; using System.Text; using System.Collections.Generic; using System.Text.RegularExpressions; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems;namespace MYT…...

Vim小白学习指南

博客 Vim编辑器简介 Vim是一个非常高效的文本编辑器&#xff0c;最初源于Vi编辑器。它以其强大的文本编辑能力和快捷键而闻名于程序员和系统管理员。Vim的特别之处在于它提供了多种模式&#xff0c;每种模式都有不同的功能。 Vim的基本模式 1. 普通模式&#xff08;Normal …...

【微服务】Nacos配置管理

一、统一配置管理 1、配置统一管理 2、微服务获取配置 ①引入Nacos的配置管理客户端依赖(usersevice下) <!--nacos的配置管理依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-confi…...

从单机缓存到分布式缓存那些事

作者&#xff1a;秦怀 1 缓存前世今生 1.1 故事从硬件开始 Cache 一词来源于 1967 年的一篇电子工程期刊论文。其作者将法语词“cache”赋予“safekeeping storage”的涵义&#xff0c;用于电脑工程领域。当时没有 Cache&#xff0c;CPU 和内存都很慢&#xff0c;CPU 直接访…...

华为新手机和支付宝碰一下 带来更便捷支付体验

支付正在变的更简单。 11月26日&#xff0c;华为新品发布会引起众多关注。发布会上&#xff0c;华为常务董事余承东专门提到&#xff0c;华为Mate 70和Mate X6折叠屏手机的“独门支付秘技”——“碰一下”&#xff0c;并且表示经过华为和支付宝的共同优化&#xff0c;使用“碰…...

element ui select绑定的值是对象的属性时,显示异常.

需要声明 value-key"value",如果还不行可能是数据类型不一致数字0和字符串0是不一致的. el-select v-model"value" clearable placeholder"Select" value-key"value" style"width: 240px"><!-- <el-option v-for&…...

基于Springboot开发的时光兼职网

一、功能介绍 时光兼职网包含管理员、用户、商家三个角色以及前后台系统。 前台系统功能 首页、兼职信息推荐、查看更多等 职位申请、申请日期、上传简历、点击下载简历、留言反馈等 个人中心、上传图片、更新信息等 后台系统功能 用户登录&#xff1a; 个人中心、修改密码…...

Vue3 Ts 如何获取组件的类型

vue3 Ts ref 子组件 1、默认写法 typeof&#xff1a;获取ts类型 InstanceType&#xff1a;获取模版的实例 <tempolate><myComponent ref"myCompRef"> </tempolate><script setup lang"ts"> import { ref } from "vue&quo…...

Unity类银河战士恶魔城学习总结(P146 Delete Save file-P147 Encryption of save data删除数据和加密数据)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了快速删除存档和加密存档 以下是加密前和加密后的对比 SaveManager.cs using System.Collections; using System.Collection…...

Uniapp 使用自定义字体

技术栈&#xff1a;Uniapp 简介 为了更好的还原UI图片效果&#xff0c;往往需要使用特殊字体&#xff0c;引入字体包。 因实际业务运行平台在微信小程序上&#xff0c;对发布包的项目文件大小有限制&#xff0c;项目中某些比较大的静态资源需要放在服务器上来远程加载&#x…...

Scala

统计成绩练习 1.计算每个同学的总分和平均分 2.统计每个科目的平均分 3.列出总分前三名和单科前三名&#xff0c;并保存结果到文件中 解题思路如下&#xff1a; 1.读入txt文件&#xff0c;按行读入 2.处理数据 &#xff08;1&#xff09;计算每个同学的总分…...

fnOS中安装HAOS,集成haier

只作为自己记录重要事项&#xff0c;不做详细教程。大致流程 安装飞牛OS&#xff0c;简称fnosfnos中有集成Docker在docker中安装haos在haos中安装hacs在hacs中添加haier 在docker中安装haos 安装好fnos后&#xff0c;docker里面找到haos&#xff0c;里面下载最多的&#xff0c…...

基于群晖搭建个人图书架-TaleBook based on Docker

前言 在群晖Container Manager中部署失败&#xff0c;转通过ssh部署。 一、准备工作 名称备注群晖SSH“终端机和SNMP”中启用SSH软件secureCRT等docker-compose.ymlGithub下载并修改 二、过程 2.1 创建本地文件夹 本地路径为&#xff1a; /docker/Calibre/data 2.2 下载d…...

spring导出多个文件,要求打包成压缩包

背景 业务要求我们批量生成一批excel&#xff0c;并将这些excel压缩成一个压缩包导出给前端。 实现 java自带了ZipOutputStream&#xff0c;可以直接生成压缩包&#xff0c;因此&#xff0c;我们直接使用这个&#xff0c;在内存中生成压缩包&#xff0c;直接返回给前端。&am…...

Vue 3中实现多个自定义组件之间的切换

在 Vue 3 中&#xff0c;如果你想在 HTML 页面中实现多个自定义组件之间的切换&#xff0c;你可以使用 Vue 的条件渲染功能&#xff0c;比如 v-if、v-else-if 和 v-else 指令&#xff0c;或者使用 <component> 标签结合 is 属性来动态绑定组件。 1. 打开HBuilder X 图1 …...

opengl 三角形

最后效果&#xff1a; OpenGL version: 4.1 Metal 不知道为啥必须使用VAO 才行。 #include <glad/glad.h> #include <GLFW/glfw3.h>#include <iostream> #include <vector>void framebuffer_size_callback(GLFWwindow *window, int width, int heigh…...

shell脚本练习(2)

1. 使用case实现成绩优良差的判断 2. for创建20用户 用户前缀由用户输入 用户初始密码由用户输入 例如&#xff1a;test01,test10 3. for ping测试指网段的主机 网段由用户输入&#xff0c;例如用户输入192.168.2 &#xff0c;则ping 192.168.2.10 --- 192.168.2.2…...

JS数组的一些方法

前言 忘了在哪里听说JS是用来处理各种各样的数据的&#xff0c;所以掌握一些数组的处理方法极其重要 而最近学校要进行测试&#xff0c;本着复习回顾的想法&#xff0c;决定将一些我所知道的数组处理方法整理整理 不过难免有遗漏与错误&#xff0c;还望各位大佬指正 forEac…...

学习threejs,使用CubeCamera相机创建反光效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️CubeCamera 立方体相机 二、…...

#渗透测试#红蓝攻防#HW#漏洞挖掘#漏洞复现01-笑脸漏洞(vsftpd)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…...

使用nginx请求转发时前端报跨域问题解决

当其他接口都没有问题&#xff0c;后端也进行了跨域的配置时&#xff0c;此时问题应该就出现在nginx中 我发现当上传文件大小小于1m时并不会发生错误&#xff0c;所以我们应该配置一下nginx允许上传文件的大小 在nginx.conf中添加 在nginx目录下重启nginx即可 &#xff08;Wi…...

贪心算法入门(二)

第1题 越野跑 查看测评数据信息 为了能在下一次跑步比赛中有好的发挥&#xff0c;桐桐在一条山路上开始了她的训练 。桐桐希望能在每次训练中跑得尽可能远&#xff0c;不过她也知道农场中的一条规定&#xff1a;独自进山的时间不得超过M秒(1 < M < 10,000,000)。 整条…...

欧拉函数——acwing

题目一&#xff1a;欧拉函数 873. 欧拉函数 - AcWing题库 分析&#xff08;欧拉函数相关知识点&#xff09; 互质数不了解可以参考之前笔记&#xff0c;以便更好了解&#xff1a; 数论—快速幂&#xff0c;欧几里得及其扩展&#xff0c;逆元&#xff0c;单位元_数论单位元函…...

Spring集成Mybatis的实现

实现步骤大纲 第一步&#xff1a;准备数据库表 使用t_act表&#xff08;账户表&#xff09; 第二步&#xff1a;IDEA中创建一个模块&#xff0c;并引入依赖 spring-contextspring-jdbcmysql驱动mybatismybatis-spring&#xff1a;mybatis提供的与spring框架集成的依赖德鲁伊连…...

Redis中的分布式锁(步步为营)

分布式锁 概述 分布式锁指的是&#xff0c;所有服务中的所有线程都去获取同一把锁&#xff0c;但只有一个线程可以成功的获得锁&#xff0c;其他没有获得锁的线程必须全部等待&#xff0c;直到持有锁的线程释放锁。 分布式锁是可以跨越多个实例&#xff0c;多个进程的锁 分布…...

Linux下的三种 IO 复用

目录 一、Select 1、函数 API 2、使用限制 3、使用 Demo 二、Poll 三、epoll 0、 实现原理 1、函数 API 2、简单代码模板 3、LT/ET 使用过程 &#xff08;1&#xff09;LT 水平触发 &#xff08;2&#xff09;ET边沿触发 4、使用 Demo 四、参考链接 一、Select 在…...