Spring Aop中解析spel表示式,實現更靈活的功能
在Spring Aop中,我們可以拿到攔截方法的引數,如果能結合spel表示式,就能實現更加靈活的功能。典型的實現有Spring的快取註解:
@Cacheable(value = "user", key = "#id", condition = "#id lt 10") public User conditionFindById(final Long id) { } 複製程式碼
@Caching(put = { @CachePut(value = "user", key = "#user.id"), @CachePut(value = "user", key = "#user.username"), @CachePut(value = "user", key = "#user.email") }) public User save(User user) { 複製程式碼
本文介紹如何在aop程式設計中解析spel表示式,提供幾個通用的方法。
Spring使用自定義註解實現aop的方式這裡就不贅述,只著重介紹如何解析spel。
準備
實現非常簡單,Spring本身就提供了簡便的api,我們只需要獲取:
Method method Object[] arguments String spel
這些都能從aop入口方法的引數ProceedingJoinPoint
中得到。
spel表示式顯然就是從自定義註解中獲取了,而獲取方法和引數的方式如下:
獲取方法:
private Method getMethod(ProceedingJoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); if (method.getDeclaringClass().isInterface()) { try { method = joinPoint .getTarget() .getClass() .getDeclaredMethod(joinPoint.getSignature().getName(), method.getParameterTypes()); } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException(e); } } return method; } 複製程式碼
獲取方法引數值:
Object[] arguments = joinPoint.getArgs(); 複製程式碼
解析
然後就是解析spel表示式,首先在aop類中定義兩個屬性:
private ExpressionParser parser = new SpelExpressionParser(); private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); 複製程式碼
根據spel表示式解析引數,得到結果:
/** * 解析 spel 表示式 * * @param method方法 * @param arguments 引數 * @param spel表示式 * @param clazz返回結果的型別 * @param defaultResult 預設結果 * @return 執行spel表示式後的結果 */ private <T> T parseSpel(Method method, Object[] arguments, String spel, Class<T> clazz, T defaultResult) { String[] params = discoverer.getParameterNames(method); EvaluationContext context = new StandardEvaluationContext(); for (int len = 0; len < params.length; len++) { context.setVariable(params[len], arguments[len]); } try { Expression expression = parser.parseExpression(spel); return expression.getValue(context, clazz); } catch (Exception e) { return defaultResult; } } 複製程式碼
總結
上述就是整個解析spel表示式的關鍵流程,整體來看,aop類的結構是這樣的:
@Aspect public class SpelAspect { private ExpressionParser parser = new SpelExpressionParser(); private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); @Around(value = "@annotation(自定義註解)") public Object test(ProceedingJoinPoint point) throws Throwable { Object obj; // 獲取方法引數值 Object[] arguments = point.getArgs(); // 獲取方法 Method method = getMethod(point); // 從註解中獲取spel字串,省略... String spel = ... // 解析spel表示式 Boolean result = parseSpel(method, arguments, spel, Boolean.class, Boolean.FALSE); // 業務操作,省略... ... return point.proceed(); } } 複製程式碼
以上提供一個基本思路和幾個通用的方法(#getMethod
、#parseSpel
),接下來就是大家發揮想象力的時間啦!