加入依赖:
<!-- Redisson依赖,根据需求,可选的 --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.0</version> </dependency> <!--Jedis 客户端--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.10.2</version> </dependency>
配置属性文件 :application-redis.yml
spring: redis: #----- 自定义分组的连接 [custom] # 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true BlockWhenExhausted: true # 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数) evictionPolicyClassName: org.apache.commons.pool2.impl.DefaultEvictionPolicy # 是否启用pool的jmx管理功能, 默认true jmxEnabled: true # 是否启用后进先出, 默认true lifo: true # 最大空闲连接数, 默认8个 maxIdle: 8 # 最小空闲连接数, 默认0 minIdle: 0 # 最大连接数, 默认8个 maxTotal: 8 # 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1 maxWaitMillis: -1 # 逐出连接的最小空闲时间 默认1800000毫秒(30分钟) minEvictableIdleTimeMillis: 1800000 # 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 numTestsPerEvictionRun: 3 # 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略) SoftMinEvictableIdleTimeMillis: 1800000 # 在获取连接的时候检查有效性, 默认false testOnBorrow: false # 在空闲时检查有效性, 默认false testWhileIdle: false # 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 timeBetweenEvictionRunsMillis: -1 clients: - host: 192.168.2.218 # 端口,默认6379 port: 6379 # 超时,默认2000 timeout: 2000 # 连接超时,默认timeout connectionTimeout: 2000 # 读取超时,默认timeout soTimeout: 2000 # 密码 password: jmrh # 数据库序号,默认0 database: 0 # 客户端名称 clientName: carleasoft # SSL连接,默认false ssl: false
配置属性对应 Java 类:
@Data @ConfigurationProperties(prefix = "spring.redis") public class IRedisProperties implements Serializable { private static final long serialVersionUID = 1L; private List<Client> clients = new ArrayList<>(); // 自定义分组的连接[custom] private Boolean blockWhenExhausted; // 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数) private String evictionPolicyClassName; // 是否启用pool的jmx管理功能, 默认true private Boolean jmxEnabled; // 是否启用后进先出, 默认true private Boolean lifo; // 最大空闲连接数, 默认8个 private int maxIdle; // 最小空闲连接数, 默认0 private int minIdle; // 最大连接数, 默认8个 private int maxTotal; // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1 private int maxWaitMillis; // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟) private Long minEvictableIdleTimeMillis; // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 private Integer numTestsPerEvictionRun; // 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略) private Long softMinEvictableIdleTimeMillis; // 创建链接时检测有效性 private boolean testOnCreate = false; // 在获取连接的时候检查有效性, 默认false private Boolean testOnBorrow; // 返回时检测有效性 private boolean testOnReturn = false; // 在空闲时检查有效性, 默认false private Boolean testWhileIdle; // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 private int timeBetweenEvictionRunsMillis; @Data public static class Client { private String host = "localhost"; // 端口,默认6379 private int port = 6379; // 超时,默认2000 private int timeout = 2000; // 连接超时,默认timeout private int connectionTimeout = 2000; // 读取超时,默认timeout private int soTimeout = 2000; // 密码 private String password; // 数据库序号,默认0 private int database = 0; // 客户端名称 private String clientName; // SSL连接,默认false private Boolean ssl = false; } }
配置:
IRedis 是Redis 的具体操作类,
IRedisAspect 是 Redis 的切面类,用来代理关闭 Jedis 的,
RedissonClient 是配置 Redisson 分布式锁的,自行按需求选择取舍
这里可以自行选需要的类进行配置
@Slf4j @Configuration @ComponentScan(basePackages = {"com.xxx.xxx.redis.service"}) @EnableConfigurationProperties(value = {IRedisProperties.class}) public class IRedisConfig { @Autowired private IRedisProperties redisProperties; private JedisPool jedisPool; @Bean @ConditionalOnProperty(name = "spring.redis") public JedisPoolConfig jedisPoolConfig() { JedisPoolConfig config = BeanUtil.copyProperties(redisProperties, JedisPoolConfig.class); return config; } @Bean @ConditionalOnBean(JedisPoolConfig.class) public JedisPool createPool(JedisPoolConfig config) { RedisProperties.Client client = redisProperties.getClients().get(0); jedisPool = new JedisPool(config, // 地址 client.getHost(), // 端口 client.getPort(), // 连接超时 client.getConnectionTimeout(), // 读取数据超时 client.getSoTimeout(), // 密码 client.getPassword(), // 默认数据库序号 client.getDatabase(), // 客户端名 client.getClientName(), // 是否使用SSL client.getSsl(), // SSL相关,使用默认 null, null, null); log.info("[ IRedis ] |- Bean [JedisPool] Auto Configure."); return jedisPool; } @Bean @ConditionalOnBean(JedisPoolConfig.class) public ShardedJedisPool shardedJedisPool(JedisPoolConfig config) { List<JedisShardInfo> shards = redisProperties.getClients().stream() .map(this::createShardInfo) .collect(Collectors.toList()); ShardedJedisPool shardedJedisPool = new ShardedJedisPool(config, shards); return shardedJedisPool; } private JedisShardInfo createShardInfo(RedisProperties.Client client){ JedisShardInfo jedisShardInfo = new JedisShardInfo( // 地址 client.getHost(), // 端口 client.getPort(), // 客户端名称 client.getClientName(), // 是否使用SSL client.getSsl(), // SSL相关,使用默认 null, null, null); jedisShardInfo.setPassword(client.getPassword()); jedisShardInfo.setConnectionTimeout(client.getConnectionTimeout()); jedisShardInfo.setSoTimeout(client.getSoTimeout()); return jedisShardInfo; } public void close() { jedisPool.close(); } /** * Redisson客户端 * * @return */ @Bean @ConditionalOnProperty(name = "spring.redis.clients") public RedissonClient redissonClient() { RedisProperties.Client client = redisProperties.getClients().get(0); Config config = new Config(); config.useSingleServer() .setAddress("redis://" + client.getHost() + ":" + client.getPort()) .setPassword(client.getPassword()) .setDatabase(0) .setConnectionPoolSize(redisProperties.getMaxTotal()) .setConnectionMinimumIdleSize(2); RedissonClient redissonClient = Redisson.create(config); log.info("[CarleaSoft] |- Bean [RedissonClient] Auto Configure."); return redissonClient; } }
Redis 具体操作工具类:
@Slf4j @Component public class IRedis { private static volatile ThreadLocal<Jedis> currentJedis = new ThreadLocal<>(); private static volatile ThreadLocal<ShardedJedis> currentShardJedis = new ThreadLocal<>(); @Autowired private JedisPool jedisPool; @Autowired private ShardedJedisPool shardedJedisPool; public Jedis getJedis() { Jedis jedis = jedisPool.getResource(); jedis.select(0); return jedis; } public ShardedJedis shardedJedis() { ShardedJedis shardedJedis = shardedJedisPool.getResource(); return shardedJedis; } public void close(Jedis jedis) { if (null != jedis) { jedis.close(); } } public void close(ShardedJedis shardedJedis) { if (null != shardedJedis) { shardedJedis.close(); } } /** * 此函数慎用 * * @return */ public Jedis threadJedis() { Jedis jedis = currentJedis.get(); if (null == jedis) { jedis = this.getJedis(); currentJedis.set(jedis); } return jedis; } public void closeJedis() { try { this.close(currentJedis.get()); } finally { // 只会删除自己线程中的数据 currentJedis.remove(); } } /** * 此函数慎用 * * @return */ public ShardedJedis threadShardJedis() { ShardedJedis shardedJedis = currentShardJedis.get(); if (null == shardedJedis) { shardedJedis = this.shardedJedis(); currentShardJedis.set(shardedJedis); } return shardedJedis; } public void closeShardJedis() { try { this.close(currentShardJedis.get()); } finally { // 只会删除自己线程中的数据 currentShardJedis.remove(); } } }
Redis 切面类,作用是辅助关闭 Jedis的,可自行选择,若不需要则无需以下部分
@Aspect @Component @AllArgsConstructor public class IRedisAspect { private final IRedis iRedis; @Pointcut("@annotation(threadJedis)") public void pointCut(ThreadJedis threadJedis) { } @Around("pointCut(threadJedis)") public Object redisAround(ProceedingJoinPoint point, ThreadJedis threadJedis) throws Throwable { Object result; try { // 调用目标方法 result = point.proceed(); } catch (Throwable throwable) { // 异常通知 throwable.printStackTrace(); throw throwable; } finally { // 后置通知 iRedis.closeJedis(); } // 返回通知 return result; } @Around("@annotation(threadShardJedis)") public Object redisAround(ProceedingJoinPoint point, ThreadShardJedis threadShardJedis) throws Throwable { Object result; try { // 调用目标方法 result = point.proceed(); } catch (Throwable throwable) { // 异常通知 throwable.printStackTrace(); throw throwable; } finally { // 后置通知 iRedis.closeShardJedis(); } // 返回通知 return result; } }
注解:
切面注解(这里使用的是注解模式切入):
/** * 注意:此注解慎用,若切面代理失效,则会造成 ThreadLocal 空间不释放 * Jedis 切面注解 * 使用注意:只能是代理对象调用时生效,类内部调用将无效必须手动关闭 ShardJedis */ @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ThreadJedis { }
/** * 注意:此注解慎用,若切面代理失效,则会造成 ThreadLocal 空间不释放 * ShardJedis 切面注解 * 使用注意:只能是代理对象调用时生效,类内部调用将无效必须手动关闭Jedis */ @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ThreadShardJedis { }
启动注解,只需要在主启动类中加入 @EnableBraineexRedis 即可开启 Redis 使用
@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(value = {IRedisConfig.class}) public @interface EnableCarleaRedis { }
主配置文件 application.yml 中需要配置引入自定的的配置文件,
spring: profiles: include:
- redis
使用:
private final IRedis iRedis; /** * 此函数禁止不允许代理失效,否则切面无法关闭 Jedis,@ThreadJedis 谨慎使用 */ @Override @ThreadJedis public DomainTag domainById(String id) { Jedis jedis = iRedis.getJedis(); // 。。。。。 // 无需申明关闭资源,代理切面会帮我们关闭 }