From 071a081aecd3f24c84fac9bfca57dafda6b989d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=82=85=E5=93=A5?= <184172133@qq.com> Date: Sat, 4 Nov 2023 09:48:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E5=82=85=E5=93=A5=EF=BC=8Cfeat?= =?UTF-8?q?=EF=BC=9Aredis=20=E6=A8=A1=E5=9D=97=EF=BC=8C=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=92=8C=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dev-ops/environment/docker-compose.yml | 13 +- docs/dev-ops/environment/redis/redis.conf | 3 + pom.xml | 11 +- xfg-frame-archetype-std-app/pom.xml | 8 +- .../cn/bugstack/config/RedisClientConfig.java | 84 +++++++ .../config/RedisClientConfigProperties.java | 38 +++ .../src/main/resources/application-dev.yml | 18 +- .../test/infrastructure/redis/RedisTest.java | 64 +++++ .../pom.xml | 5 + .../infrastructure/redis/IRedisService.java | 231 ++++++++++++++++++ .../infrastructure/redis/RedissonService.java | 149 +++++++++++ 11 files changed, 612 insertions(+), 12 deletions(-) create mode 100644 docs/dev-ops/environment/redis/redis.conf create mode 100644 xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfig.java create mode 100644 xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfigProperties.java create mode 100644 xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/redis/RedisTest.java create mode 100644 xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/IRedisService.java create mode 100644 xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/RedissonService.java diff --git a/docs/dev-ops/environment/docker-compose.yml b/docs/dev-ops/environment/docker-compose.yml index 65c89ae..816f0fe 100644 --- a/docs/dev-ops/environment/docker-compose.yml +++ b/docs/dev-ops/environment/docker-compose.yml @@ -28,7 +28,7 @@ services: depends_on: mysql: condition: service_healthy - + # MySQL mysql: image: mysql:8.0.32 container_name: mysql @@ -61,6 +61,17 @@ services: container_name: mysql-job-dbdata volumes: - /var/lib/mysql + # Redis + redis: + image: redis:7.2.0 + container_name: redis + ports: + - 6379:6379 + volumes: + - ./redis/redis.conf:/usr/local/etc/redis/redis.conf + command: redis-server /usr/local/etc/redis/redis.conf + networks: + - my-network networks: my-network: diff --git a/docs/dev-ops/environment/redis/redis.conf b/docs/dev-ops/environment/redis/redis.conf new file mode 100644 index 0000000..c251d9b --- /dev/null +++ b/docs/dev-ops/environment/redis/redis.conf @@ -0,0 +1,3 @@ +bind 0.0.0.0 +port 6379 +requirepass 123456 \ No newline at end of file diff --git a/pom.xml b/pom.xml index e2cf923..66d5610 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,6 @@ commons-codec 1.15 - org.apache.dubbo dubbo @@ -112,16 +111,16 @@ dubbo-spring-boot-starter 3.0.9 - - - - - com.alibaba.nacos nacos-client 2.1.0 + + org.redisson + redisson-spring-boot-starter + 3.23.4 + diff --git a/xfg-frame-archetype-std-app/pom.xml b/xfg-frame-archetype-std-app/pom.xml index ffb7b64..4bf649a 100644 --- a/xfg-frame-archetype-std-app/pom.xml +++ b/xfg-frame-archetype-std-app/pom.xml @@ -87,14 +87,14 @@ org.apache.dubbo dubbo-spring-boot-starter - - - - com.alibaba.nacos nacos-client + + org.redisson + redisson-spring-boot-starter + diff --git a/xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfig.java b/xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfig.java new file mode 100644 index 0000000..8add0cb --- /dev/null +++ b/xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfig.java @@ -0,0 +1,84 @@ +package cn.bugstack.config; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.BaseCodec; +import org.redisson.client.protocol.Decoder; +import org.redisson.client.protocol.Encoder; +import org.redisson.config.Config; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.io.IOException; + +/** + * Redis 客户端,使用 Redisson Redisson + * + * @author Fuzhengwei bugstack.cn @小傅哥 + */ +@Configuration +@EnableConfigurationProperties(RedisClientConfigProperties.class) +public class RedisClientConfig { + + @Bean("redissonClient") + public RedissonClient redissonClient(ConfigurableApplicationContext applicationContext, RedisClientConfigProperties properties) { + Config config = new Config(); + // 根据需要可以设定编解码器;https://github.com/redisson/redisson/wiki/4.-%E6%95%B0%E6%8D%AE%E5%BA%8F%E5%88%97%E5%8C%96 + // config.setCodec(new RedisCodec()); + + config.useSingleServer() + .setAddress("redis://" + properties.getHost() + ":" + properties.getPort()) + .setPassword(properties.getPassword()) + .setConnectionPoolSize(properties.getPoolSize()) + .setConnectionMinimumIdleSize(properties.getMinIdleSize()) + .setIdleConnectionTimeout(properties.getIdleTimeout()) + .setConnectTimeout(properties.getConnectTimeout()) + .setRetryAttempts(properties.getRetryAttempts()) + .setRetryInterval(properties.getRetryInterval()) + .setPingConnectionInterval(properties.getPingInterval()) + .setKeepAlive(properties.isKeepAlive()) + ; + + return Redisson.create(config); + } + + static class RedisCodec extends BaseCodec { + + private final Encoder encoder = in -> { + ByteBuf out = ByteBufAllocator.DEFAULT.buffer(); + try { + ByteBufOutputStream os = new ByteBufOutputStream(out); + JSON.writeJSONString(os, in, SerializerFeature.WriteClassName); + return os.buffer(); + } catch (IOException e) { + out.release(); + throw e; + } catch (Exception e) { + out.release(); + throw new IOException(e); + } + }; + + private final Decoder decoder = (buf, state) -> JSON.parseObject(new ByteBufInputStream(buf), Object.class); + + @Override + public Decoder getValueDecoder() { + return decoder; + } + + @Override + public Encoder getValueEncoder() { + return encoder; + } + + } + +} diff --git a/xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfigProperties.java b/xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfigProperties.java new file mode 100644 index 0000000..dc9f4cc --- /dev/null +++ b/xfg-frame-archetype-std-app/src/main/java/cn/bugstack/config/RedisClientConfigProperties.java @@ -0,0 +1,38 @@ +package cn.bugstack.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Fuzhengwei bugstack.cn @小傅哥 + * @description Redis 连接配置 redisson-spring-boot-starter + * @create 2023-09-03 16:51 + */ +@Data +@ConfigurationProperties(prefix = "redis.sdk.config", ignoreInvalidFields = true) +public class RedisClientConfigProperties { + + /** host:ip */ + private String host; + /** 端口 */ + private int port; + /** 账密 */ + private String password; + /** 设置连接池的大小,默认为64 */ + private int poolSize = 64; + /** 设置连接池的最小空闲连接数,默认为10 */ + private int minIdleSize = 10; + /** 设置连接的最大空闲时间(单位:毫秒),超过该时间的空闲连接将被关闭,默认为10000 */ + private int idleTimeout = 10000; + /** 设置连接超时时间(单位:毫秒),默认为10000 */ + private int connectTimeout = 10000; + /** 设置连接重试次数,默认为3 */ + private int retryAttempts = 3; + /** 设置连接重试的间隔时间(单位:毫秒),默认为1000 */ + private int retryInterval = 1000; + /** 设置定期检查连接是否可用的时间间隔(单位:毫秒),默认为0,表示不进行定期检查 */ + private int pingInterval = 0; + /** 设置是否保持长连接,默认为true */ + private boolean keepAlive = true; + +} diff --git a/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml b/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml index b40f3c2..9abba08 100644 --- a/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml +++ b/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml @@ -17,7 +17,7 @@ spring: datasource: username: root password: 123456 - url: jdbc:mysql://127.0.0.1:3306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true + url: jdbc:mysql://127.0.0.1:13306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true driver-class-name: com.mysql.cj.jdbc.Driver hikari: pool-name: Retail_HikariCP @@ -34,6 +34,22 @@ spring: # mapper-locations: classpath:/mybatis/mapper/*.xml # config-location: classpath:/mybatis/config/mybatis-config.xml +# Redis +redis: + sdk: + config: + host: 127.0.0.1 + port: 6379 + password: 123456 + pool-size: 10 + min-idle-size: 5 + idle-timeout: 30000 + connect-timeout: 5000 + retry-attempts: 3 + retry-interval: 1000 + ping-interval: 60000 + keep-alive: true + # Dubbo dubbo: application: diff --git a/xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/redis/RedisTest.java b/xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/redis/RedisTest.java new file mode 100644 index 0000000..b83dde5 --- /dev/null +++ b/xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/redis/RedisTest.java @@ -0,0 +1,64 @@ +package cn.bugstack.test.infrastructure.redis; + +import cn.bugstack.infrastructure.redis.IRedisService; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.redisson.api.RLock; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; + +/** + * Redis + * @author Fuzhengwei bugstack.cn @小傅哥 + */ +@Slf4j +@RunWith(SpringRunner.class) +@SpringBootTest +public class RedisTest { + + @Resource + private IRedisService redissonService; + + @Test + public void test_setValue() { + redissonService.setValue("xfg", "test123"); + log.info("设置属性值"); + } + + @Test + public void test_getValue() { + String xfg = redissonService.getValue("xfg"); + log.info("测试结果:{}", xfg); + } + + @Test + public void test_remove() { + redissonService.remove("60711088280"); + } + + /** + * 可重入锁,加锁和解锁。Redisson的分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口,同时还支持自动过期解锁。 + * lock.lock(); + * lock.lock(10, TimeUnit.SECONDS); + * lock.tryLock(3, 10, TimeUnit.SECONDS); + * lock.lockAsync(); + * lock.lockAsync(10, TimeUnit.SECONDS); + * Future res = lock.tryLockAsync(3, 10, TimeUnit.SECONDS); + */ + @Test + public void test_ReentrantLock() throws Exception { + RLock lock = redissonService.getLock(""); + try { + // 1. 最常见的使用方法 + lock.lock(); + + } finally { + lock.unlock(); + } + } + + +} diff --git a/xfg-frame-archetype-std-infrastructure/pom.xml b/xfg-frame-archetype-std-infrastructure/pom.xml index 55dea5f..c6d9022 100644 --- a/xfg-frame-archetype-std-infrastructure/pom.xml +++ b/xfg-frame-archetype-std-infrastructure/pom.xml @@ -18,6 +18,11 @@ org.projectlombok lombok + + org.redisson + redisson-spring-boot-starter + + cn.bugstack diff --git a/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/IRedisService.java b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/IRedisService.java new file mode 100644 index 0000000..1f9d0d8 --- /dev/null +++ b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/IRedisService.java @@ -0,0 +1,231 @@ +package cn.bugstack.infrastructure.redis; + +import org.redisson.api.*; + +/** + * Redis 服务 + * @author Fuzhengwei bugstack.cn @小傅哥 + */ +public interface IRedisService { + + /** + * 设置指定 key 的值 + * + * @param key 键 + * @param value 值 + */ + void setValue(String key, T value); + + /** + * 设置指定 key 的值 + * + * @param key 键 + * @param value 值 + * @param expired 过期时间 + */ + void setValue(String key, T value, long expired); + + /** + * 获取指定 key 的值 + * + * @param key 键 + * @return 值 + */ + T getValue(String key); + + /** + * 获取队列 + * + * @param key 键 + * @param 泛型 + * @return 队列 + */ + RQueue getQueue(String key); + + /** + * 加锁队列 + * + * @param key 键 + * @param 泛型 + * @return 队列 + */ + RBlockingQueue getBlockingQueue(String key); + + /** + * 延迟队列 + * + * @param rBlockingQueue 加锁队列 + * @param 泛型 + * @return 队列 + */ + RDelayedQueue getDelayedQueue(RBlockingQueue rBlockingQueue); + + /** + * 自增 Key 的值;1、2、3、4 + * + * @param key 键 + * @return 自增后的值 + */ + long incr(String key); + + /** + * 指定值,自增 Key 的值;1、2、3、4 + * + * @param key 键 + * @return 自增后的值 + */ + long incrBy(String key, long delta); + + /** + * 自减 Key 的值;1、2、3、4 + * + * @param key 键 + * @return 自增后的值 + */ + long decr(String key); + + /** + * 指定值,自增 Key 的值;1、2、3、4 + * + * @param key 键 + * @return 自增后的值 + */ + long decrBy(String key, long delta); + + + /** + * 移除指定 key 的值 + * + * @param key 键 + */ + void remove(String key); + + /** + * 判断指定 key 的值是否存在 + * + * @param key 键 + * @return true/false + */ + boolean isExists(String key); + + /** + * 将指定的值添加到集合中 + * + * @param key 键 + * @param value 值 + */ + void addToSet(String key, String value); + + /** + * 判断指定的值是否是集合的成员 + * + * @param key 键 + * @param value 值 + * @return 如果是集合的成员返回 true,否则返回 false + */ + boolean isSetMember(String key, String value); + + /** + * 将指定的值添加到列表中 + * + * @param key 键 + * @param value 值 + */ + void addToList(String key, String value); + + /** + * 获取列表中指定索引的值 + * + * @param key 键 + * @param index 索引 + * @return 值 + */ + String getFromList(String key, int index); + + /** + * 将指定的键值对添加到哈希表中 + * + * @param key 键 + * @param field 字段 + * @param value 值 + */ + void addToMap(String key, String field, String value); + + /** + * 获取哈希表中指定字段的值 + * + * @param key 键 + * @param field 字段 + * @return 值 + */ + String getFromMap(String key, String field); + + /** + * 将指定的值添加到有序集合中 + * + * @param key 键 + * @param value 值 + */ + void addToSortedSet(String key, String value); + + /** + * 获取 Redis 锁(可重入锁) + * + * @param key 键 + * @return Lock + */ + RLock getLock(String key); + + /** + * 获取 Redis 锁(公平锁) + * + * @param key 键 + * @return Lock + */ + RLock getFairLock(String key); + + /** + * 获取 Redis 锁(读写锁) + * + * @param key 键 + * @return RReadWriteLock + */ + RReadWriteLock getReadWriteLock(String key); + + /** + * 获取 Redis 信号量 + * + * @param key 键 + * @return RSemaphore + */ + RSemaphore getSemaphore(String key); + + /** + * 获取 Redis 过期信号量 + *

