spring boot整合redisson

1.springboot 整合redisson,也依賴於spring-boot-starter-data-redis。

1.引入依賴

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/>
    </parent>
     <dependencies>
	<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.11.6</version>
        </dependency>
         </dependencies>

3.11.6要依賴於2.2.0,否則會出現一些classnotFount。

2.yml配置

redisson依賴於spring-redis前綴的配置,可以在動態配置的代碼中發現

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.redisson.spring.starter;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.redisson.spring.data.connection.RedissonConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.ReflectionUtils;

@Configuration
@ConditionalOnClass({Redisson.class, RedisOperations.class})
@AutoConfigureBefore({RedisAutoConfiguration.class})
@EnableConfigurationProperties({RedissonProperties.class, RedisProperties.class})
public class RedissonAutoConfiguration {
    @Autowired
    private RedissonProperties redissonProperties;
    @Autowired
    private RedisProperties redisProperties;
    @Autowired
    private ApplicationContext ctx;

    public RedissonAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean({StringRedisTemplate.class})
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean({RedisConnectionFactory.class})
    public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
        return new RedissonConnectionFactory(redisson);
    }

    @Bean(
        destroyMethod = "shutdown"
    )
    @ConditionalOnMissingBean({RedissonClient.class})
    public RedissonClient redisson() throws IOException {
        Config config = null;
        Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
        Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
        Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, this.redisProperties);
        int timeout;
        Method nodesMethod;
        if (null == timeoutValue) {
            timeout = 10000;
        } else if (!(timeoutValue instanceof Integer)) {
            nodesMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
            timeout = ((Long)ReflectionUtils.invokeMethod(nodesMethod, timeoutValue)).intValue();
        } else {
            timeout = (Integer)timeoutValue;
        }

        if (this.redissonProperties.getConfig() != null) {
            try {
                InputStream is = this.getConfigStream();
                config = Config.fromJSON(is);
            } catch (IOException var11) {
                try {
                    InputStream is = this.getConfigStream();
                    config = Config.fromYAML(is);
                } catch (IOException var10) {
                    throw new IllegalArgumentException("Can't parse config", var10);
                }
            }
        } else if (this.redisProperties.getSentinel() != null) {
            nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
            Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, this.redisProperties.getSentinel());
            String[] nodes;
            if (nodesValue instanceof String) {
                nodes = this.convert(Arrays.asList(((String)nodesValue).split(",")));
            } else {
                nodes = this.convert((List)nodesValue);
            }

            config = new Config();
            ((SentinelServersConfig)config.useSentinelServers().setMasterName(this.redisProperties.getSentinel().getMaster()).addSentinelAddress(nodes).setDatabase(this.redisProperties.getDatabase()).setConnectTimeout(timeout)).setPassword(this.redisProperties.getPassword());
        } else {
            Method method;
            if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties) != null) {
                Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties);
                method = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
                List<String> nodesObject = (List)ReflectionUtils.invokeMethod(method, clusterObject);
                String[] nodes = this.convert(nodesObject);
                config = new Config();
                ((ClusterServersConfig)config.useClusterServers().addNodeAddress(nodes).setConnectTimeout(timeout)).setPassword(this.redisProperties.getPassword());
            } else {
                config = new Config();
                String prefix = "redis://";
                method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
                if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, this.redisProperties)) {
                    prefix = "rediss://";
                }

                ((SingleServerConfig)config.useSingleServer().setAddress(prefix + this.redisProperties.getHost() + ":" + this.redisProperties.getPort()).setConnectTimeout(timeout)).setDatabase(this.redisProperties.getDatabase()).setPassword(this.redisProperties.getPassword());
            }
        }

        return Redisson.create(config);
    }

    private String[] convert(List<String> nodesObject) {
        List<String> nodes = new ArrayList(nodesObject.size());
        Iterator var3 = nodesObject.iterator();

        while(true) {
            while(var3.hasNext()) {
                String node = (String)var3.next();
                if (!node.startsWith("redis://") && !node.startsWith("rediss://")) {
                    nodes.add("redis://" + node);
                } else {
                    nodes.add(node);
                }
            }

            return (String[])nodes.toArray(new String[nodes.size()]);
        }
    }

    private InputStream getConfigStream() throws IOException {
        Resource resource = this.ctx.getResource(this.redissonProperties.getConfig());
        InputStream is = resource.getInputStream();
        return is;
    }
}

會優先讀取RedisProperties的屬性,如果讀取不到,纔會讀取RedissonProperties的屬性,redission的配置屬性是一個路徑,屬性需要單獨寫入別的配置文件,如下

singleServerConfig:
  address: "redis://127.0.0.1:6379"

本例中我們yml配置如下

spring:
    redis:
        host: localhost
        port: 6379

採取單節點模式

package com.ly;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootRedissonTest {
  @Autowired
  private Redisson redisson;
  @Autowired
  private RedisTemplate<String,String> redisTemplate;

  @Test
  public void test(){
  	redisson.getKeys().flushall();
  	RMap<String,String> rMap = redisson.getMap("map", StringCodec.INSTANCE);
  	rMap.put("one","1");

  	BoundHashOperations<String,String,String> hash = redisTemplate
  	.boundHashOps("map");
  	String mapOneVal = hash.get("one");
  	System.out.println(mapOneVal);
  }



  @Test
  public void distributeLockTest() throws IOException {

  	String distributeTestKey = "dis_test_key";

  	Thread t = new Thread(new ConsumerLockTest(redisson,distributeTestKey));
  	t.setName("thread 1");
  	t.start();
  	while (true){

  	}
  }

  @Test
  public void distributeLockTest2() throws IOException {

  	String distributeTestKey = "dis_test_key";

  	Thread t = new Thread(new ConsumerLockTest(redisson,distributeTestKey));
  	t.setName("thread 2");
  	t.start();
  	while (true){

  	}

  }

  @Test
  public void distributeLockTest3() throws IOException {

  	String distributeTestKey = "dis_test_key";

  	Thread t = new Thread(new ConsumerLockTest(redisson,distributeTestKey));
  	t.setName("thread 3");
  	t.start();
  	while (true){

  	}

  }

  public class ConsumerLockTest implements Runnable{
  	private Redisson redisson;
  	private String distributeTestKey;

  	public ConsumerLockTest(Redisson redisson, String distributeTestKey) {
  		this.redisson = redisson;
  		this.distributeTestKey = distributeTestKey;
  	}
  	@Override
  	public void run() {

  		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  		RLock lock = redisson.getLock(distributeTestKey);
  		lock.lock();
  		try {

  			System.out.println(format.format(new Date())+","+Thread.currentThread().getName()+":獲取了鎖");
  			Thread.sleep(25000);
  		} catch (InterruptedException e) {
  			e.printStackTrace();
  		}finally {
  			lock.unlock();
  			System.out.println(format.format(new Date())+","+Thread.currentThread().getName()+":釋放了鎖");
  		}
  	}
  }

}	

redisson實現了高性能的分佈式鎖,內部採用了看門狗,會自動爲鎖續航,如果檢測到連接斷開,鎖會解開。
還是支持了很多數據結構和原子類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章