From e428fe166f69f50c4e1b172fbc912e6b16344225 Mon Sep 17 00:00:00 2001 From: cicadasmile <1327880701@qq.com> Date: Thu, 4 Jul 2019 23:19:01 +0800 Subject: [PATCH] =?UTF-8?q?SpringBoot2.0=20=E6=95=B4=E5=90=88=20Redis?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=20,=E5=AE=9E=E7=8E=B0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=98=9F=E5=88=97=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++ pom.xml | 6 +- ware-redis-cluster/pom.xml | 88 +++++++++++++++++++ .../com/redis/cluster/RedisApplication.java | 12 +++ .../com/redis/cluster/config/RedisConfig.java | 17 ++++ .../com/redis/cluster/config/RedisLock.java | 41 +++++++++ .../com/redis/cluster/config/RedisParam.java | 86 ++++++++++++++++++ .../com/redis/cluster/config/RedisPool.java | 45 ++++++++++ .../com/redis/cluster/controller/MsgBody.java | 36 ++++++++ .../cluster/controller/RedisController.java | 48 ++++++++++ .../com/redis/cluster/listen/LogAListen.java | 39 ++++++++ .../redis/cluster/listen/RedisHandler.java | 13 +++ .../redis/cluster/listen/RedisListener.java | 60 +++++++++++++ .../redis/cluster/service/RedisService.java | 5 ++ .../service/impl/RedisServiceImpl.java | 27 ++++++ .../com/redis/cluster/utils/SpringUtil.java | 31 +++++++ .../src/main/resources/application-dev.yml | 14 +++ .../src/main/resources/application.yml | 14 +++ 18 files changed, 584 insertions(+), 3 deletions(-) create mode 100644 ware-redis-cluster/pom.xml create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/RedisApplication.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisConfig.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisLock.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisParam.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisPool.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/controller/MsgBody.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/controller/RedisController.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/listen/LogAListen.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisHandler.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisListener.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/service/RedisService.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/service/impl/RedisServiceImpl.java create mode 100644 ware-redis-cluster/src/main/java/com/redis/cluster/utils/SpringUtil.java create mode 100644 ware-redis-cluster/src/main/resources/application-dev.yml create mode 100644 ware-redis-cluster/src/main/resources/application.yml diff --git a/README.md b/README.md index 1b08aaa..567c9d4 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,11 @@ 5、SpringBoot2.0 整合 QuartJob ,实现定时器实时管理
+ +6、SpringBoot2.0 整合 Redis集群 ,实现消息队列场景
+ +持续更新中... + ## 项目简介 SpringBoot 集成常用中间件 diff --git a/pom.xml b/pom.xml index e66d22a..4ccb44c 100644 --- a/pom.xml +++ b/pom.xml @@ -23,12 +23,12 @@ ware-rocket-queue ware-shard-jdbc - - - + ware-email-send ware-swagger-two + + ware-redis-cluster diff --git a/ware-redis-cluster/pom.xml b/ware-redis-cluster/pom.xml new file mode 100644 index 0000000..fb90253 --- /dev/null +++ b/ware-redis-cluster/pom.xml @@ -0,0 +1,88 @@ + + + + middle-ware-parent + com.boot.parent + 1.0-SNAPSHOT + + 4.0.0 + + com.redis.cluster + ware-redis-cluster + jar + + + + org.springframework.boot + spring-boot-starter-data-redis + ${spring-boot.version} + + + redis.clients + jedis + ${redis-client.version} + + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + + + org.springframework.boot + spring-boot-starter-aop + ${spring-boot.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + true + + + org.springframework + spring-context-support + ${spring.version} + + + joda-time + joda-time + ${joda.time.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + + + + ${project.artifactId} + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/RedisApplication.java b/ware-redis-cluster/src/main/java/com/redis/cluster/RedisApplication.java new file mode 100644 index 0000000..84e592d --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/RedisApplication.java @@ -0,0 +1,12 @@ +package com.redis.cluster; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) +public class RedisApplication { + public static void main(String[] args) { + SpringApplication.run(RedisApplication.class,args) ; + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisConfig.java b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisConfig.java new file mode 100644 index 0000000..a9cb62a --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisConfig.java @@ -0,0 +1,17 @@ +package com.redis.cluster.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; + +@Configuration +public class RedisConfig { + + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { + StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); + stringRedisTemplate.setConnectionFactory(factory); + return stringRedisTemplate; + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisLock.java b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisLock.java new file mode 100644 index 0000000..3cd3987 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisLock.java @@ -0,0 +1,41 @@ +package com.redis.cluster.config; + +import org.springframework.stereotype.Component; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisSentinelPool; +import javax.annotation.Resource; + +@Component +public class RedisLock { + private static String keyPrefix = "RedisLock:"; + @Resource + private JedisSentinelPool jedisSentinelPool; + + public boolean addLock(String key, long expire) { + Jedis jedis = null; + try { + jedis = jedisSentinelPool.getResource(); + /* + * nxxx的值只能取NX或者XX,如果取NX,则只有当key不存在是才进行set,如果取XX,则只有当key已经存在时才进行set + * expx的值只能取EX或者PX,代表数据过期时间的单位,EX代表秒,PX代表毫秒。 + */ + String value = jedis.set(keyPrefix + key, "1", "nx", "ex", expire); + return value != null; + } catch (Exception e){ + e.printStackTrace(); + }finally { + if (jedis != null) jedis.close(); + } + return false; + } + + public void removeLock(String key) { + Jedis jedis = null; + try { + jedis = jedisSentinelPool.getResource(); + jedis.del(keyPrefix + key); + } finally { + if (jedis != null) jedis.close(); + } + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisParam.java b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisParam.java new file mode 100644 index 0000000..e1e6c74 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisParam.java @@ -0,0 +1,86 @@ +package com.redis.cluster.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "spring.redis.sentinel") +public class RedisParam { + + private String nodes ; + private String master ; + private Integer maxTotal ; + private Integer minIdle ; + private Integer maxWaitMillis ; + private Integer timeBetweenEvictionRunsMillis ; + private boolean testWhileIdle ; + private boolean testOnBorrow ; + private boolean testOnReturn ; + + public String getNodes() { + return nodes; + } + public void setNodes(String nodes) { + this.nodes = nodes; + } + public String getMaster() { + return master; + } + public void setMaster(String master) { + this.master = master; + } + + public Integer getMaxTotal() { + return maxTotal; + } + + public void setMaxTotal(Integer maxTotal) { + this.maxTotal = maxTotal; + } + + public Integer getMinIdle() { + return minIdle; + } + + public void setMinIdle(Integer minIdle) { + this.minIdle = minIdle; + } + + public Integer getMaxWaitMillis() { + return maxWaitMillis; + } + + public void setMaxWaitMillis(Integer maxWaitMillis) { + this.maxWaitMillis = maxWaitMillis; + } + + public Integer getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public boolean isTestWhileIdle() { + return testWhileIdle; + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisPool.java b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisPool.java new file mode 100644 index 0000000..8d6788a --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/config/RedisPool.java @@ -0,0 +1,45 @@ +package com.redis.cluster.config; + +import com.redis.cluster.listen.RedisListener; +import com.redis.cluster.utils.SpringUtil; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import redis.clients.jedis.JedisSentinelPool; +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +@Configuration +@EnableConfigurationProperties(RedisParam.class) +public class RedisPool { + + @Resource + private RedisParam redisParam ; + + @Bean("jedisSentinelPool") + public JedisSentinelPool getRedisPool (){ + Set sentinels = new HashSet<>(); + sentinels.addAll(Arrays.asList(redisParam.getNodes().split(","))); + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); + poolConfig.setMaxTotal(redisParam.getMaxTotal()); + poolConfig.setMinIdle(redisParam.getMinIdle()); + poolConfig.setMaxWaitMillis(redisParam.getMaxWaitMillis()); + poolConfig.setTestWhileIdle(redisParam.isTestWhileIdle()); + poolConfig.setTestOnBorrow(redisParam.isTestOnBorrow()); + poolConfig.setTestOnReturn(redisParam.isTestOnReturn()); + poolConfig.setTimeBetweenEvictionRunsMillis(redisParam.getTimeBetweenEvictionRunsMillis()); + JedisSentinelPool redisPool = new JedisSentinelPool(redisParam.getMaster(), sentinels, poolConfig); + return redisPool; + } + @Bean + SpringUtil springUtil() { + return new SpringUtil(); + } + @Bean + RedisListener redisListener() { + return new RedisListener(); + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/controller/MsgBody.java b/ware-redis-cluster/src/main/java/com/redis/cluster/controller/MsgBody.java new file mode 100644 index 0000000..1da3ef2 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/controller/MsgBody.java @@ -0,0 +1,36 @@ +package com.redis.cluster.controller; + +import java.util.Date; + +public class MsgBody { + + private String name ; + + private String desc ; + + private Date createTime ; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/controller/RedisController.java b/ware-redis-cluster/src/main/java/com/redis/cluster/controller/RedisController.java new file mode 100644 index 0000000..62d9421 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/controller/RedisController.java @@ -0,0 +1,48 @@ +package com.redis.cluster.controller; + +import com.alibaba.fastjson.JSONObject; +import com.redis.cluster.service.RedisService; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisSentinelPool; +import javax.annotation.Resource; +import java.util.Date; + +@RestController +public class RedisController { + + @Resource + private RedisService redisService ; + @Resource + private StringRedisTemplate stringRedisTemplate; + @Resource + private JedisSentinelPool jedisSentinelPool; + + @RequestMapping("/increment") + public String increment (){ + stringRedisTemplate.opsForValue().increment("cicada-key",10L) ; + return "success" ; + } + + @RequestMapping("/sentinel") + public String sentinel (){ + Jedis jedis = jedisSentinelPool.getResource() ; + jedis.set("sentinel","sentinel") ; + return "success" ; + } + + /** + * 队列推消息 + */ + @RequestMapping("/saveQueue") + public String saveQueue (){ + MsgBody msgBody = new MsgBody() ; + msgBody.setName("LogAModel"); + msgBody.setDesc("描述"); + msgBody.setCreateTime(new Date()); + redisService.saveQueue("LogA-key", JSONObject.toJSONString(msgBody)); + return "success" ; + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/listen/LogAListen.java b/ware-redis-cluster/src/main/java/com/redis/cluster/listen/LogAListen.java new file mode 100644 index 0000000..a22e14a --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/listen/LogAListen.java @@ -0,0 +1,39 @@ +package com.redis.cluster.listen; + +import com.redis.cluster.config.RedisLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; + +@Component +public class LogAListen implements RedisHandler { + + private static final Logger LOG = LoggerFactory.getLogger(LogAListen.class) ; + @Resource + private RedisLock redisLock; + @Override + public String queueName() { + return "LogA-key"; + } + @Override + public String consume(String msgBody) { + // 加锁,防止消息重复投递 + String lockKey = "lock-order-uuid-A"; + boolean lock = false; + try { + lock = redisLock.addLock(lockKey, 60); + if (!lock) { + return "success"; + } + LOG.info("LogA-key == >>" + msgBody); + } catch (Exception e){ + e.printStackTrace(); + } finally { + if (lock) { + redisLock.removeLock(lockKey); + } + } + return "success"; + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisHandler.java b/ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisHandler.java new file mode 100644 index 0000000..cffcaaf --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisHandler.java @@ -0,0 +1,13 @@ +package com.redis.cluster.listen; + +public interface RedisHandler { + /** + * 队列名称 + */ + String queueName(); + + /** + * 队列消息内容 + */ + String consume (String msgBody); +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisListener.java b/ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisListener.java new file mode 100644 index 0000000..5ab8df1 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/listen/RedisListener.java @@ -0,0 +1,60 @@ +package com.redis.cluster.listen; + +import com.redis.cluster.utils.SpringUtil; +import org.springframework.beans.factory.InitializingBean; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisSentinelPool; +import javax.annotation.Resource; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class RedisListener implements InitializingBean { + /** + * Redis 集群 + */ + @Resource + private JedisSentinelPool jedisSentinelPool; + private List handlers = null; + private ExecutorService product = null; + private ExecutorService consumer = null; + /** + * 初始化配置 + */ + @Override + public void afterPropertiesSet() { + handlers = SpringUtil.getBeans(RedisHandler.class) ; + product = new ThreadPoolExecutor(10,15,60 * 3, + TimeUnit.SECONDS,new SynchronousQueue<>()); + consumer = new ThreadPoolExecutor(10,15,60 * 3, + TimeUnit.SECONDS,new SynchronousQueue<>()); + for (RedisHandler redisHandler : handlers){ + product.execute(() -> { + redisTask(redisHandler); + }); + } + } + /** + * 队列监听 + */ + public void redisTask (RedisHandler redisHandler){ + Jedis jedis = null ; + while (true){ + try { + jedis = jedisSentinelPool.getResource() ; + List msgBodyList = jedis.brpop(0, redisHandler.queueName()); + if (msgBodyList != null && msgBodyList.size()>0){ + consumer.execute(() -> { + redisHandler.consume(msgBodyList.get(1)) ; + }); + } + } catch (Exception e){ + e.printStackTrace(); + } finally { + if (jedis != null) jedis.close(); + } + } + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/service/RedisService.java b/ware-redis-cluster/src/main/java/com/redis/cluster/service/RedisService.java new file mode 100644 index 0000000..d1f49e8 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/service/RedisService.java @@ -0,0 +1,5 @@ +package com.redis.cluster.service; + +public interface RedisService { + void saveQueue (String queueKey ,String msgBody) ; +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/service/impl/RedisServiceImpl.java b/ware-redis-cluster/src/main/java/com/redis/cluster/service/impl/RedisServiceImpl.java new file mode 100644 index 0000000..7ed1453 --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/service/impl/RedisServiceImpl.java @@ -0,0 +1,27 @@ +package com.redis.cluster.service.impl; + +import com.redis.cluster.service.RedisService; +import org.springframework.stereotype.Service; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisSentinelPool; +import javax.annotation.Resource; + +@Service +public class RedisServiceImpl implements RedisService { + + @Resource + private JedisSentinelPool jedisSentinelPool; + + @Override + public void saveQueue(String queueKey, String msgBody) { + Jedis jedis = null; + try { + jedis = jedisSentinelPool.getResource(); + jedis.lpush(queueKey,msgBody) ; + } catch (Exception e){ + e.printStackTrace(); + } finally { + if (jedis != null) jedis.close(); + } + } +} diff --git a/ware-redis-cluster/src/main/java/com/redis/cluster/utils/SpringUtil.java b/ware-redis-cluster/src/main/java/com/redis/cluster/utils/SpringUtil.java new file mode 100644 index 0000000..c10ba5e --- /dev/null +++ b/ware-redis-cluster/src/main/java/com/redis/cluster/utils/SpringUtil.java @@ -0,0 +1,31 @@ +package com.redis.cluster.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class SpringUtil implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringUtil.applicationContext = applicationContext; + } + public static T getBean(Class clazz) { + return applicationContext.getBean(clazz); + } + + public static T getBean(String name, Class clazz) { + return applicationContext.getBean(name, clazz); + } + + public static List getBeans(Class clz) { + Map map = applicationContext.getBeansOfType(clz); + return new ArrayList<>(map.values()); + } +} diff --git a/ware-redis-cluster/src/main/resources/application-dev.yml b/ware-redis-cluster/src/main/resources/application-dev.yml new file mode 100644 index 0000000..6164622 --- /dev/null +++ b/ware-redis-cluster/src/main/resources/application-dev.yml @@ -0,0 +1,14 @@ +spring: + # Redis 集群 + redis: + sentinel: + # sentinel 配置 + master: mymaster + nodes: 192.168.0.127:26379 + maxTotal: 60 + minIdle: 10 + maxWaitMillis: 10000 + testWhileIdle: true + testOnBorrow: true + testOnReturn: false + timeBetweenEvictionRunsMillis: 10000 diff --git a/ware-redis-cluster/src/main/resources/application.yml b/ware-redis-cluster/src/main/resources/application.yml new file mode 100644 index 0000000..b5aa42c --- /dev/null +++ b/ware-redis-cluster/src/main/resources/application.yml @@ -0,0 +1,14 @@ +# Tomcat +server: + tomcat: + uri-encoding: UTF-8 + max-threads: 1000 + min-spare-threads: 30 + port: 7006 + connection-timeout: 5000ms + +spring: + application: + name: ware-redis-cluster + profiles: + active: dev \ No newline at end of file