This commit is contained in:
shuhongfan
2023-09-04 16:40:17 +08:00
commit cf5ac25c14
8267 changed files with 1305066 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sentinel-demo</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-demo-spring-webflux</artifactId>
<properties>
<spring.boot.version>2.1.3.RELEASE</spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-webflux-adapter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,38 @@
/*
* Copyright 1999-2019 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* <p>A demo for Spring WebFlux reactive application.</p>
*
* <p>To integrate with Sentinel dashboard, you can run the demo with the parameters (an example):
* <code>-Dproject.name=WebFluxDemoApplication -Dcsp.sentinel.dashboard.server=localhost:8080
* -Dcsp.sentinel.api.port=8720
* </code>
* </p>
*
* @author Eric Zhao
*/
@SpringBootApplication
public class WebFluxDemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebFluxDemoApplication.class, args);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author Eric Zhao
*/
@Configuration
public class RedisConfig {
@Bean
public ReactiveRedisTemplate<String, String> stringReactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory){
RedisSerializationContext<String, String> serializationContext = RedisSerializationContext
.<String, String>newSerializationContext(new StringRedisSerializer())
.hashKey(new StringRedisSerializer())
.hashValue(new StringRedisSerializer())
.build();
return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux.config;
import java.util.Collections;
import java.util.List;
import com.alibaba.csp.sentinel.adapter.spring.webflux.SentinelWebFluxFilter;
import com.alibaba.csp.sentinel.adapter.spring.webflux.exception.SentinelBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
/**
* @author Eric Zhao
*/
public class WebFluxConfig {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public WebFluxConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(-1)
public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
// Register the block exception handler for Spring WebFlux.
return new SentinelBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public SentinelWebFluxFilter sentinelWebFluxFilter() {
// Register the Sentinel WebFlux filter.
return new SentinelWebFluxFilter();
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 1999-2019 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux.controller;
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
import com.alibaba.csp.sentinel.demo.spring.webflux.service.BazService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
* @author Eric Zhao
*/
@RestController
@RequestMapping(value = "/baz")
public class BazController {
@Autowired
private BazService bazService;
@GetMapping("/{id}")
public Mono<String> apiGetValue(@PathVariable("id") Long id) {
return bazService.getById(id)
.transform(new SentinelReactorTransformer<>("BazService:getById"));
}
@PostMapping("/{id}")
public Mono<Boolean> apiSetValue(@PathVariable("id") Long id, @RequestBody String value) {
return bazService.setValue(id, value)
.transform(new SentinelReactorTransformer<>("BazService:setValue"));
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 1999-2019 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux.controller;
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
import com.alibaba.csp.sentinel.demo.spring.webflux.service.FooService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Eric Zhao
*/
@RestController
@RequestMapping(value = "/foo")
public class FooController {
@Autowired
private FooService fooService;
@GetMapping("/single")
public Mono<String> apiNormalSingle() {
return fooService.emitSingle()
// transform the publisher here.
.transform(new SentinelReactorTransformer<>("demo_foo_normal_single"));
}
@GetMapping("/flux")
public Flux<Integer> apiNormalFlux() {
return fooService.emitMultiple()
.transform(new SentinelReactorTransformer<>("demo_foo_normal_flux"));
}
@GetMapping("/slow")
public Mono<String> apiDoSomethingSlow(ServerHttpResponse response) {
return fooService.doSomethingSlow();
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 1999-2019 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
/**
* <p>A sample service for interacting with Redis via reactive Redis client.</p>
* <p>To play this service, you need a Redis instance running in local.</p>
*
* @author Eric Zhao
*/
@Service
public class BazService {
@Autowired
private ReactiveRedisTemplate<String, String> template;
public Mono<String> getById(Long id) {
if (id == null || id <= 0) {
return Mono.error(new IllegalArgumentException("invalid id: " + id));
}
return template.opsForValue()
.get(KEY_PREFIX + id)
.switchIfEmpty(Mono.just("not_found"));
}
public Mono<Boolean> setValue(Long id, String value) {
if (id == null || id <= 0 || value == null) {
return Mono.error(new IllegalArgumentException("invalid parameters"));
}
return template.opsForValue()
.set(KEY_PREFIX + id, value);
}
private static final String KEY_PREFIX = "sentinel-reactor-test:";
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.spring.webflux.service;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
/**
* @author Eric Zhao
*/
@Service
public class FooService {
@SuppressWarnings("PMD.ThreadPoolCreationRule")
private final ExecutorService pool = Executors.newFixedThreadPool(8);
private final Scheduler scheduler = Schedulers.fromExecutor(pool);
public Mono<String> emitSingle() {
return Mono.just(ThreadLocalRandom.current().nextInt(0, 2000))
.map(e -> e + "d");
}
public Flux<Integer> emitMultiple() {
int start = ThreadLocalRandom.current().nextInt(0, 6000);
return Flux.range(start, 10);
}
public Mono<String> doSomethingSlow() {
return Mono.fromCallable(() -> {
Thread.sleep(2000);
System.out.println("doSomethingSlow: " + Thread.currentThread().getName());
return "ok";
}).publishOn(scheduler);
}
}

View File

@@ -0,0 +1,2 @@
spring.application.name=sentinel-webflux-demo-application
server.port=8081