zoukankan      html  css  js  c++  java
  • 使用spring EL表达式+自定义切面封装缓存模块

      需求是这样的,业务代码需要使用到缓存功能以减少数据库压力,使用redis来实现,并且需要生成缓存的key由方法的传参拼接而成(貌似也只能这样才能保证同样的select查询可以使用缓存),简单的方式就是在需要缓存的方法内加上大概这样的逻辑:查询缓存--->没有则查询数据库 --->查询结果以key-value形式放入缓存,这样对业务代码造成了侵入,并且产生大量重复的代码,很不优雅,所以决定自己封装一个缓存模块,在需要缓存的地方只需要加入一个注解即可。

      首先自定义一个注解

    package com.example.test.aspect;
    
    
    import java.lang.annotation.*;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Inherited
    public @interface MyCache {
    
        String value() default "";
    }

      定义切面

    package com.example.test.aspect;
    
    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.aspectj.lang.reflect.MethodSignature;
    import org.springframework.expression.EvaluationContext;
    import org.springframework.expression.Expression;
    import org.springframework.expression.ExpressionParser;
    import org.springframework.expression.spel.standard.SpelExpressionParser;
    import org.springframework.expression.spel.support.StandardEvaluationContext;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    
    
    @Component
    @Aspect
    public class MyAspect {
    
        //切入点,带有Myche注解并且是UserService类下的方法
        @Pointcut("@annotation(com.example.test.aspect.MyCache)&&execution(* com.example.test.service.UserService.*(..))")
        public  void pointCut(){};
    
        @Around("pointCut()")
        public Object cache(ProceedingJoinPoint joinPoint)throws Throwable{
            //获取方法签名
            MethodSignature  methodSignature = (MethodSignature) joinPoint.getSignature();
            //获取目标方法
            Method method = methodSignature.getMethod();
    //       Method method2 = joinPoint.getTarget().getClass().getMethod(methodSignature.getName(),methodSignature.getParameterTypes());
            //获取方法上的注解
            MyCache myCache = method.getDeclaredAnnotation(MyCache.class);
            //得到el表达式
            String el = myCache.value();
            //解析el表达式,将#id等替换为参数值
            ExpressionParser expressionParser = new SpelExpressionParser();
            Expression expression = expressionParser.parseExpression(el);
            EvaluationContext context = new StandardEvaluationContext();
            String[] parameterNames = methodSignature.getParameterNames();
            Object[] args = joinPoint.getArgs();
            for (int i = 0; i <parameterNames.length ; i++) {
                context.setVariable(parameterNames[i],args[i]);
            }
            String key = expression.getValue(context).toString();
            System.out.println(key);
            //根据key从缓存中拿数据,这里省略
            
            //如果缓存中没有则执行目标方法
            Object o =   joinPoint.proceed();
            //将结果放入缓存,这里省略
            
            return o;
            
        }
    }

      测试的service

    package com.example.test.service;
    
    import com.example.test.aspect.MyCache;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService implements UserServiceInterface{
        
    
        @MyCache("'asd_' + #id")
        @Override
        public void addUser(String id,String name){
            System.out.println(id + "----" + name);
        }
    }

      测试类,这里是springboot项目

    package com.example.test;
    
    import com.example.test.service.UserService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class TestApplicationTests {
    
        @Autowired
        private UserService userService;
    
        @Test
        public void contextLoads() {
            System.out.println(userService.getClass().getName());
    
            userService.addUser("12345" ,"zhagnsan");
        }
    
    }

      执行结果如下:

      修改UserService上的注解为:"'asd_' + #id + '_' + #name",结果如下

  • 相关阅读:
    第三章 达瑞,一个很能挣钱的男孩
    入门代码教程第一节 如何:定义服务协定
    第二节 Windows Communication Foundation 基础概念
    入门代码教程第四节 如何:创建客户端
    BZOJ:2186: [Sdoi2008]沙拉公主的困惑
    DNN学习笔记代码学习:Provider 荣
    DNN学习笔记代码学习:DataCache 荣
    DNN学习笔记代码学习:ProviderConfiguration 荣
    DNN学习笔记代码学习:Reflection 荣
    java动态加载类
  • 原文地址:https://www.cnblogs.com/hhhshct/p/10636159.html
Copyright © 2011-2022 走看看