实战 Springboot2 集成Redis 哨兵模式、集群模式、缓存管理、Lettuce拓扑刷新
redis搭建集群模式、Cluster模式(6节点,3主3从集群模式,添加删除节点)_redis cluster节点带数据增减-CSDN博客
Linux部署Redis哨兵集群 一主两从三哨兵(这里使用Redis6,其它版本类似)_linux redis集群模式部署-CSDN博客
配置yaml
redis:redis-configs:redis-order:type: sentinel #standalone clusterhostAndPort: 192.168.132.1:16379,192.168.132.1:16380,192.168.132.1:16381masterName: mymasterpassword: dyj1username:database: 15timeout: 10000pool:max-idle: 8min-idle: 0max-active: 8max-wait: 10000
# redis-pay:
# type: standalone
# hostAndPort: localhost:6380
# database: 14
# timeout: 10000
# pool:
# max-idle: 8 # 连接池中的最大空闲连接 默认 8
# min-idle: 0 # 连接池中的最小空闲连接 默认 0
# max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 默认 8
# max-wait: 10000 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
# redis-order-cluster:
# type: cluster
# hostAndPort: xxx:6379,xxx:6379,xxx:6379
# database: 15
# timeout: 10000
# max-redirects: 3
# pool:
# max-idle: 8
# min-idle: 0
# max-active: 8
# max-wait: 10000
# redis-pay-cluster:
# type: cluster
# hostAndPort: xxx:6379,xxx:6379,xxx:6379
# database: 14
# timeout: 10000
# pool:
# max-idle: 8
# min-idle: 0
# max-active: 8
# max-wait: 10000
cache:caffeine:cache10M: "initialCapacity=20,maximumSize=100,expireAfterWrite=10m,recordStats"cache30s: "initialCapacity=20,maximumSize=100,expireAfterWrite=30s"redis:cache10M: "10"cache30s: "30"
redis连接池
package org.example.redis.config;import freemarker.template.utility.StringUtil;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnection;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.util.Pair;import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.*;@Configuration
@Data
@EnableConfigurationProperties({RedisPoolConfig.class})
public class RedisConnectionFactoryConfig {public static Map<String, LettuceConnectionFactory> redisConnectionFactors = new HashMap<>();@Autowiredprivate RedisPoolConfig redisPoolConfig;@PostConstructpublic void init() {redisPoolConfig.getRedisConfigs().forEach((name, config) -> {LettuceConnectionFactory redisConnectionFactory = null;LettuceClientConfiguration clientConfig = getClientConfiguration(config);switch (config.getType()) {case "standalone":RedisStandaloneConfiguration redisStandaloneConfiguration = createRedisStandaloneConfiguration(config);if (redisStandaloneConfiguration != null) {redisConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);}break;case "cluster":RedisClusterConfiguration redisClusterConfiguration = createRedisClusterConfiguration(config);if (redisClusterConfiguration != null) {redisConnectionFactory = new LettuceConnectionFactory(redisClusterConfiguration, clientConfig);}break;case "sentinel":RedisSentinelConfiguration redisSentinelConfiguration = createRedisSentinelConfiguration(config);if (redisSentinelConfiguration != null) {redisConnectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration, clientConfig);}break;default:System.out.printf("Unknown type: %d\n", config.getType());break;}if (null != redisConnectionFactory) {// 在获取连接时,先验证连接是否已经中断,如果已经中断则创建一个新的连接redisConnectionFactory.setValidateConnection(true);redisConnectionFactory.afterPropertiesSet(); // start() for spring-data-redis-3.X; afterPropertiesSet() for spring-data-redis-2.XredisConnectionFactors.putIfAbsent(name, redisConnectionFactory);}});}private LettuceClientConfiguration getClientConfiguration(RedisPoolConfig.Config config) {GenericObjectPoolConfig<LettuceConnection> poolConfig = new GenericObjectPoolConfig<>();if (StringUtils.isNotBlank(config.getPool().getMaxActive())) {poolConfig.setMaxTotal(Integer.parseInt(config.getPool().getMaxActive()));}if (StringUtils.isNotBlank(config.getPool().getMaxWait())) {poolConfig.setMaxWait(Duration.ofMillis(Integer.parseInt(config.getPool().getMaxWait())));}if (StringUtils.isNotBlank(config.getPool().getMaxIdle())) {poolConfig.setMaxIdle(Integer.parseInt(config.getPool().getMaxIdle()));}if (StringUtils.isNotBlank(config.getPool().getMinIdle())) {poolConfig.setMinIdle(Integer.parseInt(config.getPool().getMinIdle()));}int timeout = -1;if (StringUtils.isNotBlank(config.getTimeout())) {timeout = Integer.parseInt(config.getTimeout());}if (StringUtils.equals(config.getType(), "cluster")){// 支持自适应集群拓扑刷新和动态刷新源ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder().enableAllAdaptiveRefreshTriggers()// 开启自适应刷新.enableAdaptiveRefreshTrigger()// 开启定时刷新 default 60 SECONDS.enablePeriodicRefresh(Duration.ofSeconds(5)).build();ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder().topologyRefreshOptions(clusterTopologyRefreshOptions)// RedisTemplate通过StatefulRedisClusterConnection发送GET命令到Redis集群。// 根据Redis集群的哈希槽机制,命令被路由到正确的节点。// 如果键不存在于当前节点,会触发重定向(最多max-redirects次)直到找到正确的节点或者达到最大重定向次数。//.maxRedirects().build();LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig)//.readFrom(ReadFrom.SLAVE_PREFERRED) //读写分离:主写从读模式配置.clientOptions(clusterClientOptions).build();return lettuceClientConfiguration;}LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder().shutdownTimeout(Duration.ofMillis(timeout)).poolConfig(poolConfig).build();return clientConfig;}private RedisSentinelConfiguration createRedisSentinelConfiguration(RedisPoolConfig.Config config) {RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();redisSentinelConfiguration.setMaster(config.getMasterName());List<Pair<String, Integer>> hostAndPorts = parseClusterHostAndPort(config.getHostAndPort());if (hostAndPorts.isEmpty()) {return null;}for (Pair<String, Integer> hostAndPort : hostAndPorts) {RedisNode.RedisNodeBuilder builder = RedisNode.newRedisNode()
// .promotedAs(RedisNode.NodeType.SLAVE).listeningAt(hostAndPort.getFirst(), hostAndPort.getSecond());redisSentinelConfiguration.addSentinel(builder.build());}setUsername(config, redisSentinelConfiguration);setPassword(config, redisSentinelConfiguration);setDatabase(config, redisSentinelConfiguration);return redisSentinelConfiguration;}private RedisClusterConfiguration createRedisClusterConfiguration(RedisPoolConfig.Config config) {List<Pair<String, Integer>> hostAndPorts = parseClusterHostAndPort(config.getHostAndPort());if (hostAndPorts.isEmpty()) {return null;}RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();for (Pair<String, Integer> hostAndPort : hostAndPorts) {RedisNode node = new RedisNode(hostAndPort.getFirst(), hostAndPort.getSecond());redisClusterConfiguration.addClusterNode(node);}setUsername(config, redisClusterConfiguration);setPassword(config, redisClusterConfiguration);setClusterConf(config, redisClusterConfiguration);return redisClusterConfiguration;}private RedisStandaloneConfiguration createRedisStandaloneConfiguration(RedisPoolConfig.Config config) {Pair<String, Integer> hostAndPort = parseHostAndPort(config.getHostAndPort());if (null == hostAndPort) {return null;}RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(hostAndPort.getFirst());redisStandaloneConfiguration.setPort(hostAndPort.getSecond());setUsername(config, redisStandaloneConfiguration);setPassword(config, redisStandaloneConfiguration);setDatabase(config, redisStandaloneConfiguration);return redisStandaloneConfiguration;}private void setUsername(RedisPoolConfig.Config config, RedisConfiguration.WithPassword connectionFactory) {if (null != config.getUsername() && !config.getUsername().isEmpty()) {connectionFactory.setUsername(config.getUsername());}}private void setPassword(RedisPoolConfig.Config config, RedisConfiguration.WithPassword connectionFactory) {if (null != config.getPassword() && !config.getPassword().isEmpty()) {connectionFactory.setPassword(config.getPassword());}}private void setDatabase(RedisPoolConfig.Config config, RedisConfiguration.WithDatabaseIndex connectionFactory) {if (null != config.getDatabase() && !config.getDatabase().isEmpty()) {int database = Integer.parseInt(config.getDatabase());connectionFactory.setDatabase(database);}}private void setClusterConf(RedisPoolConfig.Config config, RedisClusterConfiguration redisClusterConfiguration) {if (null != config.getClusterMaxRedirects() && !config.getClusterMaxRedirects().isEmpty()) {int maxRedirects = Integer.parseInt(config.getClusterMaxRedirects());redisClusterConfiguration.setMaxRedirects(maxRedirects);}}private List<Pair<String, Integer>> parseClusterHostAndPort(String hostAndPortStr) {String[] hosts = hostAndPortStr.split(",");List<Pair<String, Integer>> hostAndPorts = new ArrayList<>();for (String hostAndPort : hosts) {Pair<String, Integer> pair = parseHostAndPort(hostAndPort);if (null != pair) {hostAndPorts.add(pair);}}return hostAndPorts;}private Pair<String, Integer> parseHostAndPort(String hostAndPortStr) {String[] hostAndPort = hostAndPortStr.split(":");if (hostAndPort.length != 2) {System.out.printf("Invalid host and port: %s\n", hostAndPortStr);return null;}String host = hostAndPort[0].trim();String port = hostAndPort[1].trim();return Pair.of(host, Integer.parseInt(port));}
}
缓存管理类
package org.example.redis.config;import com.github.benmanes.caffeine.cache.*;
import lombok.extern.slf4j.Slf4j;
import org.example.redis.listener.CaffeineCacheRemovalListener;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Slf4j
@Configuration
@EnableCaching
@EnableConfigurationProperties({CustomerCacheProperties.class})
public class CacheManagerConfiguration {public interface redisCacheKey {public final static String cache10M = "cache10M";public final static String cache30s = "cache30s";}public interface caffeineCacheKey {public final static String cache10M = "cache10M";public final static String cache30s = "cache30s";}@Resourceprivate CustomerCacheProperties customerCacheProperties;public interface CacheManagerNames {String REDIS_CACHE_MANAGER = "redisCacheManager";String LOCAL_CACHE_MANAGER = "localCacheManager";}@Bean(name = CacheManagerNames.REDIS_CACHE_MANAGER)@Primarypublic RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {Map<String, RedisCacheConfiguration> expires = new HashMap<>();customerCacheProperties.getRedis().forEach((name, time) -> {expires.put(name, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(Integer.parseInt(time))));});// Map<String, RedisCacheConfiguration> expires = ImmutableMap.<String, RedisCacheConfiguration>builder()
// .put(cache15, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(15)))
// .put(cache30, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(30)))
// .build();RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(factory).cacheDefaults(cacheConfiguration()).withInitialCacheConfigurations(expires)//事务感知功能有助于确保在事务提交之后缓存和数据库中的数据保持一致,这对于保证数据完整性和避免脏读非常重要。// 然而,这也可能会增加一些性能开销,因此在不需要强一致性的场景下,可以考虑禁用这个特性以提高性能.transactionAware().build();//以锁写入的方式创建RedisCacheWriter对象
// RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);return redisCacheManager;}@Beanpublic RedisCacheConfiguration cacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));}@Bean(name = CacheManagerNames.LOCAL_CACHE_MANAGER)public CacheManager caffeineCacheManager() {List<CaffeineCache> caffeineCaches = new ArrayList<>();customerCacheProperties.getCaffeine().forEach((name, spec) -> {CaffeineSpec caffeineSpec = CaffeineSpec.parse(spec);Caffeine<Object, Object> caffeine = Caffeine.from(caffeineSpec);caffeine.removalListener(new CaffeineCacheRemovalListener());// caffeineCache.executor(cacheExecutor);// 设置定时任务执行过期清除操作//.scheduler(Scheduler.systemScheduler())//cache对缓存写的通知回调caffeine.writer(new CacheWriter<Object, Object>() {@Overridepublic void write(Object key, Object value) {log.info("CacheManager write key={}", key);}@Overridepublic void delete(Object key, Object value, RemovalCause cause) {log.info("CacheManager delete key={}, cause={}", key, cause);}});// //使用CacheLoader创建一个LoadingCache
// caffeine.build(new CacheLoader<String, String>() {
// //同步加载数据
// @Override
// public String load(String key) throws Exception {
// log.info("CacheManager load key={}", key);
// return "value_" + key;
// }
//
// //异步加载数据
// @Override
// public String reload(String key, String oldValue) throws Exception {
// log.info("CacheManager reload key={}", key);
// return "value_" + key;
// }
// });CaffeineCache caffeineCache = new CaffeineCache(name, caffeine.build());caffeineCaches.add(caffeineCache);});SimpleCacheManager simpleCacheManager = new SimpleCacheManager();simpleCacheManager.setCaches(caffeineCaches);return simpleCacheManager;}// @Override
// @Cacheable(key = "#userId", cacheNames = CacheManagerConfiguration.CacheNames.CACHE_15MINS,
// cacheManager = CacheManagerConfiguration.CacheManagerNames.EHCACHE_CACHE_MANAGER)
// public User findUserAccordingToId(Long userId) {
// return userRepository.findById(userId).orElse(User.builder().build());
// }
//
// @Override
// @Cacheable(key = "#username", cacheNames = CacheManagerConfiguration.CacheNames.CACHE_15MINS,
// cacheManager = CacheManagerConfiguration.CacheManagerNames.REDIS_CACHE_MANAGER)
// public User findUserAccordingToUserName(String username) {
// return userRepository.findUserByUsername(username);
// }// @Cacheable( sync = true)}
创建不同的template
package org.example.redis.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import static org.example.redis.config.RedisConnectionFactoryConfig.redisConnectionFactors;@Configuration
@Data
@DependsOn("redisConnectionFactoryConfig")
public class RestTemplateConfig {@Bean(name = "orderStringRedisTemplate")@Primarypublic StringRedisTemplate orderStringRedisTemplate() {return buildStringRedisTemplate(redisConnectionFactors.get("redis-order"));}//
// public RedisTemplate<String, Object> buildObjRedisTemplate(RedisConnectionFactory factory) {
//
// RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// redisTemplate.setConnectionFactory(factory);
//
// Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();
// redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// redisTemplate.setKeySerializer(new StringRedisSerializer());
//
// redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
// redisTemplate.afterPropertiesSet();
// return redisTemplate;
// }public StringRedisTemplate buildStringRedisTemplate(RedisConnectionFactory factory) {StringRedisTemplate redisTemplate = new StringRedisTemplate(factory);Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);return jackson2JsonRedisSerializer;}}
使用实体类接收,使用Map接收。key需要根据自己的业务区分即可
package org.example.redis.config;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "redis")
public class RedisPoolConfig {public Map<String, Config> redisConfigs;@NoArgsConstructor@AllArgsConstructor@Datapublic static class Config {private String name;private String type;private String hostAndPort;private String username;private String password;private String database;
// private String sentinelMasterHostAndPort; // for Sentineprivate String masterName; // for Sentineprivate String clusterMaxRedirects; // for Clusterprivate String timeout;private PoolConfig pool;@Data@NoArgsConstructor@AllArgsConstructorpublic static class PoolConfig {private String maxIdle;private String minIdle;private String maxActive;private String maxWait;}}
}
缓存redis 以及caffeine
package org.example.redis.config;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "cache")
public class CustomerCacheProperties {public Map<String, String> caffeine;public Map<String, String> redis;
}
<!-- lettuce这个客户端--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId> </dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>2.9.3</version> </dependency>
相关文章:
实战 Springboot2 集成Redis 哨兵模式、集群模式、缓存管理、Lettuce拓扑刷新
redis搭建集群模式、Cluster模式(6节点,3主3从集群模式,添加删除节点)_redis cluster节点带数据增减-CSDN博客 Linux部署Redis哨兵集群 一主两从三哨兵(这里使用Redis6,其它版本类似)_linux red…...
MYSQL--binlog和redo log
前言 MySQL日志 MySQL日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中比较重要的就是二进制日志binlog(归档日志)、事务日志redo log(重做日志)和undo log(回滚日志)。 这篇…...

R语言医疗数据分析笔记
分组因子又是什么意思,分组因子和数组的区别是什么 举个实际的例子 分组因子 分组因子是分类变量,用于将数据分成不同组以便于比较或分析。例如,在一项研究中,研究对象的性别(男性和女性)可以视为一个分组…...
SpringBoot使用Jackson-XML裁剪多余的根节点
相关博客:《SpringBoot集成WebService(wsdl)》 比如我们有以下入参 我们只需要MedicalCardInfo这个根节点,其余都不要。如何处理? <A><B><Sender>Aa</Sender><MsgType>Bb</MsgType><MsgVersion>…...

vue路由学习
1、基本了解 (1) (2) (3)在创建vue项目时,就已经勾选了vue-router 2、 (0)自己手写了一个新的组件文件(部门管理)(DeptView.vue) (1&a…...
Kubernetes基于helm部署Kafka_Kraft集群并取消SASL认证且开启数据持久化
注:本文档部署Kafka时,取消了默认的SASL认证的相关配置,并开启了数据持久化。 一、添加并更新Helm仓库 helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update bitnami二、下载并解压kafka的Chart helm pull bitna…...
kotlin -- Flow和Rxjava 对比
引言 我们先说说,关键词 响应式编程,数据流,观察者模式。 观察者模式 一个button setOnClickListener 就是观察者模式。 button是被观察者,它产生一个事件(点击),观察者OnClickListener接收到,做出相…...

【JVM篇】自动内存管理——HotSpot虚拟机对象探秘
目录 前言 一、对象的创建 二、对象的内存布局 三、对象的访问定位 总结 前言 相关文章:【JVM篇】自动内存管理——运行时数据区-CSDN博客 介绍完Java虚拟机的运行时数据区域之后,我们大致明白了Java虚拟机内存模型的概况,但可能会好奇其…...
代谢组数据分析(十七):基于structToolbox代谢组分析流程讲解
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 介绍 structToolbox 是一个广泛使用的工具箱,专门用于代谢组学和其他组学数据的分析。它提供了一系列的数据预处理、统计分析和机器学习方法,特别强调统计和机器学习的重要性。这个工具箱允许…...

科普课堂走起 | 什么是网络安全和数据安全?
网络安全和数据安全是现代数字世界中非常重要的两个概念。让我们来详细了解一下这两个领域。 1.网络安全(Network Security) 网络安全是指保护网络系统免受未经授权的访问、攻击、破坏或滥用的一系列技术和过程。它旨在确保信息的机密性、完整性和可用…...
C语言中常用的函数
处理字符串常用的函数 size_t strspn(const char *s, const char *accept); 函数参数说明: s是被查找的字符串 accepct是要匹配的字符串函数功能说明: 它返回s字符串起始部分中,完全由accept字符串中的字符组成的子字符串的长度函数返回值…...
如何在SpringBoot中进行单元测试?
在Spring Boot中进行单元测试通常会涉及以下几个步骤: 1. 添加测试依赖 确保在你的pom.xml(Maven)或build.gradle(Gradle)中包含了Spring Boot的测试依赖。Spring Boot的Starter依赖spring-boot-starter-test通常已经…...

分布式事务学习整理
一、整体背景 最近在分布式事务领域这块的了解比较少,对自己来说是一个业务盲点,所以想抽空学习以及整理下关于分布式事务的相关知识。 1、分布式事务的发展 总所周知,我们为什么要考虑分布式事务,从一开始发展来说,…...
Conda配置瘦身术:精通conda config --remove命令
Conda配置瘦身术:精通conda config --remove命令 Conda作为Python和其他科学计算语言的包管理器,其灵活性和强大功能在很大程度上依赖于其配置系统。随着时间的推移,Conda配置可能会变得复杂和冗余。conda config --remove命令提供了一种方法…...

Windows下编译安装PETSc
本文记录在Windows下使用MinGW-w64编译安装PETSc的流程。 0、环境 操作系统Windows 11MSYS2msys2-x86_64-20240507 1、开发环境 首先,下载并安装MSYS2,然后编辑PATH环境变量,添加mingw64相关路径:C:\msys64\mingw64\bin。 然…...

phpstudy搭建sqlilabs本地靶场
请先在网上解决好前置条件的下载和安装:phpstudy、vscode、navicat premium(非必要)、sqlilab的压缩包/文件夹 phpstudy--安装sqlilabs 1.打开phpstudy后,我们会用到MySQL5.7.26和Nginx1.15.11 #mysql5.7.26是因为sqlilabs靶场不支持高版本MySQL 2.在软…...

Linux 实验基础环境准备(外网篇)
1.关闭禁用防火墙和selinux systemctl disable firewalld --now sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config2.保证可以连接外网 ping -c3 www.baidu.com 3.配置yum为阿里仓库并下载epel源 mkdir /etc/yum.repos.d/bak/; mv /etc/yum.repos.d/*.repo /e…...
centos8 安装mysql 制作备份数据库脚本
1、配置阿里云源 cd /etc/yum.repos.d/ vim CentOS-Stream-AppStream.repo [appstream] nameCentOS Stream $releasever - AppStream #mirrorlisthttp://mirrorlist.centos.org/?release$stream&arch$basearch&repoAppStream&infra$infra baseurlhttp://mirrors…...

Parsing error: The keyword ‘interface‘ is reserved配置优化
当我们在创建Vue项目时,Vue默认是配置了eslint代码规范检查的,不过我们在项目中Typescript来编写代码时,却报了标题的错误,对应的代码如下: <script lang="ts"> export default{name: "DlHeader" } </script><script setup lang=&quo…...

C语言指针详解-包过系列(二)目录版
C语言指针详解-包过系列(二)目录版 1、数组名的深入理解1.1、数组名的本质1.2、数组名本质的两个例外1.2.1、sizeof(数组名)1.2.2、&数组名 2、使用指针访问数组3、一维数组传参本质4、二级指针4.1、二级指针介绍4.2、二级指针…...

《探秘跨网段局域网IP广播:解锁网络通信的新姿势》
一、从基础出发:广播与跨网段 在计算机网络的世界中,广播域是一个至关重要的概念。简单来说,广播域是指网络中能接收任一台主机发出的广播帧的所有主机集合。当一台主机在广播域内发出一个广播帧时,同一广播域内的所有其他主机都可以收到该广播帧。在没有路由器或 VLAN 分割…...
OpenWrt:使用ALSA实现边录边播
ALSA是Linux系统中的高级音频架构(Advanced Linux Sound Architecture)。目前已经成为了linux的主流音频体系结构,想了解更多的关于ALSA的知识,详见:http://www.alsa-project.org 在内核设备驱动层,ALSA提供…...

C语言中的数据类型(二)--结构体
在之前我们已经探讨了C语言中的自定义数据类型和数组,链接如下:C语言中的数据类型(上)_c语言数据类型-CSDN博客 目录 一、结构体的声明 二、结构体变量的定义和初始化 三、结构体成员的访问 3.1 结构体成员的直接访问 3.2 结…...
React 中 HTML 插入的全场景实践与安全指南
在 React 开发过程中,我们常常会遇到需要插入 HTML 内容的场景。比如将服务端返回的富文本渲染到页面,还有处理复杂的 UI 结构,正确的 HTML 插入方式不仅影响页面展示效果,更关乎应用的安全性。 本文将详细探讨 React 中插入 HTM…...
NoSQL 之 Redis 配置与优化
目录 一、 前置知识点 1. 关系数据库与非关系型数据库 (1)关系型数据库 (2)非关系型数据库 (3)非关系型数据库产生背景 (4)两者对比 2. Redis 基础 (1࿰…...
赋能大型语言模型与外部世界交互——函数调用的崛起
大型语言模型 (LLM) 近年来在自然语言处理领域取得了革命性的进展,展现出强大的文本理解、生成和对话能力。然而,这些模型在与外部实时数据源和动态系统交互方面存在固有的局限性 1。它们主要依赖于训练阶段学习到的静态知识,难以直接访问和利…...
QuickJS 如何发送一封邮件 ?
参阅:bellard.org : QuickJS 如何使用 qjs 执行 js 脚本 在 QuickJS 中发送邮件需要依赖外部库或调用系统命令,因为 QuickJS 本身不包含 SMTP 功能。以下是两种实现方法: 方法 1:调用系统命令(推荐) 使…...

如何轻松、安全地管理密码(新手指南)
很多人会为所有账户使用相同、易记的密码,而且常常多年不换。虽然这样方便记忆,但安全性非常低。 您可能听说过一些大型网站的信息泄露事件,同样的风险也可能存在于您的WordPress网站中。如果有不法分子获取了访问权限,您的网站和…...

vue3 + vite实现动态路由,并进行vuex持久化设计
在后台管理系统中,如何根据后端返回的接口,来动态的设计路由呢,今天一片文章带你们解 1、在vuex中设置一个方法 拿到完整的路由数据 const state {routerList: []}; const mutations { dynameicMenu(state, payload) {// 第一步 通过glob…...
【nano与Vim】常用命令
使用nano编辑器 保存文件 : 按下CtrlO组合键,然后按Enter键确认文件名。 退出编辑器 : 按下CtrlX组合键。 使用vi或vim编辑器 保存文件 : 按Esc键退出插入模式,然后输入:w并按Enter键保存文件。 退出编辑器 …...