Sentinel: 使用注解限流


在前面我們對Sentinel做了一個詳細的介紹,可以手動的通過Sentinel提供的SphU類來保護資源。這種做法不好的地方在於每個需要限制的地方都得寫代碼,從 0.1.1 版本開始,Sentinel 提供了 @SentinelResource 注解的方式,非常方便。

要使用注解來保護資源需要引入下面的Maven依賴:

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-annotation-aspectj</artifactId>
	<version>1.4.1</version>
</dependency>

引入之后我們需要配置SentinelResourceAspect切面讓其生效,因為是通過SentinelResourceAspect切面來實現的,我這邊以Spring Boot中使用進行配置示列:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;

@Configuration
public class AopConfiguration {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
    
}

然后在需要限制的方法上加SentinelResource注解即可:

@SentinelResource(value = "get", blockHandler = "exceptionHandler")
@Override
public String get(String id) {
   return "http://cxytiandi.com";
}

public String exceptionHandler(String id, BlockException e) {
   e.printStackTrace();
   return "錯誤發生在" + id;
}

SentinelResource:value

表示資源名,必填項

SentinelResource:blockHandler

處理 BlockException 的方法名,可選項。若未配置,則將 BlockException 直接拋出。

  • blockHandler 函數訪問范圍需要是 public
  • 返回類型需要與原方法相匹配
  • 參數類型需要和原方法相匹配並且最后加一個額外的參數,類型為 BlockException
  • blockHandler 函數默認需要和原方法在同一個類中

如果你不想讓異常處理方法跟業務方法在同一個類中,可以使用 blockHandlerClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析。

業務方法:

@SentinelResource(value = "get2", blockHandler = "handleException", blockHandlerClass = { ExceptionUtil.class })
@Override
public String get2() {
	return "http://cxytiandi.com";
}

異常處理類:

import com.alibaba.csp.sentinel.slots.block.BlockException;

public final class ExceptionUtil {

    public static String handleException(BlockException ex) {
        System.err.println("錯誤發生: " + ex.getClass().getCanonicalName());
        return "error";
    }
    
}

如何測試?

我們可以在Spring Boot的啟動類中定義規則,然后快速訪問接口,就可以看出效果啦,或者用壓力測試工具ab等。

@SpringBootApplication
public class App {
	public static void main(String[] args) {
		initFlowRules();
		SpringApplication.run(App.class, args);
	}
	
	private static void initFlowRules() {
		List<FlowRule> rules = new ArrayList<>();
		
		FlowRule rule = new FlowRule();
		rule.setResource("get");
		rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
		rule.setCount(1);
		rules.add(rule);
		
		rule = new FlowRule();
		rule.setResource("get2");
		rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
		rule.setCount(1);
		rules.add(rule);
		
		FlowRuleManager.loadRules(rules);
	}
}

源碼分析

只需要配置了SentinelResourceAspect就可以使用注解,我們來簡單的看下SentinelResourceAspect的源碼

@Aspect
public class SentinelResourceAspect extends AbstractSentinelAspectSupport {

    @Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")
    public void sentinelResourceAnnotationPointcut() {
    }

    @Around("sentinelResourceAnnotationPointcut()")
    public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取當前訪問的方法
        Method originMethod = resolveMethod(pjp);
        // 獲取方法上的SentinelResource注解
        SentinelResource annotation = originMethod.getAnnotation(SentinelResource.class);
        if (annotation == null) {
            // Should not go through here.
            throw new IllegalStateException("Wrong state for SentinelResource annotation");
        }
        // 獲取資源名
        String resourceName = getResourceName(annotation.value(), originMethod);
        EntryType entryType = annotation.entryType();
        Entry entry = null;
        try {
            entry = SphU.entry(resourceName, entryType, 1, pjp.getArgs());
            Object result = pjp.proceed();
            return result;
        } catch (BlockException ex) {
            // 處理被限制的異常,回調事先配置的異常處理方法
            return handleBlockException(pjp, annotation, ex);
        } catch (Throwable ex) {
            Tracer.trace(ex);
            throw ex;
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }
}

上面是整個切面的代碼,對所有加了SentinelResource注解的方法進去切入。細節代碼在AbstractSentinelAspectSupport中,大家自己去看看。

歡迎加入我的知識星球,一起交流技術,免費學習猿天地的課程(http://cxytiandi.com/course)

PS:目前星球中正在星主的帶領下組隊學習Sentinel,等你哦!

微信掃碼加入猿天地知識星球

猿天地


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM