pom文件如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.eem</groupId> <artifactId>sentinel</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sentinel</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.5.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 业务类如下
import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.springframework.stereotype.Service; @Service public class DemoService { private int counter; @SentinelResource(value = "DemoService.call", blockHandler = "callBlocked") public String call() { System.out.println("Hello (" + ++counter + ")"); return counter+"---------------------"; } public String callBlocked(BlockException ex) { System.err.println("Blocked (" + ++counter + ") : " + ex.toString()); return "---------提交过于频繁,请稍后在试-------"; } /* 这个类包含两个方法,其中 call() 方法是主角,正常的业务会调用这个方法;而 callBlocked() 则会在 call() 方法被拒绝掉时调用。 call() 方法上面的 @SentinelResource 注解标明了该方法是需要进行访问控制的。Sentinel 将需要进行访问控制的方法都称作资源。这个注解有两个属性,value 属性表示该资源的名称, 我们通过名称为不同的资源制定不同的控制规则。blockHandler 属性表示方法被拒绝时应该调用哪个替代方法, 这个替代方法必须在同一个类当中,且参数列表要在原方法参数列表的基础上再添加一个 BlockException 类型的参数。*/ }
启动类如下:
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import java.util.ArrayList; import java.util.List; @EnableEurekaClient @EnableDiscoveryClient @SpringBootApplication public class SentinelApplication { public static void main(String[] args) throws Exception { initRules(); SpringApplication.run(SentinelApplication.class, args); } //规则方法 private static void initRules() throws Exception { FlowRule rule1 = new FlowRule(); rule1.setResource("DemoService.call"); rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); rule1.setCount(5); // 每秒调用最大次数为 5 次 List<FlowRule> rules = new ArrayList<>(); rules.add(rule1); // 将控制规则载入到 Sentinel com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager.loadRules(rules); } @Bean public SentinelResourceAspect sentinelResourceAspect() { return new SentinelResourceAspect(); } }
说明:
Spring 提供 AOP 机制来实现方法调用的拦截,这是 Sentinel 实现控制规则的原理。Sentinel 提供 com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect
类,我们要在 Spring 容器中加入这个 bean 才能让 @SentinelResource
注解起作用。我们需要在 SentinelTestApplication
类里面添加上面的代码:当然,在实际项目里面这一步可以放到自动配置当中。
配置文件
eureka: client: registerWithEureka: true fetchRegistry: true serviceUrl: defaultZone: http://localhost:9601/eureka/ port: 9603