Add basic demo for Sentinel Spring WebFlux adapter
Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
d481014d8a
commit
0b8f1c5838
|
|
@ -30,6 +30,7 @@
|
||||||
<module>sentinel-demo-slot-chain-spi</module>
|
<module>sentinel-demo-slot-chain-spi</module>
|
||||||
<module>sentinel-demo-cluster</module>
|
<module>sentinel-demo-cluster</module>
|
||||||
<module>sentinel-demo-command-handler</module>
|
<module>sentinel-demo-command-handler</module>
|
||||||
|
<module>sentinel-demo-spring-webflux</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?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.5.0-SNAPSHOT</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-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<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>
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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:";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
spring.application.name=sentinel-webflux-demo-application
|
||||||
|
server.port=8081
|
||||||
Loading…
Reference in New Issue