springboot项目中mybatis使用mybatis-redis开启三级缓存需要创建redis.properties优化方案
- 前言
- 下载mybatis-redis源码分析
- RedisCache 代码
- RedisConfigurationBuilder的parseConfiguration方法
- 优化改造
- 1.创建JedisConfig类
- 2.复制RedisCache代码创建自定义的MyRedisCache
- 3.指定缓存实现类为自己的类
- xml方式
- 注解方式
- 总结
前言
Springboot项目中mybatis使用mybatis-redis开启三级缓存需要创建redis.properties优化方案,如何开启三级缓存详见 十分钟带你了解Mybatis一、二、三级缓存,赶紧用起来!。
本文主要解决在使用mybatis-redis开启三级缓存时候,必须强制创建redis.properties文件,这样导致redis配置在多个地方存在,强迫症患者是无法忍受的,下面开始我们的优化改造。
下载mybatis-redis源码分析
发现mybatis-redis也是实现Cache接口实现三级缓存
RedisCache 代码
public final class RedisCache implements Cache {
private final ReadWriteLock readWriteLock = new DummyReadWriteLock();
private String id;
private static JedisPool pool;
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();
pool = new JedisPool(redisConfig, redisConfig.getHost(), redisConfig.getPort(),
redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getPassword(),
redisConfig.getDatabase(), redisConfig.getClientName());
}
。。。。
略
}
可以看到底层采用jedis做缓存框架,通过RedisConfigurationBuilder.getInstance().parseConfiguration()去获取redis配置
RedisConfigurationBuilder的parseConfiguration方法
public RedisConfig parseConfiguration(ClassLoader classLoader) {
Properties config = new Properties();
InputStream input = classLoader.getResourceAsStream(redisPropertiesFilename);
if (input != null) {
try {
config.load(input);
} catch (IOException e) {
throw new RuntimeException(
"An error occurred while reading classpath property '"
+ redisPropertiesFilename
+ "', see nested exceptions", e);
} finally {
try {
input.close();
} catch (IOException e) {
// close quietly
}
}
}
RedisConfig jedisConfig = new RedisConfig();
setConfigProperties(config, jedisConfig);
return jedisConfig;
}
可以看到这边读取是redisPropertiesFilename文件
上图可以看到默认是redis.properties文件,也可以通过system参数指定,且RedisConfigurationBuilder类是一个final类,基本上没用方法可以处理。因为源码内部只支持properties文件解析,没兼容springboot配置。
优化改造
1.创建JedisConfig类
代码如下:
package com.uhu.redis.cache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.time.Duration;
/**
* @author liujunjie
* @description
* @create 2023-11-29 11:54
**/
@Configuration
@Slf4j
public class JedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private Duration timeout;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean
public JedisPool jedisPool() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxTotal(maxActive);
// 是否启用pool的jmx管理功能, 默认true
jedisPoolConfig.setJmxEnabled(true);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, Integer.parseInt(String.valueOf(timeout.toMillis())), password);
log.info("JedisPool连接成功:" + host + ":" + port);
return jedisPool;
}
}
2.复制RedisCache代码创建自定义的MyRedisCache
代码如下:
/**
* Copyright 2015 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.uhu.cache;
import cn.hutool.extra.spring.SpringUtil;
import org.apache.ibatis.cache.Cache;
import org.mybatis.caches.redis.RedisCallback;
import org.mybatis.caches.redis.SerializeUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Map;
/**
* Cache adapter for Redis.
*
* @author Eduardo Macarron
*/
public class MyRedisCache implements Cache {
private String id;
private static JedisPool pool;
public MyRedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
pool = SpringUtil.getBean(JedisPool.class);
}
private Object execute(RedisCallback callback) {
Jedis jedis = pool.getResource();
try {
return callback.doWithRedis(jedis);
} finally {
jedis.close();
}
}
@Override
public String getId() {
return this.id;
}
@Override
public int getSize() {
return (Integer) execute(new RedisCallback() {
@Override
public Object doWithRedis(Jedis jedis) {
Map<byte[], byte[]> result = jedis.hgetAll(id.toString().getBytes());
return result.size();
}
});
}
@Override
public void putObject(final Object key, final Object value) {
execute(new RedisCallback() {
@Override
public Object doWithRedis(Jedis jedis) {
jedis.hset(id.toString().getBytes(), key.toString().getBytes(), SerializeUtil.serialize(value));
return null;
}
});
}
@Override
public Object getObject(final Object key) {
return execute(new RedisCallback() {
@Override
public Object doWithRedis(Jedis jedis) {
return SerializeUtil.unserialize(jedis.hget(id.toString().getBytes(), key.toString().getBytes()));
}
});
}
@Override
public Object removeObject(final Object key) {
return execute(new RedisCallback() {
@Override
public Object doWithRedis(Jedis jedis) {
return jedis.hdel(id.toString(), key.toString());
}
});
}
@Override
public void clear() {
execute(new RedisCallback() {
@Override
public Object doWithRedis(Jedis jedis) {
jedis.del(id.toString());
return null;
}
});
}
@Override
public String toString() {
return "Redis {" + id + "}";
}
}
3.指定缓存实现类为自己的类
xml方式
<mapper namespace="xxx">
<cache type="com.uhu.redis.cache.MyRedisCache"/>
<!--禁用某个查询使用缓存-->
<select id="findAll" resultType="xxx" useCache="false">
</select>
</mapper>
注解方式
@CacheNamespace(implementation = MyRedisCache.class)
@Mapper
public interface XxxDao {
}
总结
以上就是SpringBoot项目中Mybatis使用mybatis-redis开启三级缓存必须创建redis.properties优化方案,通过简单的源码改造,就可以让许多强迫症患者心情舒畅。