首页 > 编程 > Java > 正文

Java自定义注解实现Redis自动缓存的方法

2019-11-26 12:31:22
字体:
来源:转载
供稿:网友

在实际开发中,可能经常会有这样的需要:从MySQL中查询一条数据(比如用户信息),此时需要将用户信息保存至Redis。

刚开始我们可能会在查询的业务逻辑之后再写一段Redis相关操作的代码,时间长了后发现这部分代码实际上仅仅做了Redis的写入动作,跟业务逻辑没有实质的联系,那么有没有什么方法能让我们省略这些重复劳动呢?

首先想到用AOP,在查询到某些数据这一切入点(Pointcut)完成我们的切面相关处理(也就是写入Redis)。那么,如何知道什么地方需要进行缓存呢,也就是什么地方需要用到AOP呢?参考数据库事务的实现用到了@Transactional,那我们也可以自定义一个注解@RedisCache,将此注解用在需要的方法上,方法的返回结果作为需要保存的信息,方法的查询参数(比如用户的id)可以用来作为key。

上面的分析考虑下来貌似可行,那么接下来就动手实践吧!

详细步骤

1.创建一个自定义注解@RedisCache

package redis;import java.lang.annotation.*;/** * 自定义注解,结合AOP实现Redis自动缓存 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Inherited@Documentedpublic @interface RedisCache {}

2.创建缓存写入的辅助类:RedisHelper.java,其中包含一个范型方法用于接收不同类的实例对象,以保证我们的方法能够通用。这里比较简单,直接把对象转成json,在Redis中用string保存。而且不管什么情况统统写入,实际还可以完善下具体逻辑,比如判断缓存是否已存在,缓存信息是否最新等等。

package redis;import com.alibaba.fastjson.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;@Componentpublic class RedisHelper {  @Autowired  private StringRedisTemplate stringRedisTemplate;  public <T> void saveCache(String key,T t){    String json = JSONObject.toJSONString(t);    stringRedisTemplate.opsForValue().set(key,json);  }}

3.创建RedisCacheAspect.java,利用AOP框架AspectJ完成切面处理(用万金油环绕通知吧,按需要有取舍地使用具体某些类型的通知吧),我们这里用到了返回通知,也就是方法调用成功得到返回结果后进行切面处理动作

package redis;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Aspect@Componentpublic class RedisCacheAspect {  @Autowired  private RedisHelper redisHelper;  @Pointcut("@annotation(redis.RedisCache)")  public void setJoinPoint(){}  //环绕通知:可以获取返回值  @Around(value = "setJoinPoint()")  public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){    Object result = null;    try {      //前置通知      result = proceedingJoinPoint.proceed();      //返回通知      //缓存至Redis      Object[] args = proceedingJoinPoint.getArgs();      //key策略:需要缓存的对象的全类名-id,如:entity.User-1      redisHelper.saveCache(result.getClass().getName()+"-"+args[0],result);    } catch (Throwable e) {      //异常通知    }    //后置通知    return result;  }}

4.接下来是具体业务相关的代码

UserController.java

package controller;import com.alibaba.fastjson.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import service.UserService;@SuppressWarnings("unused")@Controllerpublic class UserController {  @Autowired  private UserService userService;  @RequestMapping(value = "/user/{id}", method = RequestMethod.GET,produces = "application/json;charset=utf-8")  @ResponseBody  public String test(@PathVariable Long id){    return JSONObject.toJSONString(userService.get(id));  }}

UserService.java,其中get方法上使用了自定义注解@RedisCache

package service;import dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import redis.RedisCache;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Servicepublic class UserService<User> implements BaseService<User> {  @Autowired  private UserDao userDao;  public Map add(User user) {    return null;  }  public Map update(User user) {    return null;  }  @RedisCache  public User get(Long id) {    return (User) userDao.get(id);  }  public List<User> query(User user) {    List<User> list = new ArrayList<User>();    list = userDao.query(user);    return list;  }  public Map delete(User user) {    return null;  }}

5.测试

浏览器直接访问http://localhost:8080/user/1,得到返回结果

http://localhost:8080/user/1

连接Redis查看结果

127.0.0.1:6381> keys entity*1) "entity.User-1"127.0.0.1:6381> get entity.User-1"{/"id/":1,/"mobile/":/"110/",/"name/":/"/xe7/x94/xa8/xe6/x88/xb71/",/"password/":/"123456/",/"username/":/"0001/"}"127.0.0.1:6381>

好了,到此我们已经看到开头的想法验证成功了,只需要在查询的方法上加上注解@RedisCache,就自动地悄无声息地写入Redis了,是不是很方便!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表