解决spring集成redisson踩过的坑
作者:丶诸子百家
spring集成redisson踩过的坑
我用spring的xml集成一直报错,所以只能选择注解方式:
@Configuration public class RedissionConfig { Logger log = LoggerFactory.getLogger(RedissionConfig.class); @Value("${redis_ip}") String redis_ip; @Value("${redis_port}") String redis_port; @Value("${redis_password}") String redis_password; @Bean(name="redissonClient") public RedissonClient init(){ log.info("redis_ip:"+redis_ip); log.info("redis_port:" +redis_port); log.info("redis_password:"+redis_password); Config config = new Config(); String url = "redis://"+redis_ip+":"+redis_port; log.info(url); config.useSingleServer().setAddress(url).setPassword(redis_password); RedissonClient redissonClient = Redisson.create(config); log.info("初始化RedissonClient"); return redissonClient; } }
第一坑就是版本兼容问题
我用的Spring是4.2.7,第一次集成的是3.12.0,会报以下错误:
严重: Unable to process Jar entry [module-info.class] from Jar [jar:file:/C:/Users/Administrator/.m2/repository/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.10.1/jackson-dataformat-yaml-2.10.1.jar!/] for annotations org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19 at org.apache.tomcat.util.bcel.classfile.Constant.readConstant(Constant.java:133) at org.apache.tomcat.util.bcel.classfile.ConstantPool.<init>(ConstantPool.java:60) at org.apache.tomcat.util.bcel.classfile.ClassParser.readConstantPool(ClassParser.java:209) at org.apache.tomcat.util.bcel.classfile.ClassParser.parse(ClassParser.java:119) at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:2134) at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:2010) at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1976) at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1961) at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1319) at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:878) at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:376) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5322) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748)
所以把版本降低到3.10.0,就不会报错了。
第二个坑是设置密码问题
因为要区分多环境,所以把redis的信息写到配置文件中,如果按照上面的配置,会报以下错误:
Caused by: org.redisson.client.RedisException: ERR Client sent AUTH, but no password is set. channel: [id: 0xe37c85e0, L:/192.168.0.128:54867 - R:192.168.0.128/192.168.0.128:5802] command: (AUTH), params: [] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:314) at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:130) at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:110) at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502) at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:656) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:591) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:508) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:470) ... 3 more
所以要判断密码是否为空,如果是空不做参数即可,下面是改正过的代码:
public RedissonClient init(){ log.info("redis_ip:"+redis_ip); log.info("redis_port:" +redis_port); log.info("redis_password:"+redis_password); Config config = new Config(); String url = "redis://"+redis_ip+":"+redis_port; log.info(url); SingleServerConfig singleServerConfig = config.useSingleServer().setAddress(url); if(!StringUtils.isEmpty(redis_password)){ singleServerConfig.setPassword(redis_password); } RedissonClient redissonClient = Redisson.create(config); log.info("初始化RedissonClient"); return redissonClient; }
另外,网上的帖子好多直接放的ip+端口号,但是我本地会报错,一定在加redis://192.168.2.128:6379这种格式的,可能是因为版本问题,也有可能就是误导人的。
看到上面的报错,感觉知道xml的错误了:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd"> <beans profile="development"> <!--redisson --> <!--<redisson:client id="redissonClient"> <redisson:single-server address="redis://182.92.97.141:5802"/> </redisson:client>--> </beans>
没有设置密码,一定不要把password属性放上去,要不会报错的~
spring整合redisson配置
配置方式
redis的部署方式有单节点部署、哨兵方式部署、集群方式部署3种方式
各种配置方式可以去看xsd文件:redisson-1.1.xsd
<xsd:element name="single-server"> // 单节点 <xsd:element name="sentinel-servers"> // 哨兵 <xsd:element name="cluster-servers"> // 集群 <xsd:element name="master-slave-servers"> // 主从
等其他方式
单节点配置standalone
单纯的java代码,基于单节点部署为了保证数据的备份,一般会添加一个节点作为slave来备份master节点上的数据
//创建配置 Config config = new Config(); //指定使用单节点部署方式 config.useSingleServer().setAddress("redis://127.0.0.1:6379"); //创建客户端(发现这一非常耗时,基本在2秒-4秒左右) RedissonClient redisson = Redisson.create(config); //首先获取redis中的key-value对象,key不存在没关系 RBucket<String> keyObject = redisson.getBucket("key"); //如果key存在,就设置key的值为新值value //如果key不存在,就设置key的值为value keyObject.set("value"); //最后关闭RedissonClient redisson.shutdown();
spring整合pom
<!--redisson--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>2.10.4</version> </dependency> <!--redis--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>1.7.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.1.RELEASE</version> </dependency>
spring整合redisson.xml
<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:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd"> <redisson:client id="standalone" name="aliasName1,aliasName2"> <redisson:single-server address="redis://127.0.0.1:6379" /> </redisson:client> </beans>
哨兵配置sentinel
纯java代码
//创建配置 Config config = new Config(); //指定使用哨兵部署方式 config.useSentinelServers() //设置sentinel.conf配置里的sentinel别名 //比如sentinel.conf里配置为sentinel monitor my-sentinel-name 127.0.0.1 6379 2,那么这里就配置my-sentinel-name .setMasterName("my-sentinel-name") //这里设置sentinel节点的服务IP和端口,sentinel是采用Paxos拜占庭协议,一般sentinel至少3个节点 //记住这里不是配置redis节点的服务端口和IP,sentinel会自己把请求转发给后面monitor的redis节点 .addSentinelAddress("redis://127.0.0.1:26379") .addSentinelAddress("redis://127.0.0.1:26389") .addSentinelAddress("redis://127.0.0.1:26399"); //创建客户端(发现这一非常耗时,基本在2秒-4秒左右) RedissonClient redisson = Redisson.create(config); //首先获取redis中的key-value对象,key不存在没关系 RBucket<String> keyObject = redisson.getBucket("key"); //如果key存在,就设置key的值为新值value //如果key不存在,就设置key的值为value keyObject.set("value"); //最后关闭RedissonClient redisson.shutdown();
spring整合redis和redisson的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd"> <!-- 构造JedisConnectionFactory实例,注入池配置poolConfig和哨兵配置sentinelConfig--> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!--<constructor-arg index="0" ref="redisSentinelConfiguration"/>--> <!--<constructor-arg index="1" ref="jedisPoolConfig"/>--> <constructor-arg ref="redisSentinelConfiguration"/> <property name="poolConfig" ref="jedisPoolConfig"/> <property name="database" value="${redis.database}"/> </bean> <!-- 配置JedisPoolConfig--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="minIdle" value="${redis.minIdle}"/> <property name="maxIdle" value="${redis.maxIdle}"/> <property name="maxTotal" value="${redis.maxTotal}"/> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> <property name="testWhileIdle" value="${redis.testWhileIdle}"/> <property name="testOnReturn" value="${redis.testOnReturn}"/> <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/> <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/> </bean> <!-- 配置RedisSentinelConfiguration--> <bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration"> <property name="master"> <bean class="org.springframework.data.redis.connection.RedisNode"> <property name="name" value="${redis.masterName}"/> </bean> </property> <property name="sentinels"> <set> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg index="0" value="${redis.host}"/> <constructor-arg index="1" value="${redis.port}"/> </bean> </set> </property> </bean> <!-- 用于缓存对象--> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> <!-- key --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <!-- value --> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> </bean> <!-- 用于缓存字符串--> <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> </bean> <redisson:client id="redissonClient"> <!--master-name为redis的主节点名称--> <redisson:sentinel-servers master-name="mymaster"> <!-- 可以配置多个 --> <redisson:sentinel-address value="redis://172.17.46.11:26379" /> </redisson:sentinel-servers> </redisson:client> </beans>
使用
@Autowired @Lazy private RedissonClient redissonClient; /** * @param key 具体键值 * @return 锁对象 */ public RReadWriteLock getLock(String key) { return redissonClient.getReadWriteLock(key); }
集群配置cluster
纯java代码
//创建配置 Config config = new Config(); //指定使用集群部署方式 config.useClusterServers() // 集群状态扫描间隔时间,单位是毫秒 .setScanInterval(2000) //cluster方式至少6个节点(3主3从,3主做sharding,3从用来保证主宕机后可以高可用) .addNodeAddress("redis://127.0.0.1:6379" ) .addNodeAddress("redis://127.0.0.1:6380") .addNodeAddress("redis://127.0.0.1:6381") .addNodeAddress("redis://127.0.0.1:6382") .addNodeAddress("redis://127.0.0.1:6383") .addNodeAddress("redis://127.0.0.1:6384"); //创建客户端(发现这一非常耗时,基本在2秒-4秒左右) RedissonClient redisson = Redisson.create(config); //首先获取redis中的key-value对象,key不存在没关系 RBucket<String> keyObject = redisson.getBucket("key"); //如果key存在,就设置key的值为新值value //如果key不存在,就设置key的值为value keyObject.set("value"); //最后关闭RedissonClient redisson.shutdown();
spring整合redisson配置方式
<?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:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd"> <!-- Redis 连接池配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="minIdle" value="${redis.minIdle}"/> <property name="maxIdle" value="${redis.maxIdle}"/> <property name="maxTotal" value="${redis.maxTotal}"/> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> <property name="testWhileIdle" value="${redis.testWhileIdle}"/> <property name="testOnReturn" value="${redis.testOnReturn}"/> <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/> <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/> <property name="timeBetweenEvictionRunsMillis" value="30000"/> </bean> <!-- jedisCluster 配置 --> <!-- 自定义的工厂类,实现了FactoryBean<JedisCluster>接口 --> <bean id="jedisCluster" class="com.xxxxx.JedisClusterFactory"> <!-- address: 集群配置 --> <property name="address" value="${redisColony.host}"/> <!-- timeout: 连接超时时间 --> <property name="timeout" value="100000"/> <!-- maxRedirections: 最大重定向 --> <property name="maxRedirections" value="5"/> <!-- 连接池 --> <property name="genericObjectPoolConfig" ref="poolConfig"/> </bean> <!--redisson的实例 --> <redisson:client id="redissonClient"> <redisson:cluster-servers> <!-- 节点地址同redis集群的节点 --> <redisson:node-address value="${redisColony.host1}"/> <redisson:node-address value="${redisColony.host2}"/> <redisson:node-address value="${redisColony.host3}"/> <redisson:node-address value="${redisColony.host4}"/> <redisson:node-address value="${redisColony.host5}"/> <redisson:node-address value="${redisColony.host6}"/> </redisson:cluster-servers> </redisson:client> </beans>
properties文件
redisColony.host = 172.17.46.11:36379,172.17.46.11:36381,172.17.45.12:36379,172.17.45.12:36381,172.17.45.13:36379,172.17.45.13:36381 redis.timeOut = 100000 redis.redirection = 5 redisColony.host1 = redis://172.17.46.11:36379 redisColony.host2 = redis://172.17.46.11:36381 redisColony.host3 = redis://172.17.45.12:36379 redisColony.host4 = redis://172.17.45.12:36381 redisColony.host5 = redis://172.17.45.13:36379 redisColony.host6 = redis://172.17.45.13:36381
使用方式与哨兵配置方式相同,@Autowired注入即可
主从部署方式(master/slave)
纯java代码
//创建配置 Config config = new Config(); //指定使用主从部署方式 config.useMasterSlaveServers() //设置redis主节点 .setMasterAddress("redis://127.0.0.1:6379") //设置redis从节点 .addSlaveAddress("redis://127.0.0.1:6380", "redis://127.0.0.1:6381"); //创建客户端(发现这一非常耗时,基本在2秒-4秒左右) RedissonClient redisson = Redisson.create(config); //首先获取redis中的key-value对象,key不存在没关系 RBucket<String> keyObject = redisson.getBucket("key"); //如果key存在,就设置key的值为新值value //如果key不存在,就设置key的值为value keyObject.set("value"); //最后关闭RedissonClient redisson.shutdown();
spring整合redisson.xml
<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:redisson="http://redisson.org/schema/redisson" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://redisson.org/schema/redisson http://redisson.org/schema/redisson/redisson.xsd"> <redisson:client id="masterSlave"> <redisson:master-slave-servers master-address="redis://127.0.0.1:6379"> <redisson:slave-address value="redis://127.0.0.1:6380" /> <redisson:slave-address value="redis://127.0.0.1:6381" /> </redisson:master-slave-servers> </redisson:client> </beans>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。