2018-09-24

9856 ワード

SpringbootでのAOP+redisパッケージキャッシュ
目次
一、目的二、配置--1、pom.xml--2、redis構成--3、応答クラス--4、AOPカットの構成三、自作キャッシュの使い方
一、目的
コントロールレイヤのメソッドにコメントを付けるとaop接面を利用してコードの拡張を行い,コードの拡張ではredisをキャッシュミドルウェアとして利用することができる.注記についてはカスタム@RedisCached二、配置
1、pom.xml

    org.springframework.boot
    spring-boot-starter-aop


    org.springframework.boot
    spring-boot-starter-data-redis


2、redis配置
@Configuration
public class RedisConfig {
    /**
     * @Description:        , redis           { @link RedisTemplate}
     * @Author: maozi
     * @Date: 2018/6/5 11:49
     * @see:
     **/
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory){
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(factory);
        return template;
    }
}
@Repository
public class RedisDao {

    /**
     * @Description:       { @link }
     * @Author: maozi
     * @Date: 2018/6/5 11:52
     * @see:
     **/
    @Autowired
    private StringRedisTemplate stringTemplate;

    /**
     * @Description:        { @link }
     * @Author: maozi
     * @Date: 2018/6/5 11:53
     * @see:
     **/
    @Autowired
    private RedisTemplate template;

    public void setStringKey(String key, String value,int expire) {
        if(stringTemplate.hasKey(key)){
            stringTemplate.delete(key);
        }

        ValueOperations ops = stringTemplate.opsForValue();
        ops.set(key,value,expire, TimeUnit.MINUTES);
    }

    public String getStringValue(String key) {
        ValueOperations ops = this.stringTemplate.opsForValue();
        return ops.get(key);
    }

    public Object getValue(String key) {
        return template.opsForValue().get(key);
    }

    public void setKey(String key,Object value,long minutes){
        if(template.hasKey(key)){
            template.delete(key);
        }
        template.opsForValue().set(key,value,minutes, TimeUnit.MINUTES);
    }

    public boolean existByKey(String key){
        return template.hasKey(key);
    }

    public boolean existByStringKey(String key){
        return stringTemplate.hasKey(key);
    }

    public long getExpireTime(String key){
        return template.getExpire(key);
    }

    public Boolean setExpireToReturnYes(String key,long timeout){
        if (!template.hasKey(key)){
            return false;
        }
        return template.expire(key,timeout,TimeUnit.MINUTES);
    }

    public Boolean setStringExpireToReturnYes(String key,long timeout){
        if(!stringTemplate.hasKey(key)){
            return false;
        }
        return stringTemplate.expire(key,timeout,TimeUnit.MINUTES);
    }

    public void cleanCacheByString(String key){
        stringTemplate.delete(key);
    }

    public void cleanCache(String key){
        template.delete(key);
    }
}

注意:ここのテンプレートには文字とオブジェクトがあります.valueが文字の場合、文字テンプレートが推奨されます.application.properties
# redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=1
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=500
spring.redis.pool.min-idle=0
spring.redis.timeout=0

3、応答クラス
@ApiModel(description = "      ")
public class ResponseResult {
    private String errorCode;
    private String errorMsg;
    private Object objectResult;


    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public Object getObjectResult() {
        return objectResult;
    }

    public void setObjectResult(Object objectResult) {
        this.objectResult = objectResult;
    }

    @Override
    public String toString(){
        return JSON.toJSONString(this);
    }

}

4、AOP切面の配置
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RedisCached {
    public int expire() default 5;//    ,  5  
}
/**
 * @Description: redis   AOP
 * @Author: maozi
 * @Date: 2018/9/3 10:07
 * @see: RedisCached
 **/
@Aspect
@Component
public class RedisAspect {

    private final Logger logger = LoggerFactory.getLogger(RedisAspect.class);

    @Autowired
    RedisDao redisDao;

    @Pointcut("execution(public com.zhengjia.entity.ResponseResult com.zhengjia.web.*.*(..)) && @annotation(com.zhengjia.common.Annotation.RedisCached)")
    public void redisAdvice(){}

