All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.open.capacity.redis.RedisAutoConfig Maven / Gradle / Ivy

There is a newer version: 1.0.0.RC4
Show newest version
package com.open.capacity.redis;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
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.condition.ConditionalOnProperty;
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.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.ReflectionUtils;

import com.open.capacity.redis.serializer.RedisObjectSerializer;
import com.open.capacity.redis.util.RedisUtil;

import io.lettuce.core.RedisClient;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;

/*
 * @author 作者 owen
 * @version 创建时间:2017年04月23日 下午20:01:06 类说明 redis自动装配
 */
@Configuration
@EnableCaching
@SuppressWarnings("all")
@AutoConfigureBefore(RedisTemplate.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedisAutoConfig {

	@Autowired(required = false)
	private RedissonProperties redissonProperties;

	@Autowired
	private RedisProperties redisProperties;

	@Autowired
	private ApplicationContext ctx;

	@Bean(destroyMethod = "destroy")
	@ConditionalOnClass(RedisClient.class)
	public LettuceConnectionFactory lettuceConnectionFactory(GenericObjectPoolConfig genericObjectPoolConfig) {
		Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
		Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
		Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
		RedisConfiguration redisConfiguration = null;
		LettuceClientConfiguration clientConfig = null;
		if (redisProperties.getSentinel() != null) {
			// 哨兵配置
			Method nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
			Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());

			String[] nodes = null;
			Set sentinelHostAndPorts = new HashSet<>();
			if (nodesValue instanceof String) {
				nodes = convert(Arrays.asList(((String) nodesValue).split(",")));
				sentinelHostAndPorts.addAll(Arrays.asList(((String) nodesValue).split(",")));
			} else {
				nodes = convert((List) nodesValue);
				sentinelHostAndPorts.addAll((List) nodesValue);
			}
			redisConfiguration = new RedisSentinelConfiguration(redisProperties.getSentinel().getMaster(),
					sentinelHostAndPorts);
			((RedisSentinelConfiguration) redisConfiguration)
					.setPassword(RedisPassword.of(redisProperties.getPassword()));
			((RedisSentinelConfiguration) redisConfiguration).setDatabase(redisProperties.getDatabase());
			clientConfig = LettucePoolingClientConfiguration.builder().commandTimeout(redisProperties.getTimeout())
					.poolConfig(genericObjectPoolConfig).build();

		} else if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
			// 集群配置
			List clusterNodes = redisProperties.getCluster().getNodes();
			Set nodes = new HashSet();
			clusterNodes.forEach(address -> nodes
					.add(new RedisNode(address.split(":")[0].trim(), Integer.valueOf(address.split(":")[1]))));
			redisConfiguration = new RedisClusterConfiguration();
			((RedisClusterConfiguration) redisConfiguration).setClusterNodes(nodes);
			((RedisClusterConfiguration) redisConfiguration)
					.setPassword(RedisPassword.of(redisProperties.getPassword()));

			/**
			 * ClusterTopologyRefreshOptions配置用于开启自适应刷新和定时刷新。如自适应刷新不开启,
			 * Redis集群变更时将会导致连接异常!
			 */
			ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
					// 开启自适应刷新
					.enableAdaptiveRefreshTrigger(ClusterTopologyRefreshOptions.RefreshTrigger.MOVED_REDIRECT,
							ClusterTopologyRefreshOptions.RefreshTrigger.PERSISTENT_RECONNECTS)
					// 开启所有自适应刷新,MOVED,ASK,PERSISTENT都会触发
					// .enableAllAdaptiveRefreshTriggers()
					// 自适应刷新超时时间(默认30秒)
					.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(25)) // 默认关闭开启后时间为30秒
					// 开周期刷新
					.enablePeriodicRefresh(Duration.ofSeconds(20)) // 默认关闭开启后时间为60秒
					// ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD
					// 60 .enablePeriodicRefresh(Duration.ofSeconds(2)) =
					// .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))
					.build();
			clientConfig = LettucePoolingClientConfiguration.builder().commandTimeout(redisProperties.getTimeout())
					.poolConfig(genericObjectPoolConfig)
					.clientOptions(
							ClusterClientOptions.builder().topologyRefreshOptions(topologyRefreshOptions).build())
					// 将appID传入连接,方便Redis监控中查看
					// .clientName(appName + "_lettuce")
					.build();

		} else {
			// 单机版配置
			redisConfiguration = new RedisStandaloneConfiguration();
			((RedisStandaloneConfiguration) redisConfiguration).setDatabase(redisProperties.getDatabase());
			((RedisStandaloneConfiguration) redisConfiguration).setHostName(redisProperties.getHost());
			((RedisStandaloneConfiguration) redisConfiguration).setPort(redisProperties.getPort());
			((RedisStandaloneConfiguration) redisConfiguration)
					.setPassword(RedisPassword.of(redisProperties.getPassword()));

			clientConfig = LettucePoolingClientConfiguration.builder().commandTimeout(redisProperties.getTimeout())
					.poolConfig(genericObjectPoolConfig).build();

		}

		if (redisProperties.isSsl()) {
			clientConfig.isUseSsl();
		}

		LettuceConnectionFactory factory = new LettuceConnectionFactory(redisConfiguration, clientConfig);
		return factory;
	}

	/*
	 * GenericObjectPoolConfig 连接池配置
	 */
	@Bean
	public GenericObjectPoolConfig genericObjectPoolConfig() {
		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
		poolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
		poolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
		poolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
		poolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().getSeconds());
		Duration timeOut = redisProperties.getTimeout();
		Duration shutdownTimeout = redisProperties.getLettuce().getShutdownTimeout();
		return poolConfig;
	}

 
	@Bean 
	public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory ) {
	 
		RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
		redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(30L)) // 设置缓存的默认超时时间:30分钟
				.disableCachingNullValues() // 如果是空值,不缓存
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())) // 设置key序列化器
				.serializeValuesWith(
						RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.java())); // 设置value序列化器
		return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(lettuceConnectionFactory))
				.cacheDefaults(redisCacheConfiguration).build();
	}

	/*
	 * 适配redis cluster单节点
	 */
	@Primary
	@Bean("redisTemplate")
	// 没有此属性就不会装配bean 如果是单个redis 将此注解注释掉
	@ConditionalOnProperty(name = "spring.redis.cluster.nodes", matchIfMissing = false)
	public RedisTemplate getRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
		RedisTemplate redisTemplate = new RedisTemplate();
		redisTemplate.setConnectionFactory(lettuceConnectionFactory);
		RedisSerializer stringSerializer = new StringRedisSerializer();
		// RedisSerializer redisObjectSerializer = new RedisObjectSerializer();
		RedisSerializer redisObjectSerializer = new RedisObjectSerializer();
		redisTemplate.setKeySerializer(stringSerializer); // key的序列化类型
		redisTemplate.setHashKeySerializer(stringSerializer);
		redisTemplate.setValueSerializer(redisObjectSerializer); // value的序列化类型
		redisTemplate.setHashValueSerializer(redisObjectSerializer); // value的序列化类型
		redisTemplate.afterPropertiesSet();

		redisTemplate.opsForValue().set("hello", "wolrd");
		return redisTemplate;
	}

	/*
	 * 适配redis单节点
	 */
	@Primary
	@Bean("redisTemplate")
	@ConditionalOnProperty(name = "spring.redis.host", matchIfMissing = true)
	public RedisTemplate getSingleRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
		RedisTemplate redisTemplate = new RedisTemplate();
		RedisSerializer redisObjectSerializer = new RedisObjectSerializer();
		redisTemplate.setConnectionFactory(lettuceConnectionFactory);
		redisTemplate.setKeySerializer(new StringRedisSerializer()); // key的序列化类型
		redisTemplate.setValueSerializer(redisObjectSerializer); // value的序列化类型
		redisTemplate.setHashValueSerializer(redisObjectSerializer);
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}

	@Bean
	public HashOperations hashOperations(StringRedisTemplate stringRedisTemplate) {
		return stringRedisTemplate.opsForHash();
	}

	/*
	 * redis工具类
	 */
	@Bean("redisUtil")
	public RedisUtil redisUtil(LettuceConnectionFactory lettuceConnectionFactory,
			StringRedisTemplate stringRedisTemplate, HashOperations hashOperations) {
		RedisUtil redisUtil = new RedisUtil(lettuceConnectionFactory, stringRedisTemplate, hashOperations);
		return redisUtil;
	}

	@Bean(destroyMethod = "shutdown")
	@ConditionalOnProperty(name = "spring.redis.redisson.enable", matchIfMissing = false, havingValue = "true")
	@ConditionalOnMissingBean(RedissonClient.class)
	public RedissonClient redissonClient() throws IOException {
		Config config = null;
		Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
		Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
		Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
		int timeout;
		if (null == timeoutValue) {
			timeout = 60000;
		} else if (!(timeoutValue instanceof Integer)) {
			Method millisMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
			timeout = ((Long) ReflectionUtils.invokeMethod(millisMethod, timeoutValue)).intValue();
		} else {
			timeout = (Integer) timeoutValue;
		}
		// spring.redis.redisson.config=classpath:redisson.yaml
		if (redissonProperties.getConfig() != null) {

			try {
				InputStream is = getConfigStream();
				config = Config.fromJSON(is);
			} catch (IOException e) {
				// trying next format
				try {
					InputStream is = getConfigStream();
					config = Config.fromYAML(is);
				} catch (IOException ioe) {
					throw new IllegalArgumentException("Can't parse config", ioe);
				}
			}
		} else if (redisProperties.getSentinel() != null) {
			// 哨兵配置
			Method nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
			Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());

			String[] nodes;
			if (nodesValue instanceof String) {
				nodes = convert(Arrays.asList(((String) nodesValue).split(",")));
			} else {
				nodes = convert((List) nodesValue);
			}

			config = new Config();
			config.useSentinelServers().setMasterName(redisProperties.getSentinel().getMaster())
					.addSentinelAddress(nodes).setDatabase(redisProperties.getDatabase()).setConnectTimeout(timeout)
					.setPassword(redisProperties.getPassword());
		} else if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
			// 集群配置
			Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties);
			Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
			List nodesObject = (List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject);
			String[] nodes = convert(nodesObject);
			config = new Config();
			config.useClusterServers().addNodeAddress(nodes).setConnectTimeout(timeout)
					.setPassword(redisProperties.getPassword());
		} else {
			// 单机redssion默认配置
			config = new Config();
			String prefix = "redis://";
			Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
			if (method != null && (Boolean) ReflectionUtils.invokeMethod(method, redisProperties)) {
				prefix = "rediss://";
			}

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

		}

		return Redisson.create(config);
	}

	private String[] convert(List nodesObject) {
		List nodes = new ArrayList(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()]);
	}

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

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy