RuoYi-Vue-Plus (SpringCache、CacheManager、@Cacheable)

一、概述

        1、SpringCache是Spring提供的一个缓存框架,在Spring3.1版本开始支持将缓存添加到现有的spring应用程序中,在4.1开始,缓存已支持JSR-107注释和更多自定义的选项。

        2、SpringCache利用了AOP,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能了,做到了对代码侵入性做小。

        3、SpringCache框架还提供了CacheManager接口,可以实现降低对各种缓存框架的耦合。它不是具体的缓存实现,它只提供一整套的接口和代码规范、配置、注解等,用于整合各种缓存方案,比如Caffeine、Guava Cache、Ehcache。

二、SpringCache概念

接口:


1、Cache接口:缓存接口,定义缓存操作。实现有 如RedisCache、EhCacheCache、ConcurrentMapCache等

2、cacheResolver:指定获取解析器

3、CacheManager:缓存管理器,管理各种缓存(Cache)组件;如:RedisCacheManager,使用redis作为缓存。指定缓存管理器

注解:

1- @Cacheable:在方法执行前查看是否有缓存对应的数据,如果有直接返回数据,如果没有调用方法获取数据返回,并缓存起来。

2- @CacheEvict:将一条或多条数据从缓存中删除。

3- @CachePut:将方法的返回值放到缓存中

4- @EnableCaching:开启缓存注解功能

5- @Caching:组合多个缓存注解;

6- @CacheConfig:统一配置@Cacheable中的value值

三、spring缓存整合redis 

RedisConfig 
类路径: com.ruoyi.framework.config.RedisConfig
1- spring 自动管理缓存机制
@EnableCaching //开启spring缓存,提升性能
@Slf4j
@Configuration
@EnableCaching //1- spring 自动管理缓存机制 ,,提升性能
@EnableConfigurationProperties(RedissonProperties.class)
public class RedisConfig {
 2- 整合自定义缓存管理器
 /**
     * 2-自定义缓存管理器 整合spring-cache
     */
    @Bean
    public CacheManager cacheManager() {
        return new PlusSpringCacheManager();
    }

自定义 管理器PlusSpringCacheManager,实现CacheManager 接口,基于redssion操作缓存

/**
 * Copyright (c) 2013-2021 Nikita Koksharov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ruoyi.framework.manager;

import com.ruoyi.common.utils.redis.RedisUtils;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.spring.cache.CacheConfig;
import org.redisson.spring.cache.RedissonCache;
import org.springframework.boot.convert.DurationStyle;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * A {@link org.springframework.cache.CacheManager} implementation
 * backed by Redisson instance.
 * <p>
 * 修改 RedissonSpringCacheManager 源码
 * 重写 cacheName 处理方法 支持多参数
 *
 * @author Nikita Koksharov
 *
 */
@SuppressWarnings("unchecked")
public class PlusSpringCacheManager implements CacheManager {

    //是否自动配置name
    private boolean dynamic = true;

    //是否允许null
    private boolean allowNullValues = true;

    //事务提交之后执行
    private boolean transactionAware = true;

    // 常用缓存配置 ttl;  maxIdleTime; maxSize; 等
    Map<String, CacheConfig> configMap = new ConcurrentHashMap<>();
    // 缓存实例
    ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>();

    /**
     * Creates CacheManager supplied by Redisson instance
     */
    public PlusSpringCacheManager() {
    }


    /**
     * Defines possibility of storing {@code null} values.
     * <p>
     * Default is <code>true</code>
     *
     * @param allowNullValues stores if <code>true</code>
     */
    public void setAllowNullValues(boolean allowNullValues) {
        this.allowNullValues = allowNullValues;
    }

    /**
     * Defines if cache aware of Spring-managed transactions.
     * If {@code true} put/evict operations are executed only for successful transaction in after-commit phase.
     * <p>
     * Default is <code>false</code>
     *
     * @param transactionAware cache is transaction aware if <code>true</code>
     */
    public void setTransactionAware(boolean transactionAware) {
        this.transactionAware = transactionAware;
    }

