为何研究:公司项目先配置了redis集群,但是在某些地方需要使用分布式锁。后面才加的redisson。因为需求只需要改redisson的某些配置,所以网上常用的在yaml中配置的方法就不怎么好用了。如果想配置某些字段,还需要把集群地址再配置一遍,非常不人性化。在网上搜索良久,未发现符合我需求的。正想放弃之际,突然灵光一闪。我们什么都不配置的时候redisson是如何默认的呢。于是一路溯源,找到了RedissonAutoConfiguration(见名知意,自动配置)。
@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;
}
//1、判断spring.redis.redisson是否有config配置
if (this.redissonProperties.getConfig() != null) {
try {
config = Config.fromYAML(this.redissonProperties.getConfig());
} catch (IOException var13) {
try {
config = Config.fromJSON(this.redissonProperties.getConfig());
} catch (IOException var12) {
throw new IllegalArgumentException("Can't parse config", var12);
}
}
//2、判断spring.redis.redisson是否有file配置
} else if (this.redissonProperties.getFile() != null) {
try {
InputStream is = this.getConfigStream();
config = Config.fromYAML(is);
} catch (IOException var11) {
try {
InputStream is = this.getConfigStream();
config = Config.fromJSON(is);
} catch (IOException var10) {
throw new IllegalArgumentException("Can't parse config", var10);
}
}
//3、判断spring.redis.redisson是否有sentinel配置
} 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 {
//4、什么都没配置的话就走redisson默认配置
Method method;
if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties) != null) {
//reids集群走这里
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 {
//单机版reids走这里
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());
}
}
看完代码以后,发现是真简单,直接把第四步的拿出来自己改改就好了。下面就是半天的劳动成果(不想把参数放在yaml中配置了,有需要可自己改)。
import com.alibaba.excel.util.ListUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.List;
@Configuration
public class RedissonConfig {
private RedisProperties redisProperties;
public RedissonConfig(RedisProperties redisProperties) {
this.redisProperties=redisProperties;
}
/**
* redisson java配置,取yaml中redis的链接配置
* 不支持在yaml中配置,如想在yaml中单独配置redisson,请删掉此类。
* RedissonAutoConfiguration
* @return {@link RedissonClient}
*/
@Bean(destroyMethod = "shutdown")
RedissonClient redisson() {
Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
if(clusterMethod==null){
return null;
}
Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties);
if(clusterObject==null){
//单机模式配置
Config config = new Config();
config.setNettyThreads(2);
config.setThreads(2);
String prefix = "redis://";
Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, this.redisProperties)) {
prefix = "rediss://";
}
(config.useSingleServer().setAddress(prefix + this.redisProperties.getHost() + ":" + this.redisProperties.getPort()).setConnectTimeout(1000)).setDatabase(this.redisProperties.getDatabase()).setPassword(this.redisProperties.getPassword());
return Redisson.create(config);
}
Method method = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
if(method==null){
return null;
}
List<String> nodesObject = (List)ReflectionUtils.invokeMethod(method, clusterObject);
if(nodesObject==null){
return null;
}
String[] nodes = this.convert(nodesObject);
Config config = new Config();
//集群模式参数配置
ClusterServersConfig clusterServersConfig = config.useClusterServers().addNodeAddress(nodes).setConnectTimeout(1000);
clusterServersConfig.setPassword(this.redisProperties.getPassword());
clusterServersConfig.setSlaveConnectionMinimumIdleSize(2);
clusterServersConfig.setMasterConnectionMinimumIdleSize(2);
clusterServersConfig.setMasterConnectionPoolSize(2);
config.setNettyThreads(2);
config.setThreads(2);
return Redisson.create(config);
}
private String[] convert(List<String> nodesObject) {
List<String> nodes = ListUtils.newArrayListWithExpectedSize(nodesObject.size());
for (String node:nodesObject) {
if (!node.startsWith("redis://") && !node.startsWith("rediss://")) {
nodes.add("redis://" + node);
} else {
nodes.add(node);
}
}
return nodes.toArray(new String[nodes.size()]);
}
}