    @Around("redisAdvice()")
    public Object Interceptor(ProceedingJoinPoint pjp){
        Object result = null;
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();

        String port = String.valueOf(request.getServerPort());
        String uri = request.getRequestURI();
        String methodType = request.getMethod();
        String queryString = request.getQueryString();

        //       
        Method method=getMethod(pjp);

        //  annotation   
        RedisCached annotation = method.getAnnotation(RedisCached.class);
        int expire = annotation.expire();

        //      
        if(!methodType.equalsIgnoreCase("GET")){
            throw new RuntimeException("   get     ");
        }

        //key     url      
        String keyName = "";
        if(method.getAnnotation(IgnoreToken.class) == null){ //        ,keyName      sourceFrom  
            String token = request.getHeader("Authorization");
            if(token.isEmpty()) throw new RuntimeException("   Authorization   token  ");
            Map userMap = (Map)redisDao.getValue(token);
            keyName = (String)userMap.get("sourceFrom") + port + uri + "?" + queryString;
        }else {
            keyName = port + uri + "?" + queryString;
        }

        ResponseResult responseResult = new ResponseResult();

        try {
            if (!redisDao.existByKey(keyName)){//     ,     
                result = pjp.proceed();
                responseResult = (ResponseResult)result;
                if(responseResult.getObjectResult() != null){ //      
                    redisDao.setKey(keyName,responseResult.getObjectResult(),expire);
                }
            }else{//     ,        
                responseResult.setObjectResult(redisDao.getValue(keyName));
                responseResult.setErrorCode(Constants.RESPONSE_CODE_SUCCESS);
                responseResult.setErrorMsg(Constants.RESPONSE_MSG_OK);
                result = responseResult;
                logger.info("redis       ,key  " + keyName);
            }

        } catch (Throwable e) {
            e.printStackTrace();
            responseResult.setErrorCode(Constants.RESPONSE_CODE_ERROR);
            responseResult.setErrorMsg("redisAspect  !");
            logger.info("redisAspect  !");
        }
        return result;
    }

    /**
     *           
     *
     *  MethodSignature.getMethod()                  
     *                
     *                     
     */
    public Method getMethod(ProceedingJoinPoint pjp){
        //       
        Object [] args=pjp.getArgs();
        Class [] argTypes=new Class[pjp.getArgs().length];
        if(args.length == 1 && args[0] == null){
            args = new Object[0];
        }
        for(int i=0;i 0){
                method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argTypes);
            }else { //      
                Class clazz = Class.forName(pjp.getSignature().getDeclaringTypeName());
                Method[] i = clazz.getMethods();
                for(Method data : clazz.getMethods()){
                    if(data.getName().equalsIgnoreCase(pjp.getSignature().getName())){
                        method = data;
                        break;
                    }
                }

            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return method;

    }
}

注意:1、キャッシュされたkeyの一意性はurlで保証され、ここではGetリクエストのみが許可され、拡張したい場合は自分でコードを修正し、keyの一意性も他の方法で決定することができます.2、ここではResponseResultのobjectResultの値をキャッシュするので、ResponseResultで戻ります.また、戻り値が切面で制限されているためです.つまり、ResponseResultで戻り値を返さなくても、このキャッシュは機能しません.3、expireは提供され、動的にキャッシュの期限切れの時間を設定する
三、自分で書いたキャッシュプログラムの使い方
/**
  *   -       
  */
@GetMapping(value = "/correlation-degree/{name}")
@RedisCached(expire = 6)
public ResponseResult shopMallCorrelationDegree(@PathVariable String name) {
    ResponseResult responseResult = new ResponseResult();

    List> resultList = bussinessCircleService.getShopMallCorrelationDegree(name);

    responseResult.setErrorCode(Constants.RESPONSE_CODE_SUCCESS);
    responseResult.setErrorMsg(Constants.RESPONSE_MSG_OK);
    responseResult.setObjectResult(resultList);
    return responseResult;
}