Java Redis+Spring-data-redis 队列 单机版
1、redis.properties
##redisIP地址 #redis.host=10.14.2.212 redis.host=127.0.0.1 ##redis默认端口号 redis.port=6379 #redis密码 redis.pass=a7217sec!@# ##redis.database=0 ##指定使用第几个库 redis.maxIdle=300 redis.maxActive=600 redis.maxWait=1000 redis.testOnBorrow=true redis.timeout=1000 redis.pool.maxActive=200 redis.pool.maxIdle=50 redis.pool.minIdle=0 redis.pool.maxWait=15000 ##向调用者输出链接资源时,是否检测是否有效,如果无效则从连接池中移除,尝试继续获取,默认为false,建议保留默认值 redis.pool.testOnBorrow=false ##向连接池“归还”链接时,是否检测“链接”对象的有效性。默认为false。建议保持默认值. redis.pool.testOnReturn=false ##maxActive: 链接池中最大连接数,默认为8. ##maxIdle: 链接池中最大空闲的连接数,默认为8. ##minIdle: 连接池中最少空闲的连接数,默认为0. ##maxWait: 当连接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位,毫秒数;默认为-1.表示永不超时. ##minEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除。 ##softMinEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲链接将会被移除,且保留“minIdle”个空闲连接数。默认为-1. ##numTestsPerEvictionRun: 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3. ##testOnBorrow: 向调用者输出“链接”资源时,是否检测是有有效,如果无效则从连接池中移除,并尝试获取继续获取。默认为false。建议保持默认值. ##testOnReturn: 向连接池“归还”链接时,是否检测“链接”对象的有效性。默认为false。建议保持默认值. ##testWhileIdle:false 向调用者输出“链接”对象时,是否检测它的空闲超时;默认为false。如果“链接”空闲超时,将会被移除。建议保持默认值. ##timeBetweenEvictionRunsMillis: “空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1. ##whenExhaustedAction: 当“连接池”中active数量达到阀值时,即“链接”资源耗尽时,连接池需要采取的手段, 默认为1: ## -> 0 : 抛出异常, ## -> 1 : 阻塞,直到有可用链接资源 ## -> 2 : 强制创建新的链接资源
2、spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:annotation-config /> <!-- 引入外部属性文件. --> <context:property-placeholder location="classpath*:redis.properties" ignore-unresolvable="true" /> <!-- 注册 --> <context:component-scan base-package="com.xiaomei.queue.redis.demo01"/> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!--<property name="maxTotal" value="${redis.pool.maxActive}" />--> <!--最大空闲连接数 --> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <!--初始化连接数 --> <property name="minIdle" value="${redis.pool.minIdle}" /> <!--最大等待时间 --> <property name="maxWaitMillis" value="${redis.pool.maxWait}" /> <!--对拿到的connection进行validateObject校验 --> <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> <!--在进行returnObject对返回的connection进行validateObject校验 --> <property name="testOnReturn" value="${redis.pool.testOnReturn}" /> <!--定时对线程池中空闲的链接进行validateObject校验 --> <property name="testWhileIdle" value="false" /> </bean> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="mxb123" p:pool-config-ref="poolConfig"/> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="connectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer">
<!-- 采用jdk序列 --> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> <!-- 发送邮件的队列,这边只是个例子 --> <bean id="sentEmailQueue" class="com.xiaomei.queue.redis.demo01.SendEmailQueue"> <property name="redisQueue" > <bean class="com.xiaomei.queue.redis.demo01.RedisQueue" destroy-method="destroy"> <property name="redisTemplate" ref="redisTemplate"></property> <property name="queueName" value="email"></property> </bean> </property> </bean> </beans>
3、IRedisQueue.java
package com.xiaomei.queue.redis.demo01; import java.util.concurrent.TimeUnit; /** * @author xiaomei * @version V1.0 * @Title: IRedisQueue * @Package com.xiaomei.queue.redis.demo01 * @Description: * @date 11/7/17 */ public interface IRedisQueue<T> { /** * 从头开始拿 * 拿出,没有就等待 * @return * @throws InterruptedException */ public T take() throws InterruptedException; /** * 从尾开始拿 * 拿出,没有就等待 * @return * @throws InterruptedException */ public T takeOpposite() throws InterruptedException; /** * 从头开始拿 * 拿出,没有就等待 seconds 秒 * @param seconds * @return * @throws InterruptedException */ public T poll(int seconds) throws InterruptedException; /** * 从头开始拿 * 拿出,没有就等待 seconds 秒 * @param seconds * @return * @throws InterruptedException */ public T pollOpposite(int seconds) throws InterruptedException; /** * 从尾开始放 * 入队 * @param value * @return * @throws InterruptedException */ public void add(T value); /** * 从头开始放 * 入队 * @param value * @return * @throws InterruptedException */ public void addOpposite(T value); // // /** // * 从头开始删除 // * @return // */ // public T remove(); // // // /** // * 从尾开始删除 // * @return // */ // public T removeOpposite(); // /** * 删除所有 */ public void clearAll(); }
4、RedisQueue.java
package com.xiaomei.queue.redis.demo01; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.BoundListOperations; import org.springframework.data.redis.core.RedisConnectionUtils; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.util.CollectionUtils; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author xiaomei * @version V1.0 * @Title: RedisQueue * @Package com.xiaomei.queue.redis.demo01 * @Description: * @date 11/7/17 */ public class RedisQueue<T> implements InitializingBean,DisposableBean,IRedisQueue<T> { //队列名称 public String queueName; //原生key private byte[] rawKey; private RedisTemplate redisTemplate; private RedisConnectionFactory factory; private RedisConnection connection; //为了堵塞 private BoundListOperations<String, T> listOperations; private Lock lock = new ReentrantLock();//基于底层IO阻塞考虑 如果分布式的话,就是用分式式的锁 @Override public T take() throws InterruptedException { return poll(0); } @Override public T takeOpposite() throws InterruptedException { return pollOpposite(0); } @Override public T poll(int seconds) throws InterruptedException { lock.lockInterruptibly(); try{ List<byte[]> results = connection.bRPop(seconds, rawKey); if(CollectionUtils.isEmpty(results)){ return null; } return (T)redisTemplate.getValueSerializer().deserialize(results.get(1)); }finally{ lock.unlock(); } } @Override public T pollOpposite(int seconds) throws InterruptedException { lock.lockInterruptibly(); try{ List<byte[]> results = connection.bLPop(seconds, rawKey); if(CollectionUtils.isEmpty(results)){ return null; } return (T)redisTemplate.getValueSerializer().deserialize(results.get(1)); }finally{ lock.unlock(); } } @Override public void add(T value) { listOperations.rightPush(value); } @Override public void addOpposite(T value) { listOperations.leftPush(value); } @Override public void clearAll() { // listOperations. } @Override public void afterPropertiesSet() throws Exception { factory = redisTemplate.getConnectionFactory(); connection = RedisConnectionUtils.getConnection(factory); rawKey = redisTemplate.getKeySerializer().serialize(queueName); listOperations = redisTemplate.boundListOps(queueName); } @Override public void destroy() throws Exception { RedisConnectionUtils.releaseConnection(connection, factory); } public void setQueueName(String queueName) { this.queueName = queueName; } public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } }
5、SendEmailQueue
package com.xiaomei.queue.redis.demo01; import com.xiaomei.queue.redis.demo01.entity.EmailEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.redis.core.RedisTemplate; /** * @author xiaomei * @version V1.0 * @Title: SendEmailQueue * @Package com.xiaomei.queue.redis.demo01 * @Description: * @date 11/7/17 */ public class SendEmailQueue implements Runnable{ //@Autowired private IRedisQueue<EmailEntity> redisQueue; public IRedisQueue<EmailEntity> getRedisQueue() { return redisQueue; } public void setRedisQueue(IRedisQueue<EmailEntity> redisQueue) { this.redisQueue = redisQueue; } public void sentEmail(EmailEntity emailEntity) { redisQueue.add(emailEntity); } public EmailEntity getEmail() throws InterruptedException { return redisQueue.poll(1); } @Override public void run() { try { while (true){ System.out.println("take"+getEmail()); } } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-redis.xml"); SendEmailQueue sendEmailQueue = (SendEmailQueue) applicationContext.getBean("sentEmailQueue"); // Thread thread = new Thread(){ // @Override // public void run() { // for (int i = 0 ; i <100 ; i++){ // EmailEntity emailEntity = new EmailEntity(); // emailEntity.setEmailAddr(i+"-- - @qq.com"); // emailEntity.setUserName("name:"+i); // sendEmailQueue.sentEmail(emailEntity); // } // } // }; // thread.run(); sendEmailQueue.run(); } }
6、EmailEntity.java 注意必须 实现Serializeable 不然不能序列化
package com.xiaomei.queue.redis.demo01.entity; import java.io.Serializable; /** * @author 梅谢兵 * @version V1.0 * @Title: EmailEntity * @Package com.xiaomei.queue.redis.demo01.entity * @Description: * @date 11/7/17 */ public class EmailEntity implements Serializable { private String userName; private String emailAddr; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getEmailAddr() { return emailAddr; } public void setEmailAddr(String emailAddr) { this.emailAddr = emailAddr; } @Override public String toString() { return "EmailEntity{" + "userName='" + userName + '\'' + ", emailAddr='" + emailAddr + '\'' + '}'; } }
采用的是生产者和消费者的模式。
最后加上一直图

浙公网安备 33010602011771号