Ver código fonte

Add basic demo for Sentinel Spring WebFlux adapter

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao 5 anos atrás
pai
commit
0b8f1c5838
10 arquivos alterados com 398 adições e 0 exclusões
  1. +1
    -0
      sentinel-demo/pom.xml
  2. +44
    -0
      sentinel-demo/sentinel-demo-spring-webflux/pom.xml
  3. +38
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/WebFluxDemoApplication.java
  4. +40
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/config/RedisConfig.java
  5. +59
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/config/WebFluxConfig.java
  6. +51
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/controller/BazController.java
  7. +56
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/controller/FooController.java
  8. +53
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/service/BazService.java
  9. +54
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/service/FooService.java
  10. +2
    -0
      sentinel-demo/sentinel-demo-spring-webflux/src/main/resources/application.properties

+ 1
- 0
sentinel-demo/pom.xml Ver arquivo

@@ -30,6 +30,7 @@
<module>sentinel-demo-slot-chain-spi</module>
<module>sentinel-demo-cluster</module>
<module>sentinel-demo-command-handler</module>
<module>sentinel-demo-spring-webflux</module>
</modules>

<dependencies>


+ 44
- 0
sentinel-demo/sentinel-demo-spring-webflux/pom.xml Ver arquivo

@@ -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>

+ 38
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/WebFluxDemoApplication.java Ver arquivo

@@ -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);
}
}

+ 40
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/config/RedisConfig.java Ver arquivo

@@ -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);
}
}

+ 59
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/config/WebFluxConfig.java Ver arquivo

@@ -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();
}
}

+ 51
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/controller/BazController.java Ver arquivo

@@ -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"));
}
}

+ 56
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/controller/FooController.java Ver arquivo

@@ -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();
}
}

+ 53
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/service/BazService.java Ver arquivo

@@ -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:";
}

+ 54
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/java/com/alibaba/csp/sentinel/demo/spring/webflux/service/FooService.java Ver arquivo

@@ -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);
}
}

+ 2
- 0
sentinel-demo/sentinel-demo-spring-webflux/src/main/resources/application.properties Ver arquivo

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

Carregando…
Cancelar
Salvar