    /**
     * Defines 'fixed' cache names.
     * A new cache instance will not be created in dynamic for non-defined names.
     * <p>
     * `null` parameter setups dynamic mode
     *
     * @param names of caches
     */
    public void setCacheNames(Collection<String> names) {
        if (names != null) {
            for (String name : names) {
                getCache(name);
            }
            dynamic = false;
        } else {
            dynamic = true;
        }
    }

    /**
     * Set cache config mapped by cache name
     *
     * @param config object
     */
    public void setConfig(Map<String, ? extends CacheConfig> config) {
        this.configMap = (Map<String, CacheConfig>) config;
    }

    protected CacheConfig createDefaultConfig() {
        return new CacheConfig();
    }

    @Override
    public Cache getCache(String name) {
        // 重写 cacheName 支持多参数
        /**
         * 演示案例   :  String DEMO_CACHE = "demo:cache#60s#10m#20";
         */
        String[] array = StringUtils.delimitedListToStringArray(name, "#");
        name = array[0];

        Cache cache = instanceMap.get(name);
        if (cache != null) {
            return cache;
        }
        //2- dynamic=false 不会动态生成
        if (!dynamic) {
            //return cache;
            return null;
        }

        CacheConfig config = configMap.get(name);
        if (config == null) {
            config = createDefaultConfig();
            configMap.put(name, config);
        }

        //setTTL
        if (array.length > 1) {
            config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis());
        }
        //setMaxIdleTime
        if (array.length > 2) {
            config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis());
        }
        //setMaxSize
        if (array.length > 3) {
            config.setMaxSize(Integer.parseInt(array[3]));
        }

        if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) {
            return createMap(name, config);
        }

        return createMapCache(name, config);
    }

    private Cache createMap(String name, CacheConfig config) {
        //1-获取缓存
        RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
        //2-没有过期时间传2个参数
        Cache cache = new RedissonCache(map, allowNullValues);
        // 3-事务提交 之后执行
        if (transactionAware) {
            cache = new TransactionAwareCacheDecorator(cache);
        }
        //4-不存在就添加
        Cache oldCache = instanceMap.putIfAbsent(name, cache);
        if (oldCache != null) {
            cache = oldCache;
        }
        return cache;
    }

    private Cache createMapCache(String name, CacheConfig config) {
        //1-获取缓存
        RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
        //2-有过期时间传3个参数 ,config 里面有  ttl、maxIdleTime、maxSize
        Cache cache = new RedissonCache(map, config, allowNullValues);
        // 3-事务提交 之后执行
        if (transactionAware) {
            cache = new TransactionAwareCacheDecorator(cache);
        }
        //4-不存在就添加
        Cache oldCache = instanceMap.putIfAbsent(name, cache);
        if (oldCache != null) {
            cache = oldCache;
        } else {
            map.setMaxSize(config.getMaxSize());
        }
        return cache;
    }

//返回不可修改的集合
    @Override
    public Collection<String> getCacheNames() {
        return Collections.unmodifiableSet(configMap.keySet());
    }


}
3-@Cacheable

