首頁 > 軟體

Spring AOP如何在註解上使用SPEL表示式注入物件

2022-02-17 16:01:28

在註解上使用SPEL表示式注入物件

場景描述

在平時開發中,我們經常通過定義一些註解,進行輕量級開發。

今天主要研究的內容是關於如何在註解上通過spel表示式注入物件,以此呼叫注入物件的具體業務處理邏輯,然後在通過對錶示式的解析,進而獲取該業務邏輯處理的結果,類似於Spring Security中的@PreAuthorize, @PreAuthorize, @PostAuthorize等註解,本次場景案例以模仿@PreAuthorize註解進行分析。

具體案例

定義@SpelPreAuthorize註解,對標@PreAuthorize

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpelPreAuthorize {
    String value() default "";
}

定義具體業務邏輯處理類

import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component("ps")
public class PermissionService {    
    public boolean hasPermission(String permission) {
        List<String> allPermissions = Arrays.asList("user:save", "user:delete", "user:edit");
        return allPermissions.contains(permission);
    }     
}

定義切面

  • 通過@Before註解定義前置切面
  • 通過注入spelExpressionParser解析器,用於解析spel表示式
  • 範例化EvaluationContext物件(預設實現tandardEvaluationContext),解析表示式,注入上下文資訊,執行具體業務
import com.czf.ebao.data.spel.annoation.SpelPreAuthorize;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SpelPreAuthorizeAspect {
    /**
     * 注入spring bean 工廠
     */
    @Autowired
    private DefaultListableBeanFactory defaultListableBeanFactory;
    @Before("@annotation(spelPreAuthorize)")
    public void perAuthorize(JoinPoint point, SpelPreAuthorize spelPreAuthorize) {
        String permission = spelPreAuthorize.value();
        // 範例化spel表示式解析器
        SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
        // 解析表示式內容
        Expression expression = spelExpressionParser.parseExpression(permission);
        // 宣告StandardEvaluationContext物件,用於設定上下文物件。
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setBeanResolver(new BeanFactoryResolver(defaultListableBeanFactory));
        Boolean result = expression.getValue(context, Boolean.class);
        if (!result) {
            throw new RuntimeException("該使用者無存取許可權");
        }
    }
}

定義測試類

import com.czf.ebao.data.spel.annoation.SpelPreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/spel")
public class SpelController {
    
    @GetMapping("/hello")
    @SpelPreAuthorize("@pms.hasPermission('user:hello')")
    public String sayHello() {
        return "hello";
    }
}

補充

萬用字元匹配

// import org.springframework.util.PatternMatchUtils
List<String> allPermissions = Arrays.asList("user:save", "user:delete", "user:edit");
return allPermissions.stream().anyMatch(item -> PatternMatchUtils.simpleMatch(permission, item));

Spring屬性注入方式之SPEL表示式

<bean id="categroy" class="com.test.inject.Category" p:cateName="服裝"></bean>
<bean id="calculate" class="com.test.inject.PriceCalculate"></bean>
<bean id="product" class="com.test.inject.Product" p:name="A21的T恤" p:categroy-ref="categroy">
  <property name="price" value="#{calculate.calPrice()}"></property>
</bean>

spel表示式的好處就是,我們可以使用定義好的某個類中的方法來產生值,然後注入給所需要的物件使用

比較適用於比較複雜的bean注入

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com