Sentinel can be manually protected by using the SphU class provided by Sentinel. The downside of this approach is that you have to code everything you need to restrict. Starting with version 0.1.1, Sentinel provides a handy @SentinelResource annotation.
To use annotations to protect resources, you need to introduce the following Maven dependencies:
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> The < version > 1.4.1 < / version > < / dependency >Copy the code
After it is introduced, we need to configure the SentinelResourceAspect section to make it effective, because this is done through the SentinelResourceAspect section. I use the SentinelResourceAspect section as the configuration used in 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() {
returnnew SentinelResourceAspect(); }}Copy the code
Then add a SentinelResource annotation to the methods that need to be restricted:
@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 "The error occurred at" + id;
}
Copy the code
SentinelResource: value
This parameter is mandatory
SentinelResource: blockHandler
The name of the method that handles BlockException, optional. If not configured, BlockException is thrown directly.
- The blockHandler function access scope must be public
- The return type needs to match the original method
- The parameter type needs to match the original method and end with an extra parameter of type BlockException
- The blockHandler function needs to be in the same class as the original method by default
If you do not want the exception handling method to be in the same Class as the business method, use blockHandlerClass as the corresponding Class object. Note that the corresponding function must be static, otherwise it will not be parsed.
Business method:
@SentinelResource(value = "get2", blockHandler = "handleException", blockHandlerClass = { ExceptionUtil.class })
@Override
public String get2() {
return "http://cxytiandi.com";
}
Copy the code
Exception handling classes:
import com.alibaba.csp.sentinel.slots.block.BlockException;
public final class ExceptionUtil {
public static String handleException(BlockException ex) {
System.err.println("Error occurred:" + ex.getClass().getCanonicalName());
return "error"; }}Copy the code
How to test?
We can define the rules in the Boot class of Spring Boot and quickly access the interface to see the effect, or use the stress test tool AB, etc.
@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); }}Copy the code
Source code analysis
To use annotations, you only need to configure SentinelResourceAspect. Let’s take a quick look at the SentinelResourceAspect source code
@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 {/ / get the current access Method originMethod = resolveMethod(pjp); / / get in the way that SentinelResource annotation 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();returnresult; } catch (BlockException ex) {// Handle restricted exceptions and call back pre-configured exception handling methodsreturn handleBlockException(pjp, annotation, ex);
} catch (Throwable ex) {
Tracer.trace(ex);
throw ex;
} finally {
if(entry ! = null) { entry.exit(); }}}}Copy the code
Above is the code for the entire section, for all the methods annotated with SentinelResource. Detail code in AbstractSentinelAspectSupport, everyone to see.