+ * 基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。 + * 同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。 + * + * @param key 键 + * @return RPermitExpirableSemaphore + */ + RPermitExpirableSemaphore getPermitExpirableSemaphore(String key); + + /** + * 闭锁 + * + * @param key 键 + * @return RCountDownLatch + */ + RCountDownLatch getCountDownLatch(String key); + + /** + * 布隆过滤器 + * + * @param key 键 + * @param 存放对象 + * @return 返回结果 + */ + RBloomFilter getBloomFilter(String key); + +} diff --git a/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/RedissonService.java b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/RedissonService.java new file mode 100644 index 0000000..7322585 --- /dev/null +++ b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/redis/RedissonService.java @@ -0,0 +1,149 @@ +package cn.bugstack.infrastructure.redis; + +import org.redisson.api.*; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.Duration; + +/** + * Redis 服务 - Redisson + * @author Fuzhengwei bugstack.cn @小傅哥 + */ +@Service("redissonService") +public class RedissonService implements IRedisService { + + @Resource + private RedissonClient redissonClient; + + public void setValue(String key, T value) { + redissonClient.getBucket(key).set(value); + } + + @Override + public void setValue(String key, T value, long expired) { + RBucket bucket = redissonClient.getBucket(key); + bucket.set(value, Duration.ofMillis(expired)); + } + + public T getValue(String key) { + return redissonClient.getBucket(key).get(); + } + + @Override + public RQueue getQueue(String key) { + return redissonClient.getQueue(key); + } + + @Override + public RBlockingQueue getBlockingQueue(String key) { + return redissonClient.getBlockingQueue(key); + } + + @Override + public RDelayedQueue getDelayedQueue(RBlockingQueue rBlockingQueue) { + return redissonClient.getDelayedQueue(rBlockingQueue); + } + + @Override + public long incr(String key) { + return redissonClient.getAtomicLong(key).incrementAndGet(); + } + + @Override + public long incrBy(String key, long delta) { + return redissonClient.getAtomicLong(key).addAndGet(delta); + } + + @Override + public long decr(String key) { + return redissonClient.getAtomicLong(key).decrementAndGet(); + } + + @Override + public long decrBy(String key, long delta) { + return redissonClient.getAtomicLong(key).addAndGet(-delta); + } + + @Override + public void remove(String key) { + redissonClient.getBucket(key).delete(); + } + + @Override + public boolean isExists(String key) { + return redissonClient.getBucket(key).isExists(); + } + + public void addToSet(String key, String value) { + RSet set = redissonClient.getSet(key); + set.add(value); + } + + public boolean isSetMember(String key, String value) { + RSet set = redissonClient.getSet(key); + return set.contains(value); + } + + public void addToList(String key, String value) { + RList list = redissonClient.getList(key); + list.add(value); + } + + public String getFromList(String key, int index) { + RList list = redissonClient.getList(key); + return list.get(index); + } + + public void addToMap(String key, String field, String value) { + RMap map = redissonClient.getMap(key); + map.put(field, value); + } + + public String getFromMap(String key, String field) { + RMap map = redissonClient.getMap(key); + return map.get(field); + } + + public void addToSortedSet(String key, String value) { + RSortedSet sortedSet = redissonClient.getSortedSet(key); + sortedSet.add(value); + } + + @Override + public RLock getLock(String key) { + return redissonClient.getLock(key); + } + + @Override + public RLock getFairLock(String key) { + return redissonClient.getFairLock(key); + } + + @Override + public RReadWriteLock getReadWriteLock(String key) { + return redissonClient.getReadWriteLock(key); + } + + @Override + public RSemaphore getSemaphore(String key) { + return redissonClient.getSemaphore(key); + } + + @Override + public RPermitExpirableSemaphore getPermitExpirableSemaphore(String key) { + return redissonClient.getPermitExpirableSemaphore(key); + } + + @Override + public RCountDownLatch getCountDownLatch(String key) { + return redissonClient.getCountDownLatch(key); + } + + @Override + public RBloomFilter getBloomFilter(String key) { + return redissonClient.getBloomFilter(key); + } + + +} -- GitLab