【Spring Cache】六 CacheInterceptor 相关
【Spring Cache】六 CacheInterceptor 相关
- 前言
- CacheInterceptor
- CacheAspectSupport
- 1 - 关于缓存操作的属性相关
- 2 - 从 execute 方法入手
- 3 - CacheOperationContexts
- 4 - getOperationContext
- 5 - execute
- AbstractCacheInvoker
- 总结
前言
之前的章节了解到,@EnableCaching
最终会引入组件 BeanFactoryCacheOperationSourceAdvisor
,基于 Advisor = Advice + Pointcut
,其中 Advice
就是 CacheInterceptor
,本章节具体了解 CacheInterceptor
相关类:即 Spring Cache
行为的实现逻辑
CacheInterceptor
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {@Override@Nullablepublic Object invoke(final MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();// 缓存操作本身的执行,比如:缓存中未查到,或者更新缓存结果等时CacheOperationInvoker aopAllianceInvoker = () -> {try {return invocation.proceed();}catch (Throwable ex) {throw new CacheOperationInvoker.ThrowableWrapper(ex);}};Object target = invocation.getThis();Assert.state(target != null, "Target must not be null");try {return execute(aopAllianceInvoker, target, method, invocation.getArguments());}catch (CacheOperationInvoker.ThrowableWrapper th) {throw th.getOriginal();}}}
- 首先,
CacheInterceptor
是一个MethodInterceptor
,它代表整个切面拦截链的执行,执行逻辑封装在父类方法CacheAspectSupport#execute
CacheOperationInvoker
接口代表被缓存方法的执行,这里内部类的实现即MethodInvocation#proceed
- 关于
MethodInterceptor
MethodInvocation
等更多细节,可以参考下文:
【源码】Spring AOP 2 Advice
【源码】Spring AOP 3 Joinpoint
CacheAspectSupport
这是整个 CacheInterceptor
逻辑实现的核心基类,所以内容比较多,以个人角度分几个部分了解:
1 - 关于缓存操作的属性相关
/*** k:CacheOperationCacheKey* v:CacheOperationMetadata 缓存操作元数据*/private final Map<CacheOperationCacheKey, CacheOperationMetadata> metadataCache = new ConcurrentHashMap<>(1024);// 负责 SpEL 解析private final CacheOperationExpressionEvaluator evaluator = new CacheOperationExpressionEvaluator();// 用来解析指定方法的 CacheOperation@Nullableprivate CacheOperationSource cacheOperationSource;// 默认的 KeyGenerator 是 SimpleKeyGeneratorprivate SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);@Nullableprivate SingletonSupplier<CacheResolver> cacheResolver;// 本身是一个 BeanFactoryAware@Nullableprivate BeanFactory beanFactory;// 属性初始化的标识private boolean initialized = false;// 这里通常是基于 CacheConfigurer 进行配置public void configure(@Nullable Supplier<CacheErrorHandler> errorHandler, @Nullable Supplier<KeyGenerator> keyGenerator,@Nullable Supplier<CacheResolver> cacheResolver, @Nullable Supplier<CacheManager> cacheManager) {// 默认 SimpleCacheErrorHandlerthis.errorHandler = new SingletonSupplier<>(errorHandler, SimpleCacheErrorHandler::new);// 默认 SimpleKeyGeneratorthis.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new);// 默认基于 cacheManager 构造 SimpleCacheResolver// 至此,cacheResolver 有可能还是 nullthis.cacheResolver = new SingletonSupplier<>(cacheResolver,() -> SimpleCacheResolver.of(SupplierUtils.resolve(cacheManager)));}@Overridepublic void afterSingletonsInstantiated() {if (getCacheResolver() == null) {try {/*** 此时如果 cacheResolver 为 null 就尝试从容器中获取 CacheManager* 来构造 SimpleCacheResolver* 此时如果容器中没有 CacheManager 则抛出异常*/setCacheManager(this.beanFactory.getBean(CacheManager.class));}// ...}this.initialized = true;}
- 首先这里是一些缓存操作属性的定义,可以理解为默认的对象属性
- 指定了
KeyGenerator
的默认实例是SimpleKeyGenerator
,之前的章节已经了解过 - 之前了解
ProxyCachingConfiguration
配置类时了解过缓存属性可以基于CachingConfigurer
类进行自定义配置,这里就是由configure
方法处理:CacheErrorHandler
未提供自定义配置时默认实例为SimpleCacheErrorHandler
KeyGenerator
未提供自定义配置时默认实例为SimpleKeyGenerator
cacheResolver
未提供自定义配置时默认实例为基于自定义cacheManager
的SimpleCacheResolver
,当然这里如果也没有提供cacheManager
那就是null
了,具体细节可见SupplierUtils
SimpleCacheResolver#of
的处理
- 本类还是一个
SmartInitializingSingleton
,因此容器管理下会执行afterSingletonsInstantiated
,此处支持在cacheResolver
为null
时尝试从容器中获取cacheManager
并基于此创建SimpleCacheResolver
,如果此处依然无法创建cacheResolver
则抛出异常,最后标识initialized = true
2 - 从 execute 方法入手
@Nullableprotected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {if (this.initialized) {Class<?> targetClass = getTargetClass(target);// 获取 CacheOperationSource,此处就是 AnnotationCacheOperationSource 了CacheOperationSource cacheOperationSource = getCacheOperationSource();if (cacheOperationSource != null) {// 或许对应方法的所有 CacheOperationCollection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);if (!CollectionUtils.isEmpty(operations)) {// 基于 CacheOperation 集合创建的 CacheOperationContexts 执行 execute 方法return execute(invoker, method,new CacheOperationContexts(operations, method, args, target, targetClass));}}}// 如果不在容器下管理此单例的话,这里就不执行缓存操作了return invoker.invoke();}
CacheInterceptor
的invoke
方法是委托到这里的,即整个缓存切面的执行逻辑在这里实现- 先基于
CacheOperationSource
(这里就是AnnotationCacheOperationSource
)获取目标方法上的所有CacheOperationSource
s - 然后基于这些
CacheOperationSource
s 创建对应的CacheOperationContexts
进而继续往下执行
3 - CacheOperationContexts
/*** CacheOperationContexts 维护这样一组结构:* 一个方法对应多种操作* 每种操作对应多个操作上下文 CacheOperationContext* 比如:* @Cacheable("cache1")* @Cacheable("cache2")* @CachePut("cache3")* public void test() {}** 则上述方法 test 对应的 CacheOperationContexts 维护结构大致为:* Cacheable.class -> [CacheOperationContext1, CacheOperationContext2]* CachePut.class -> [CacheOperationContext3]*/private class CacheOperationContexts {// MultiValueMap: Spring 提供的一个可以重复同一个 key 的 Mapprivate final MultiValueMap<Class<? extends CacheOperation>, CacheOperationContext> contexts;// 当前缓存操作是否需要同步执行private final boolean sync;public CacheOperationContexts(Collection<? extends CacheOperation> operations, Method method,Object[] args, Object target, Class<?> targetClass) {// 基于传入的 CacheOperation 集合构造对应的 CacheOperationContextsthis.contexts = new LinkedMultiValueMap<>(operations.size());for (CacheOperation op : operations) {this.contexts.add(op.getClass(), getOperationContext(op, method, args, target, targetClass));}// 推断当前缓存操作是否需要同步执行this.sync = determineSyncFlag(method);}// ...// 推断是否同步执行private boolean determineSyncFlag(Method method) {// 同步操作只支持 CacheableOperation,如果没有那就是不需要同步List<CacheOperationContext> cacheOperationContexts = this.contexts.get(CacheableOperation.class);if (cacheOperationContexts == null) {return false;}/*** 如果上述 CacheableOperation 操作里只要有一个指定属性 sync = true 的,* 就开始判断是否真的满足同步执行条件*/boolean syncEnabled = false;for (CacheOperationContext cacheOperationContext : cacheOperationContexts) {if (((CacheableOperation) cacheOperationContext.getOperation()).isSync()) {syncEnabled = true;break;}}if (syncEnabled) {// 多个 contexts 意味多种缓存操作,不支持同步执行if (this.contexts.size() > 1) {throw new IllegalStateException("...");}// 也不支持多个 @Cacheable(sync=true) 并行if (cacheOperationContexts.size() > 1) {throw new IllegalStateException("...");}// @Cacheable(sync=true) 操作也不支持同时指定多个 cacheNameCacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();if (cacheOperationContext.getCaches().size() > 1) {throw new IllegalStateException("...");}// 缓存操作不支持指定 unless 属性if (StringUtils.hasText(operation.getUnless())) {throw new IllegalStateException("...");}return true;}return false;}}
- 之前的章节了解过缓存操作执行上下文相关的
CacheOperationInvocationContext
接口及其内部类实现CacheOperationContext
,这里的CacheOperationContexts
是对CacheOperationContext
的一层封装 CacheOperationContexts
为目标方法上每种操作维护对应的一组CacheOperationContext
s,毕竟同一个缓存操作注解可以重复添加(但这样不支持sync
同步属性)- 提供
determineSyncFlag
方法用来推断当前缓存操作是否需要同步执行,这里印证了之前对sync
属性的定义:- 它只适用于
CacheableOperation
即对应@Cacheable
注解 - 不支持与其他缓存操作混用
- 不支持
@Cacheable
的合并 - 对唯一的
@Cacheable
也不支持指定多个cacheName
- 同步操作时不支持
unless
属性
- 它只适用于
4 - getOperationContext
protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {// 构造目标方法目标操作上的 CacheOperationMetadataCacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);return new CacheOperationContext(metadata, args, target);}protected CacheOperationMetadata getCacheOperationMetadata(CacheOperation operation, Method method, Class<?> targetClass) {/*** 这个 key 是由 CacheOperation 和被注解元素的 AnnotatedElementKey 组成的* 针对同一方法上的同一种元素,也会给予其不同的属性创建对应的缓存,具体可以* 看下 CacheOperation#equals 方法*/CacheOperationCacheKey cacheKey = new CacheOperationCacheKey(operation, method, targetClass);// 先从缓存中获取,获取不到就创建CacheOperationMetadata metadata = this.metadataCache.get(cacheKey);if (metadata == null) {KeyGenerator operationKeyGenerator;/*** 如果注解上指定了 keyGenerator,则从容器中获取,否则就是 CacheConfigurer* 指定或默认的 SimpleKeyGenerator*/if (StringUtils.hasText(operation.getKeyGenerator())) {operationKeyGenerator = getBean(operation.getKeyGenerator(), KeyGenerator.class);}else {operationKeyGenerator = getKeyGenerator();}/*** 如果注解指定了 cacheResolver 就从容器获取,又或者注解指定了 cacheManager* 则从容器中获取并依此创建 SimpleCacheResolver*/CacheResolver operationCacheResolver;if (StringUtils.hasText(operation.getCacheResolver())) {operationCacheResolver = getBean(operation.getCacheResolver(), CacheResolver.class);}else if (StringUtils.hasText(operation.getCacheManager())) {CacheManager cacheManager = getBean(operation.getCacheManager(), CacheManager.class);operationCacheResolver = new SimpleCacheResolver(cacheManager);}/*** 如果注解上没有指定,CacheConfigurer 也没有指定,则此处就获取不到* cacheResolver 抛出异常*/else {operationCacheResolver = getCacheResolver();}// 基于这些属性创建 CacheOperationMetadatametadata = new CacheOperationMetadata(operation, method, targetClass,operationKeyGenerator, operationCacheResolver);this.metadataCache.put(cacheKey, metadata);}return metadata;}
- 这里是构造
CacheOperation
对应的CacheOperationContext
,核心是构造CacheOperationMetadata
,即缓存操作相关的元数据 - 其中创建
CacheOperationMetadata
时:- 会优先使用注解上指定的
keyGenerator
:从容器中获取对应bean
实例 - 同样地也会优先使用基于注解指定的
cacheResolver
cacheManager
来构造对应的cacheResolver
- 至此我们大致可以排列配置的优先级:
- 注解上指定的配置优先级最高
- 其次是
CacheConfigurer
上指定的配置 - 最后是缺省配置,比如
SimpleKeyGenerator
SimpleCacheErrorHandler
- 会优先使用注解上指定的
5 - execute
@Nullableprivate Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {// 如果当前方法要进行同步缓存操作if (contexts.isSynchronized()) {CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);Cache cache = context.getCaches().iterator().next();try {/*** 返回值是 Optional 则包装缓存或执行结果后返回* handleSynchronizedGet 方法依赖于缓存的 get(Object key, Callable<T> valueLoader)* 方法,即 get 不到就将 valueLoader::call 缓存进去并返回* get 方法的实现保证同步性,比如 ConcurrentMapCache 基于 ConcurrentMap#computeIfAbsent* 方法保证同步*/return wrapCacheValue(method, handleSynchronizedGet(invoker, key, cache));}catch (Cache.ValueRetrievalException ex) {// ...}}else {// condition 不通过就直接执行目标方法了return invokeOperation(invoker);}}// 如果非同步操作// 先执行属性 beforeInvocation = true 的 CacheEvictOperationprocessCacheEvicts(contexts.get(CacheEvictOperation.class), true,CacheOperationExpressionEvaluator.NO_RESULT);// 获取可以找到的第一个缓存值Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));/*** 这个集合会收集所有的 CachePut 操作,包括两种:* 1)缓存未命中的 CacheableOperation* 2)CachePutOperation*/List<CachePutRequest> cachePutRequests = new ArrayList<>();// 如果没有命中缓存,则此时 CacheableOperation 就相当于 CachePutOperation 了if (cacheHit == null) {collectPutRequests(contexts.get(CacheableOperation.class),CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);}/*** cacheValue:缓存值,但方法的执行结果是 Optional 时,* cacheValue 表示真实值即 Optional#get* returnValue:方法的执行结果,有可能被 Optional 包装*/Object cacheValue;Object returnValue;/*** 如果缓存命中* cacheVal 就是缓存值* returnVal 有必要的话包装成 Optional*/if (cacheHit != null && !hasCachePut(contexts)) {// If there are no put requests, just use the cache hitcacheValue = cacheHit.get();returnValue = wrapCacheValue(method, cacheValue);}/*** 如果缓存未命中* retuanVal 就是目标方法的执行结果* cacheVal 有必要的话取 Optional 的真实值*/else {returnValue = invokeOperation(invoker);cacheValue = unwrapReturnValue(returnValue);}// 把所有的 CachePutOperation 合并起来(@Cacheable 和 @CachePut)collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);// 使用最终的缓存值 cacheValue 执行 doPut 操作for (CachePutRequest cachePutRequest : cachePutRequests) {cachePutRequest.apply(cacheValue);}// 最后执行 beforeInvocation = false 的剔除缓存操作processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);// 方法的真实返回值return returnValue;}
这个方法就是 Spring Cache
的实现逻辑了:
- 首先如果之前构造
CacheOperationContexts
推断目标缓存方法需要同步执行时,会最终依赖Cache#get(Object key, Callable<T> valueLoader)
方法执行CacheableOperation
操作,它需要实现类保证线程安全,比如ConcurrentMapCache
就是基于ConcurrentMap#computeIfAbsent
方法来保证同步性的,第一章节有了解过 - 如果目标缓存方法不需要同步执行,则最先执行属性
beforeInvocation = true
的CacheEvictOperation
操作,即在方法执行前剔除缓存(基于allEntries
属性决定是清除所有缓存还是指定key
的缓存) - 接下来会尝试从缓存中获取对应的值(以指定的缓存集合中获取的第一个为准),如果缓存未命中,则对应的
CacheableOperation
就被视为CachePutOperation
了(不难理解) - 定义
cacheVal
为更新缓存的值,定义retuanVal
为返回给调用方的值:- 缓存命中时:
cacheVal
即命中的值,retuanVal
有必要的话基于cacheVal
包装成Optional
- 缓存未命中时:
retuanVal
即目标方法的执行结果,cacheVal
有必要的话从Optional
包装取出
- 缓存命中时:
- 收集所有的
CachePutRequest
,这里包括了两种:- 未命中缓存的
CacheableOperation
CachePutOperation
- 未命中缓存的
- 执行这些
CachePutRequest
,本质上就是Cache#put
- 最后执行的是属性
beforeInvocation = false
的CacheEvictOperation
操作,即在方法执行后剔除缓存(基于allEntries
属性决定是清除所有缓存还是指定key
的缓存),当然这里就可以支持unless
属性判断了(因为有方法的返回值) - 至此就是整个
Spring Cache
的实现逻辑了
AbstractCacheInvoker
public abstract class AbstractCacheInvoker {protected SingletonSupplier<CacheErrorHandler> errorHandler;// 默认 SimpleCacheErrorHandlerprotected AbstractCacheInvoker() {this.errorHandler = SingletonSupplier.of(SimpleCacheErrorHandler::new);}// ...@Nullableprotected Cache.ValueWrapper doGet(Cache cache, Object key) {try {return cache.get(key);}catch (RuntimeException ex) {getErrorHandler().handleCacheGetError(ex, cache, key);return null;}}protected void doPut(Cache cache, Object key, @Nullable Object result) {try {cache.put(key, result);}catch (RuntimeException ex) {getErrorHandler().handleCachePutError(ex, cache, key, result);}}protected void doEvict(Cache cache, Object key, boolean immediate) {try {if (immediate) {// 立即剔除cache.evictIfPresent(key);}else {// 不保证实时性cache.evict(key);}}catch (RuntimeException ex) {getErrorHandler().handleCacheEvictError(ex, cache, key);}}protected void doClear(Cache cache, boolean immediate) {try {if (immediate) {// 立即清除缓存cache.invalidate();}else {// 不保证实时性cache.clear();}}catch (RuntimeException ex) {getErrorHandler().handleCacheClearError(ex, cache);}}}
顶层基类 AbstractCacheInvoker
:
- 封装整个
Spring Cache
对底层缓存操作的基础方法doGet
doPut
doEvict
doClear
- 操作过程中的异常由
CacheErrorHandler
接口处理,默认是Spring
提供的唯一实现SimpleCacheErrorHandler
:直接抛出对应异常
总结
这段太干了,但是读都读了就尽可能全都贴上来,抛开实现的细节逻辑,我认为至少有以下几点直观收益:
- 清楚的理解了缓存操作属性的配置方式和优先级原理:
注解上指定的属性 > CacheConfigurer 指定的属性 > 缺省属性
,因此可以更加合理的编写配置类 CacheOperationContexts
类的设计很有意思,优雅的管理了method -> CacheOperation -> CacheOperationContext
的关系CacheInterceptor
CacheAspectSupport
AbstractCacheInvoker
类层级的设计:CacheInterceptor
:站在AOP
角度专注于Cache Interceptor
的实现CacheAspectSupport
:负责实现核心的Spring Cache
逻辑AbstractCacheInvoker
:提供对底层缓存的操作方法
- 等等其他,其实主要用心看,值得学习的地方是很多的
上一篇:【Spring Cache】五 从 @EnableCaching 了解 Spring Cache 实现流程
下一篇:【Spring Cache】七 Spring Cache 流程总结
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- P1055 [NOIP2008 普及组] ISBN 号码
题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括99位数字、11位识别码和33位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-就是分隔符(键盘上的减号),最后一位是识别码,例如…...
2024/4/15 4:44:03 - QT6 Mingw-w64 opencv环境配置教程
QT6 Mingw-w64 opencv傻瓜式环境配置小白教程 安装环境 win10 64位Qt-6.2.1OpenCV-4.5.5cmake-3.22.2MinGW–W64 GCC-8.1.0 x86_64-posix-seh 首先安装QT6 QT6仅支持在线安装器安装,下载地址:https://download.qt.io/archive/online_installers 安装…...
2024/4/19 19:31:18 - 【js基础--函数】
文章目录一、函数的概念二、函数的使用1、函数的声明2、函数的调用3、函数的封装三、函数的参数1、形参和实参2、函数参数的传递过程3、参数的数量四、函数的返回值1、return 语句2、return 终止函数3、return 的返回值4、函数没有 return 返回 undefined5、break ,continue ,r…...
2024/4/20 6:33:43 - reactjs脚手架index.html中配置项说明
reactjs脚手架index.html中配置项说明...
2024/4/7 20:13:07 - 基于ArduPilot的旋翼式无人机飞行器开发系列(三,四轴无人机的组成)
注意:以该系列的案例样机 --- 四轴无人机为例开展; 一,四轴无人机的硬件构成 通常以一个四周无人机的硬件组成如下: 1.一个四轴机架,4个浆叶(F450机架+脚架) 2.四个动力马达(QM2821) 3.四个无刷电子调速器(电调/ESC)(乐天20A) 4.一个飞行控制器(飞控)(如V…...
2024/4/7 20:13:06 - ExoPlayer详解
1.解码器创建过程 SimpleExoPlayer 构造函数通过DefaultRenderersFactory的createRenderers方法来创建MediaCodecAudioRender和MediaCodecVideoRenderer,当然还有一些其他render,创建完成之后统一放入renderersList中保存。随后使用renderersList作为构…...
2024/4/20 7:17:10 - .Net——元数据和IL
目录CS代码编译成IL元数据ILIL引用元数据元数据和IL在JIT编译时执行细则CS代码编译成IL cs代码编译之后将生成元数据和IL,并组成托管模块(Module)的基本单元。多个托管模块组成程序集,其实还包括一定的资源文件,例如图…...
2024/5/3 10:53:44 - JAVA语言概述(三)
三、开发环境搭建 1JDK、JRE、JVM的关系 2 JDK的下载、安装 下载:官网,github 安装:傻瓜式安装:JDK 、JRE 注意问题:安装软件的路径中不能包含中文、空格。 3 path环境变量的配置 (1)path环…...
2024/4/13 18:08:15 - android撕衣服应用介绍,android插件化开发指南pdf
new_bitmap Bitmap.createBitmap(width, height, Config.ARGB_8888);//创建一个位图 ARGB_8888 代表32位ARGB位图 paint new Paint();//实例化paint类 画笔类 paint.setAntiAlias(true);//设置画笔的锯齿效果 paint.setDither(true); //防抖动 mCanvas new Canvas(new_b…...
2024/4/17 23:50:52 - 2. SpringMVC-Hello World
Hello World一、创建Maven工程1. 新建工程2. 进行相应的配置3. 配置web.xml文件二、创建相应的类和配置文件三、创建前端页面1. 在WEB-INF在创建templates文件夹2. 创建index.html和hello.html页面四、配置tomcat进行测试一、创建Maven工程 1. 新建工程 新建maven工程&#x…...
2024/5/3 2:13:45 - 初学者c指针2(白话文版)
类型转换,指针运算 数组指针 二级指针 指针数组 Part1: 强制类型转换,指针运算,三种 ,元素个数,应用,c标准相关 强制类型转换是在数据之前加一个带括号的类型,例如转换为int类型&…...
2024/4/13 18:08:15 - mysql 数据库的设计
数据库设计:建立数据库中的表结构以及表与表之间的关联关系的过程 即:有哪些表,表里有哪些字段,表与表之间的关系 数据库设计的步骤 表关系: 一对一:在任意一方加入外键,关联一的一方逐渐&am…...
2024/4/7 20:12:59 - 枚举与优化-ICONS
【题目描述】Dave最近收集了一些有趣的鹅卵石,他想把它们排成一个矩阵,但希望矩阵的行数与列数和最小。请编一个程序帮助Dave找到这样的方案。 【输入格式】 输入文件中只有一行,包含一个自然数N(1 ≤ N ≤ 100),为要排列的鹅卵…...
2024/4/13 18:08:15 - 四次挥手TIME_WAIT状态存在的原因
四次挥手TIME_WAIT状态存在的原因客户端连接在收到服务器的结束报文段之后,并没有直接进入CLOSED状态,而是转移到TIME_ WAIT 状态。在这个状态,客户端连接要等待一段长为2MSL (Maximum Segment Life,报文段最大生存时间)的时间&am…...
2024/4/20 5:31:38 - Css 结构伪类选择器
目录Css 结构伪类选择器结构伪类-公式Css 结构伪类选择器 在日常开发中,结构伪类选择器用的还是比较多的熟练的使用它,可以让我们的代码更整洁。 作用与优势: 作用:根据元素在HTML中的结构关系查找元素。优势:减少对…...
2024/5/3 8:03:20 - Android性能优化之APK-极限压缩(资源越多,效果越显著),2021Android高级面试题总结
优化 发现我们 link 大概优化了 700 kb继续。 注意 因为 link 是检查有没有引用来做的判断是否使用了资源,那么如果是这种方式勒,所以在删除的时候一定要谨慎。 //动态获取资源 id , 未直接使用 R.xx.xx ,则这个 id 代表的资源会被认为没有…...
2024/4/26 19:39:14 - Jenkins笔记(三)部署.Net Core Webapi项目
我的博客 博客首页 前言 本次部署未不使用docker,而是采用拉取代码后编译运行的方式。 下面先给张部署的流程图,再介绍部署的配置文件和可能存在的坑 开始部署 首先,进入Jenkins首页,选择新建一个任务,这里选择流…...
2024/4/18 8:13:43 - 【C++】面向对象之继承篇
学习总结 (1)实例化Worker对象的时候,到底是先调用谁的构造函数 ——先基类的构造函数,即要想实例化一个派生类,必须先(隐性)实例化一个基类。 在销毁Worker这个对象的时候,又是…...
2024/4/18 3:51:03 - pcl深度图像
深度图像 #include <pcl/range_image/range_image.h> #include <pcl/range_image/range_image_planar.h> #include <pcl/io/io.h> #include <pcl/io/pcd_io.h> #include <pcl/features/integral_image_normal.h> #include <pcl/visualizatio…...
2024/4/16 2:11:38 - 【巨人的肩膀】Spring事务详解
引子 很多 coder 在不理解事务的原理甚至连基本概念都不清楚的情况下,就去使用数据库事务,是极容易出错,写出一些自己不能掌控的代码。网上很多文章要不就是概念,或者一点源码,或者一点测试验证,都不足以全…...
2024/5/3 1:59:35
最新文章
- Electron试用 SQLite
在客户端开发中,无论是 PC 端,还是手机端,为了能够访问离线数据,数据经常需要保存到本地,IndexDB 可以用于存储本地数据,IndexDB 是一个对象存储,数据是以 key:value 的形式进行存储和访问的&am…...
2024/5/4 6:57:11 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 【实战解析】YOLOv9全流程训练至优化终极指南
【实战解析】YOLOv9全流程训练至优化终极指南 0.引言1.环境准备2.数据预处理(1)数据准备(2)按比例划分数据集(3)xml转txt脚本(4)配置文件 3.模型训练(1)单GPU…...
2024/5/3 23:22:44 - 数据挖掘中的PCA和KMeans:Airbnb房源案例研究
目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步:确定 PCA 组件的最佳数量 10.2 第 2 步:使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…...
2024/5/3 4:40:07 - Web大并发集群部署之集群介绍
一、传统web访问模型 传统web访问模型完成一次请求的步骤 1)用户发起请求 2)服务器接受请求 3)服务器处理请求(压力最大) 4)服务器响应请求 传统模型缺点 单点故障; 单台服务器资源有限&…...
2024/5/1 13:15:58 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/3 23:10:03 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/2 15:04:34 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/4 2:59:34 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57