使用spring EL表達式+自定義切面封裝緩存模塊

  需求是這樣的,業務代碼須要使用到緩存功能以減小數據庫壓力,使用redis來實現,而且須要生成緩存的key由方法的傳參拼接而成(貌似也只能這樣才能保證一樣的select查詢能夠使用緩存),簡單的方式就是在須要緩存的方法內加上大概這樣的邏輯:查詢緩存--->沒有則查詢數據庫 --->查詢結果以key-value形式放入緩存,這樣對業務代碼形成了侵入,而且產生大量重複的代碼,很不優雅,因此決定本身封裝一個緩存模塊,在須要緩存的地方只須要加入一個註解便可。java

  首先自定義一個註解redis

package com.example.test.aspect;


import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MyCache {

    String value() default "";
}

  定義切面spring

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項目express

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",結果以下springboot

相關文章
相關標籤/搜索