以下Cacheable几个属性分别演示了如何使用:(支持SPEL表达式

  • cacheNames 
  • key 
  • sync
  • condition 
  • sync 
/**
     * <简述>cacheNames: 指定名称 可以是数组
     *        key: 支持spel表达式,可以获取参数
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @param pageQuery
     * @return java.lang.String
     */
    @Cacheable(cacheNames = "cache1", key = "#id + '_cache' + #pageQuery.pageNum")
    @GetMapping("test1")
    public  String test1(String id, PageQuery pageQuery){

        return "ok";
    }

    /**
     * <简述> condition :符合条件进行缓存
     *        #id != null :表示传入 id不为空才会缓存进入redis,id为空则不缓存
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @Cacheable(cacheNames = "cache2", key = "#id + '_cache'" , condition = "#id != null")
    @GetMapping("test2")
    public  String test2(String id){

        return "ok";
    }

    /**
     * <简述> unless 符合条件不缓存
     *        #result == null :接口返回结果为空则不进行缓存
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @Cacheable(cacheNames = "cache3", key = "#id + '_cache'" , unless = "#result == null")
    @GetMapping("test3")
    public  String test3(String id){
        return null;
    }

    /**
     * <简述> sync = true
     *       同步阻塞:同时进来多个请求, 等待前面调用返回并缓存,才能回进入下个请求
     *       作用:防止缓存积存
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @Cacheable(cacheNames = "cache4", key = "#id + '_cache'", sync = true)
    @GetMapping("test4")
    public  String test4(String id){
        return null;
    }

    /**
     * <简述> 获取类中参数
     *         比较繁琐,一般是在实现类中传递登录参数,用spel获取
     * @author syf
     * @date 2024/5/7 11:03
     * @return java.lang.String
     */
    @Cacheable(cacheNames = "cache5", key = "T(com.ruoyi.common.helper.LoginHelper).getLoginUser().getLoginId()")
    @GetMapping("test5")
    public  String test5(){
        LoginUser loginUser = LoginHelper.getLoginUser();
        return "ok";
    }
4- @CachePut

缓存更新

执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

  /**
     * <简述> 结果不为空进行更新
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @CachePut(cacheNames = "cache2", key = "#id + '_cache'" , condition = "#result != null")
    @GetMapping("test2")
    public  String test2(String id){
        boolean flag = doUpdate();
        return flag  ? "ok" : null;
    }
5- @CacheEvict

缓存删除

执行该方法,并将缓存中结果删除。

allEntries  删除所有cacheNames = "cache4",下面缓存
beforeInvocation  默认false,方法执行之后有异常不执行。true:方法执行之后有异常,也执行
  /**
     * <简述> 删除缓存
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @CacheEvict(cacheNames = "cache4", key = "#id + '_cache'")
    @GetMapping("test7")
    public  String test7(String id){
        boolean flag = doDelete();
        return flag  ? "ok" : null;
    }


  /**
     * <简述> 删除所有缓存
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @CacheEvict(cacheNames = "cache4", allEntries = true)
    @GetMapping("test8")
    public  String test8(String id){
        return null;
    }

   /**
     * <简述> beforeInvocation 无论是否有异常都执行操作
     * @author syf
     * @date 2024/5/7 11:03
     * @param id
     * @return java.lang.String
     */
    @CacheEvict(cacheNames = "cache4", beforeInvocation = true)
    @GetMapping("test9")
    public  String test9(String id){
        return null;
    }
 6-@Caching:

指定多个Spring Cache相关的注解

三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。

    @Caching(
            cacheable = {@Cacheable(value = "uer1",key = "#userName")},
            put = {@CachePut(value = "uer1", key = "#result.id"),
                    @CachePut(value = "uer1", key = "#result.age")
            }
    )
    public User getStuByStr(String userName) {
      
        List<User> users= listMapper.selectByList(studentExample);
        return Optional.ofNullable(users).orElse(null).get(0);
    }

四、若依框架中缓存使用(自定义SpringCache 源码解读)

CacheNames 常量设置规则:
key 格式为: cacheNames#ttl#maxIdleTime#maxSize
/**
 * 缓存组名称常量
 * <p>
 * key 格式为 cacheNames#ttl#maxIdleTime#maxSize
 * <p>
 * ttl 过期时间 如果设置为0则不过期 默认为0
 * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0   (超过maxIdleTime LRU算法自动清理)
 * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0
 * <p>
 * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500
 *
 * @author Lion Li
 */

PlusSpringCacheManager 实现 CacheManager 接口,重写 getCache 方法,

就是配置了  :ttl、maxIdleTime、maxSize  三个参数吗,如下:

@Override
    public Cache getCache(String name) {
        // 重写 cacheName 支持多参数
        /**
         * 1-演示案例   :  String DEMO_CACHE = "demo:cache#60s#10m#20";
         */
        String[] array = StringUtils.delimitedListToStringArray(name, "#");
        name = array[0];

        Cache cache = instanceMap.get(name);
        if (cache != null) {
            return cache;
        }
        //2- dynamic=false 不会动态生成
        if (!dynamic) {
            //return cache;
            return null;
        }

        CacheConfig config = configMap.get(name);
        if (config == null) {
            config = createDefaultConfig();
            configMap.put(name, config);
        }
        
        //setTTL
        if (array.length > 1) {
            config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis());
        }
        //setMaxIdleTime
        if (array.length > 2) {
            config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis());
        }
        //setMaxSize
        if (array.length > 3) {
            config.setMaxSize(Integer.parseInt(array[3]));
        }

        if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) {
            return createMap(name, config);
        }

        return createMapCache(name, config);
    }

 重点:下面就是PlusSpringCacheManager ,操作缓存的地方

上面调用了:createMap、createMapCache 2个方法对比:

1-逻辑:

createMapCache 多了个 setMaxSize判断,其他都一样

else {
            map.setMaxSize(config.getMaxSize());
        }

2- 返回类型 

createMap 返回  RMap

createMapCache 返回 RMapCache

对比: RMapCache 继承了 RMap 多了对于ttl、maxIdleTime、maxSize 的配置

相同 :都是基于redisson,缓存到redis

private Cache createMap(String name, CacheConfig config) {
        //1-获取缓存
        RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
        //2-没有过期时间传2个参数
        Cache cache = new RedissonCache(map, allowNullValues);
        // 3-事务提交 之后执行
        if (transactionAware) {
            cache = new TransactionAwareCacheDecorator(cache);
        }
        //4-不存在就添加
        Cache oldCache = instanceMap.putIfAbsent(name, cache);
        if (oldCache != null) {
            cache = oldCache;
        }
        return cache;
    }

    private Cache createMapCache(String name, CacheConfig config) {
        //1-获取缓存
        RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
        //2-有过期时间传3个参数 ,config 里面有  ttl、maxIdleTime、maxSize
        Cache cache = new RedissonCache(map, config, allowNullValues);
        // 3-事务提交 之后执行
        if (transactionAware) {
            cache = new TransactionAwareCacheDecorator(cache);
        }
        //4-不存在就添加
        Cache oldCache = instanceMap.putIfAbsent(name, cache);
        if (oldCache != null) {
            cache = oldCache;
        } else {
            map.setMaxSize(config.getMaxSize());
        }
        return cache;
    }

 上面  TransactionAwareCacheDecorator:

所执行的put操作,是在事务提交之后执行

 public void put(final Object key, @Nullable final Object value) {
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                public void afterCommit() {
                    TransactionAwareCacheDecorator.this.targetCache.put(key, value);
                }
            });
        } else {
            this.targetCache.put(key, value);
        }

    }

 五、缓存工具类

private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);

主要是获取 CacheManager 接口,提供对缓存CRUD操作 :
public interface CacheManager {
    @Nullable
    Cache getCache(String name);

    Collection<String> getCacheNames();
}
 
package com.ruoyi.common.utils.redis;

import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.redisson.api.RMap;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.util.Set;

