关于JAVA的redis客户端的实现
来源:互联网 发布:淘宝首页服务 编辑:程序博客网 时间:2024/05/23 22:43
最近在研究java的redis使用,尤其是在spring中的使用,总结一下。
首先java的redis客户端比较好用的,也是比较常用的是Jedis。
关于Jedis需要注意的有2点:
1. Jedis不是线程安全的。也就是说当多个线程同时使用Jedis的同一个实例的时候会出现并发问题。所以Jedis提供了一个线程池JedisPool,这个我们在后面的代码中也会使用到。
2. JedisPool需要你去手动释放其中的Jedis对象,通过你去调用returnResource方法或者returnBrokenResource方法
另外在我们的实例中,因为我们不想去每次调用jedis时都写一遍释放jedis对象的方法,所以我们利用了cglib做了一个AOP,去截获所有的jedis方法,并给它加上一个释放对象的后缀。
前提基本上说完,下面我们直接来看代码。
代码主要有两个类,EnhanceRedis和RedisCacheSupport。
其中,EnhanceRedis负责Jedis的初始化,以及AOP部分
RedisCacheSupport负责具体业务的实现,比如setValue,getkey之类
//Component标签,表示这个类会被自动扫描//可以看到这个类实现了很多接口,其中FactoryBean<EnhancerRedis>是为了实现生产bean,以便于可以自动装配(@autowired)EnhancerRedis的实例//MethodInterceptor是cglib的一个接口,用来实现动态代理,从而截获jedis方法,达到AOP//JedisCommands,MultiKeyCommands, AdvancedJedisCommands等等xxxxCommands都是Jedis的接口,用来实现不同的redis命令行@Componentpublic class EnhancerRedis implements FactoryBean<EnhancerRedis>, MethodInterceptor, JedisCommands, MultiKeyCommands, AdvancedJedisCommands, ScriptingCommands, BasicCommands, ClusterCommands{ //这一部分我们通过value标签,在properties文件里面定义了redis的一些参数,比如host,最大等待时间 @Value("${redis.maxTotal}") private int maxTotal; @Value("${redis.maxWaitMillis}") private int maxWaitMillis; @Value("${redis.maxIdle}") private int maxIdle; @Value("${redis.minIdle}") private int minIdle; @Value("${redis.timeBetweenEvictionRunsMillis}") private int timeBetweenEvictionRunsMillis; @Value("${redis.hostName}") private String host; @Value("${redis.port}") private int port; @Value("${redis.password}") private String password; //Jedis的线程池 private JedisPool pool = null; //PostConstruct标签表示,被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,servlet的init()方法之前执行。 @PostConstruct public void init() { //对JedisPool的一些参数设置 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(maxTotal); config.setMaxWaitMillis(maxWaitMillis); config.setMaxIdle(maxIdle); config.setMinIdle(minIdle); config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); if(password == null || password.trim().equals("")) { pool = new JedisPool(config, host, port); } else { pool = new JedisPool(config, host, port, Protocol.DEFAULT_TIMEOUT, password); } } //这个方法继承自FactoryBean接口,返回的是这个类通过beanfactory所获得的实例 @Override public EnhancerRedis getObject() throws Exception { //Enhancer类来自cglib,用来创建一个代理(create方法),同时绑定委托类(setSuperclass),以及指定代理类(setCallback)。这里委托类和代理类都是EnhancerRedis本身。 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(EnhancerRedis.class); enhancer.setCallback(this); return (EnhancerRedis) enhancer.create(); } //这个方法继承自FactoryBean接口,表明这个类返回的bean的类型为EnhancerRedis @Override public Class<EnhancerRedis> getObjectType() { return EnhancerRedis.class; } //这个方法继承自FactoryBean接口,表示创建的bean是否是单例 @Override public boolean isSingleton() { return true; } //这个方法继承自MethodInterceptor,用来拦截所有EnhancerRedis类的方法 //因为上面的getObject()方法创建的代理,委托类和代理类都是EnhancerRedis类自身。所以这里相当于EnhancerRedis类自身拦截自身的方法,并替换成intercept里面的内容 //这个方法主要做了两件事:1.把EnhancerRedis的实例执行的方法,改成由JedisPool里面的一个实例来执行,因为EnhancerRedis继承了一堆Jedis的接口,所以EnhancerRedis实例的方法跟JedisPool里面jedis实例的方法一致。这样做的好处是外部是不知道有JedisPool这个线程池存在的,也不需要关心它是否存在 //2. 在方法执行后通过returnRedis方法释放了JedisPool里面的jedis实例,而不需要外部调用者去手动释放,同样外部调用者也感知不到释放实例,也不需要关心它是否存在 //总之通过这个类,外部调用者可以用Jedis的线程池来调用jedis的方法,但是又无需关心Jedis线程池的存在 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Jedis redis = getRedis(); Object result = null; try { //获取到截获的方法(根据方法名和参数类型) Method methodRedis = redis.getClass().getMethod(method.getName(), method.getParameterTypes()); //实际执行时,从JedisPool里面获取一个实例来执行方法(Jedis redis = getRedis()) result = methodRedis.invoke(redis, args); //执行完毕后,释放JedisPool的实例 returnRedis(redis); } catch (Exception e) { //如果出现错误,强制释放JedisPool的实例 returnBrokenRedis(redis); } return result; } //从Jedis的线程池中去一个实例 public Jedis getRedis() { return pool.getResource(); } //释放线程池中指定的实例 public void returnRedis(Jedis jed){ pool.returnResource(jed); } //释放线程池中指定的实例 public void returnBrokenRedis(Jedis jed){ pool.returnBrokenResource(jed); } //redis的操作接口,并不需要实现, 最终将用jedis的实例来操作 //下面有大量的方法,都继承自XXXCommands接口,都是redis的具体命令 //而这些方法我们都没有具体去实现,因为这些方法实际上都不会走到它自身的方法体,而是通过intercept被截获,最终走的JedisPool里面jedis实例的方法,而jedis实例的方法则不是空的,也不会return null,所以我们无需去实现这里的这些方法 @Override public String clusterNodes() { // TODO Auto-generated method stub return null; } @Override public String clusterMeet(String ip, int port) { // TODO Auto-generated method stub return null; }
EnhancerRedis类讲完,这个类主要是对jedis的初始化和封装。
下面说一下redis的实际操作类RedisCacheSupport :
public class RedisCacheSupport { final static Logger LOGGER = LoggerFactory.getLogger(RedisCacheSupport.class); protected static final String DEFAULT_CHARSET = "utf-8"; //因为EnhancerRedis类已经实现了接口FactoryBean,所以我们可以使用Autowired进行自动装配。而且这样装配出来的bean的实例,实际上走的方法是EnhancerRedis的getObject()方法,也就是说实际上通过Autowired自动装配,这里EnhancerRedis的redis已经绑定了委托类和指定了代理类,这里的redis实例实际上已经是一个proxy @Autowired protected EnhancerRedis redis; //这里的两个常量,用作redis存储的key的前缀,来区分不同的业务 /* 通用缓存KEY前缀 */ private static final String KEY_COMM = "comm_"; /* 团队数据缓存前缀 */ private static final String KEY_TEAM = "team_"; //下面几个方法是redis最简单的使用(String类型存储) //需要注意的是传进去的key要加前缀来区分业务,比如key=KEY_COMM + "001" /** * 根据key判断是否存在,存在返回true,反之返回false * @param key * @return */ public boolean exists(String key) { return redis.exists(key); } /** * 根据Key获取缓存中的值 * @param key * @return */ public String get(String key) { return redis.get(key); } /** * 设置值到缓存中 * @param key 缓存的键 * @param value 缓存的值 */ public void put(String key, String value) { redis.set(key, value); } /**
EnhancerRedis类的代码可以看这里:http://download.csdn.net/download/l00149133/10158682
RedisCacheSupport类非常简单,不再给出代码。
阅读全文
0 0
- 关于JAVA的redis客户端的实现
- JAVA实现的异步redis客户端
- 关于java 客户端链接不上redis的解决方案
- Redis的客户端实现-Jedis
- Redis的java客户端Jedis
- redis的java客户端jedis
- Redis的java客户端Jedis
- Redis的Java客户端Jedis
- Redis的Java客户端编写
- Redis的Java客户端Jedis
- windows下java swt实现操作redis的客户端工具
- 关于redis的python客户端程序
- Redis Java客户端jedis工具类以及Redis实现的跨jvm的锁
- Redis Java客户端jedis工具类以及Redis实现的跨jvm的锁
- Redis的java客户端Jedis的使用
- redis的java客户端Jedis简单封装
- redis的Java客户端jedis使用示例
- Redis 的 Java 客户端开发包 Jedis
- 利用select接收串口数据 亲测可用小demo
- 配置本地yum源
- BZOJ1823 [JSOI2010]满汉全席
- 图--最小生成树(数据结构)
- 缓存技术:Redis与Memcached对比
- 关于JAVA的redis客户端的实现
- 使用word 2013 发布csdn博客
- 往数据库里插入时间数据时,时间自动减少了14h
- HeadFirst设计模式总结_第四章工厂模式
- lombok @EqualsAndHashCode 注解的影响
- oracle学习笔记 锁基础原理
- Normal Equations 的由来与推导
- 配置用户范围settings.xml
- 极客先锋 Linux 下的dd命令使用详解(摘录)