<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>2.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
package help.lixin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class App {
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
package help.lixin.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisConnectionFactoryConfig {
@Autowired
private RedisProperties redisProperties;
// 针对Redis自定义CacheManager的Value序列化机制
@Bean
public CacheManagerCustomizer<CacheManager> cacheManagerCustomizer() {
CacheManagerCustomizer<CacheManager> customer = (cacheManager)-> {
if( cacheManager instanceof RedisCacheManager) {
RedisCacheManager redisCacheManager = (RedisCacheManager)cacheManager;
try {
// *********************************************************
// 由于:RedisCacheManager没有相关的方法可以改变value序列化行为,所以,只能通过反射或者自定义RedisCacheManager创建过程
// 我选择了反射的方式
// *********************************************************
Field defaultCacheConfigField = RedisCacheManager.class.getDeclaredField("defaultCacheConfig");
// 允许私有属性可以被访问
defaultCacheConfigField.setAccessible(true);
RedisCacheConfiguration oldDefaultCacheConfig = (RedisCacheConfiguration)defaultCacheConfigField.get(redisCacheManager);
// 设置为json序列化
RedisCacheConfiguration newDefaultCacheConfig = oldDefaultCacheConfig.serializeValuesWith(SerializationPair.fromSerializer(RedisSerializer.json()));
// 设置RedisCacheManager属性
defaultCacheConfigField.set(redisCacheManager, newDefaultCacheConfig);
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
};
return customer;
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
List<String> clusterNodes = redisProperties.getCluster().getNodes();
String passwordAsString = redisProperties.getPassword();
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
redisClusterConfiguration.setPassword(RedisPassword.of(passwordAsString));
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲连接数, 默认8个
jedisPoolConfig.setMaxIdle(100);
// 最大连接数, 默认8个
jedisPoolConfig.setMaxTotal(500);
// 最小空闲连接数, 默认0
jedisPoolConfig.setMinIdle(0);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,
// 默认-1
jedisPoolConfig.setMaxWaitMillis(2000); // 设置2秒
// 对拿到的connection进行validateObject校验
jedisPoolConfig.setTestOnBorrow(true);
return new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
}
}
package help.lixin.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import help.lixin.entity.User;
import help.lixin.service.IHelloService;
@Service
public class HelloService implements IHelloService {
private Logger logger = LoggerFactory.getLogger(HelloService.class);
private final Map<Long, List<User>> datas = new ConcurrentHashMap<Long, List<User>>();
public HelloService() {
init();
}
private void init() {
Long tenantId = 1L;
List<User> users = new ArrayList<User>();
users.add(new User(1L, "张三"));
users.add(new User(2L, "李四"));
users.add(new User(3L, "王五"));
users.add(new User(4L, "赵六"));
datas.put(tenantId, users);
}
// 查询全部都入缓存,key=tenantId
@Cacheable(cacheNames = "users")
public List<User> findByTenantId(Long tenantId) {
return datas.get(tenantId);
}
// 有添加操作时,仅清除:tenantId % 2 == 0的缓存信息
@CacheEvict(cacheNames = "users", key="#tenantId" , condition = "#tenantId % 2 == 0", beforeInvocation = true)
public Boolean add(Long tenantId, User user) {
List<User> users = new ArrayList<User>();
users.add(user);
if (!datas.containsKey(tenantId)) {
datas.put(tenantId, users);
} else {
datas.get(tenantId).addAll(users);
}
return true;
}
}
package help.lixin.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import help.lixin.entity.User;
import help.lixin.service.IHelloService;
@RestController
public class HelloController {
private Logger logger = LoggerFactory.getLogger(HelloController.class);
@Autowired
private IHelloService helloService;
@GetMapping("/{tenantId}")
public List<User> list(@PathVariable("tenantId") Long tenantId) {
List<User> users = helloService.findByTenantId(tenantId);
return users;
}
@PostMapping("/{tenantId}")
public String addUser(@PathVariable("tenantId") Long tenantId, @RequestBody User user) {
helloService.add(tenantId, user);
return "SUCCESS";
}
}
server.port=8080
spring.application.name=test-provider
spring.redis.password=888888
spring.redis.cluster.nodes=127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384,127.0.0.1:6385
spring.redis.cluster.max-redirects=5
# 配置过期时间
# P : 是持续时间指示符,始终放在开头,是必要字符,不能省略
# T : 表示后面跟的是时间.如果存在时间则必须要有 T.
# 例:
# PT48H : 48小时
# PT30s : 30秒
# PT10M : 10分钟
# spring.cache.redis.time-to-live=PT30s
# 是否缓存空的value
# spring.cache.redis.cache-null-values=true
# key的前缀
# spring.cache.redis.key-prefix
# 是否使用前缀
# spring.cache.redis.use-key-prefix=true
# 1. 发送curl请求
curl http://localhost:8080/1
# 2. 查看redis内容
lixin-macbook:redis-cluster lixin$ ./bin/redis-cli -c -a 888888 -p 6382
# 返回结果不再是JDK的二进制了,而是JSON文本内容.
127.0.0.1:6382> get "users::1"
"[\"java.util.ArrayList\",[{\"@class\":\"help.lixin.entity.User\",\"id\":1,\"name\":\"\xe5\xbc\xa0\xe4\xb8\x89\"},{\"@class\":\"help.lixin.entity.User\",\"id\":2,\"name\":\"\xe6\x9d\x8e\xe5\x9b\x9b\"},{\"@class\":\"help.lixin.entity.User\",\"id\":3,\"name\":\"\xe7\x8e\x8b\xe4\xba\x94\"},{\"@class\":\"help.lixin.entity.User\",\"id\":4,\"name\":\"\xe8\xb5\xb5\xe5\x85\xad\"}]]"