/**
 * 缓存操作工具类 {@link }
 *
 * @author Michelle.Chung
 * @date 2022/8/13
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = {"unchecked"})
public class CacheUtils {

    private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);

    /**
     * 获取缓存组内所有的KEY
     *
     * @param cacheNames 缓存组名称
     */
    public static Set<Object> keys(String cacheNames) {
        RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache();
        return rmap.keySet();
    }

    /**
     * 获取缓存值
     *
     * @param cacheNames 缓存组名称
     * @param key        缓存key
     */
    public static <T> T get(String cacheNames, Object key) {
        Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key);
        return wrapper != null ? (T) wrapper.get() : null;
    }

    /**
     * 保存缓存值
     *
     * @param cacheNames 缓存组名称
     * @param key        缓存key
     * @param value      缓存值
     */
    public static void put(String cacheNames, Object key, Object value) {
        CACHE_MANAGER.getCache(cacheNames).put(key, value);
    }

    /**
     * 删除缓存值
     *
     * @param cacheNames 缓存组名称
     * @param key        缓存key
     */
    public static void evict(String cacheNames, Object key) {
        CACHE_MANAGER.getCache(cacheNames).evict(key);
    }

    /**
     * 清空缓存值
     *
     * @param cacheNames 缓存组名称
     */
    public static void clear(String cacheNames) {
        CACHE_MANAGER.getCache(cacheNames).clear();
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vivado 低级别 SVF JTAG 命令

低级别 SVF JTAG 命令 注释 &#xff1a; 在 Versal ™ 器件上不支持 SVF 。 低级别 JTAG 命令允许您扫描多个 FPGA JTAG 链。针对链操作所生成的 SVF 命令使用这些低级别命令来访问链中的 FPGA 。 报头数据寄存器 (HDR) 和报头指令寄存器 (HIR) 语法 HDR length […

怎么制作地理思维导图?方法推荐

怎么制作地理思维导图&#xff1f;随着信息技术的飞速发展&#xff0c;教育领域也迎来了深刻的变革。思维导图作为一种高效的学习工具&#xff0c;已经广泛应用于地理学科的教学中。它不仅可以帮助学生更好地理解和记忆地理知识&#xff0c;还能提高学习效率。本文将为大家推荐…

ESP-WROOM-32配置Arduino IDE开发环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、下载Arduino IDE二、安装工具集三、测试样例1.选则开发板2.连接开发板3.示例程序 四、使用官方示例程序总结 前言 之前用了很多注入STM32、树莓派Pico和Ar…

超标量处理器设计:重排序缓存(ROB)

★超标量处理器的很多地方用到了重排序缓存&#xff0c;但是我对它不是很了解&#xff0c;所以我整理一下重排序缓存的知识点。 重排序缓存(ROB)在确保乱序执行的指令能够正确地完成和提交(Commit)&#xff0c;也可以用来寄存器重命名。 ROB是一个先进先出的表&#xff0c;每个…

车载测试___长安汽车车机测试项目

项目介绍: 长安汽车车机是以腾讯车载互联为基础&#xff0c;融合了多媒体影音系统(QQ音乐、喜马拉雅FM、酷我音乐)、车载导航、车辆功能设定这些选项&#xff0c;可以在线听歌、导航、查看360度全景影像辅助系统&#xff0c;让车主驾车更加安逸享受。 具体模块包含远程车辆状…

LeetCode 147. 对链表进行插入排序

目录 1.原题链接&#xff1a; 2.从前往后插入结点&#xff1a; 代码实现&#xff1a; 3.提交结果&#xff1a; 4.读书分享&#xff1a; 1.原题链接&#xff1a; 147. 对链表进行插入排序 2.从前往后插入结点&#xff1a; 对于本题&#xff0c;我们可以以头结点作为参考…

【Leetcode】八大排序

总述 插入排序&#xff1a;直接插入排序&#xff1b;希尔排序&#xff1b; 选择排序&#xff1a;简单选择排序&#xff1b;堆排序&#xff1b; 交换排序&#xff1a;冒泡排序&#xff1b;快速排序&#xff1b; 归并排序&#xff1b; 桶排序/基数排序&#xff1b; 直接插入排序 …

NVIDIA Omniverse Cloud API支持数字孪生开发,可解决复杂AI问题 | 最新快讯

在全球范围内&#xff0c;价值超过 50 万亿美元的重工业市场&#xff0c;正在竞相实现数字化。 基于此&#xff0c;为帮助数字孪生技术更好地赋能千行百业&#xff0c;AI 企业 NVIDIA 在架构底层算力的同时&#xff0c;也搭建了 NVIDIA AI Enterprise 和 Omniverse 两大平台。 …

【隧道篇 / WAN优化】(7.4) ❀ 03. WAN优化的原理 ❀ FortiGate 防火墙

【简介】相信对WAN优化感兴趣的人都会有疑问&#xff0c;WAN优化真的有作用吗&#xff1f;如果真的有作用&#xff0c;那是根据什么原理呢&#xff1f;让我们来更深入的了解一下。 客户端和服务器端 其实很多人在一开始看到WAN优化这个词&#xff0c;就自然的以为上网速度太慢&…

基于51单片机的智能垃圾桶仿真设计( proteus仿真+程序+设计报告+原理图+讲解视频)

这里写目录标题 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单资料下载链接&#xff1a; 基于51单片机智能垃圾桶仿真设计( proteus仿真程序设计报告原理图讲解视频&#xff09; 仿真图proteus8.9及以上 程序编译…

ABB RobotStudio学习记录(一)新建工作站

RobotStudio新建工作站 最近遇到 虚拟示教器和 Rapid 代码不能控制 视图中机械臂的问题&#xff0c;其实是由于机械臂和工作站不匹配。以下是解决方法。 名称版本Robot Studio6.08 新建一个”空工作站“&#xff1b; 在目标位置新建一个目标文件夹 C:\solution\test&#xff0…

鸿蒙内核源码分析(文件概念篇) | 为什么说一切皆是文件

什么是文件 不说清楚什么是文件就说不清楚文件系统,更说不清楚内核是如何管理和为什么要这么来管理文件的。现代操作系统为解决信息能独立于进程之外被长期存储引入了文件,将文件抽象成一个宽泛的概念,把文档、目录&#xff08;文件夹&#xff09;、键盘、监视器、硬盘、可移动…

视频监控平台:交通运输标准JTT808设备SDK接入源代码函数分享

目录 一、JT/T 808标准简介 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;协议特点 1、通信方式 2、鉴权机制 3、消息分类 &#xff08;三&#xff09;协议主要内容 1、位置信息 2、报警信息 3、车辆控制 4、数据转发 二、代码和解释 &#xff08;一…

C语言leetcode刷题笔记1

C语言leetcode刷题笔记1 第1题&#xff1a;136.只出现一次的数字两次遍历&#xff08;O(numsSize^2)&#xff09;位运算 第2题&#xff1a;202.快乐数快慢指针记录历史数据 第3题&#xff1a;53.最大子数组和暴力求解&#xff08;超时&#xff09;动态规划分治 第1题&#xff1…

机器学习初学者 6 个核心算法!建议收藏,反复观看!

今天再来介绍机器学习算法的基本概念和适用场景&#xff01; 首先&#xff0c;引用一句英国统计学家George E. P. Box的名言&#xff1a;All models are wrong, but some are useful. 没有哪一种算法能够适用所有情况&#xff0c;只有针对某一种问题更有用的算法。 也就是说&…

【新版系统架构】知识点背诵默写本

前言 系统架构考试在即&#xff0c;想要考试的人肯定感受到了沉甸甸的压力和紧迫感&#xff0c;脑海中不断闪过知识点的画面&#xff0c;却让人有些头昏脑胀&#xff0c;发现很难完全记住&#xff0c;这个考试很难&#xff0c;知识点很多。这次我在准备考试的同时&#xff0c;…

Android GPU渲染屏幕绘制显示基础概念(1)

Android GPU渲染屏幕绘制显示基础概念&#xff08;1&#xff09; Android中的图像生产者OpenGL&#xff0c;Skia&#xff0c;Vulkan将绘制的数据存放在图像缓冲区中&#xff0c;Android中的图像消费SurfaceFlinger从图像缓冲区将数据取出&#xff0c;进行加工及合成。 Surface…

华为云CodeArts API专场直播来袭!——探索API全生命周期管理新趋势

API的全生命周期管理是否让你摸不清头脑&#xff1f;你是否对API的前沿技术和应用充满了好奇&#xff0c;渴望一探究竟&#xff1f; 华为云PaaS服务即将在5月10日16:00&#xff0c;为你带来一场别开生面的CodeArts API专场直播活动&#xff01; 你可以在轻松愉快的氛围中&…

小巧简单实用的Linux端口转发工具Rinetd

Linux下实现端口转发有很多种方法&#xff0c;尤其是在可以联网的情况下&#xff0c;更是容易。最近在资源受限的定制系统中&#xff0c;找到一个方便离线安装和使用的端口转发工具Rinetd&#xff0c;安装包仅几十K&#xff0c;而且有很多版本的Linux发行系统的支持。 1、安装…

水质监测设备预警系统

随着工业化进程的加快和城市化水平的提高&#xff0c;水质安全问题愈发受到社会各界的广泛关注。为了确保水资源的清洁与安全&#xff0c;水质监测设备预警系统成为了不可或缺的利器。在这个背景下&#xff0c;HiWoo Cloud平台凭借其先进的技术和卓越的性能&#xff0c;为水质监…
最新文章