Merge pull request #3 from alibaba/master

update
pull/1176/head
yuhuangbin 5 years ago committed by GitHub
commit 322c7db4a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -18,7 +18,7 @@
<description>Spring Cloud Alibaba Dependencies</description> <description>Spring Cloud Alibaba Dependencies</description>
<properties> <properties>
<sentinel.version>1.6.3</sentinel.version> <sentinel.version>1.7.1</sentinel.version>
<oss.version>3.1.0</oss.version> <oss.version>3.1.0</oss.version>
<seata.version>0.9.0</seata.version> <seata.version>0.9.0</seata.version>
<nacos.client.version>1.1.4</nacos.client.version> <nacos.client.version>1.1.4</nacos.client.version>
@ -198,6 +198,11 @@
<artifactId>sentinel-api-gateway-adapter-common</artifactId> <artifactId>sentinel-api-gateway-adapter-common</artifactId>
<version>${sentinel.version}</version> <version>${sentinel.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-webmvc-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!--Alibaba Seata--> <!--Alibaba Seata-->

@ -18,6 +18,7 @@ package com.alibaba.cloud.examples;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -30,7 +31,9 @@ import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -45,6 +48,52 @@ public class Application {
SpringApplication.run(Application.class, args); SpringApplication.run(Application.class, args);
} }
@Bean
public UserConfig userConfig() {
return new UserConfig();
}
}
@ConfigurationProperties(prefix = "user")
class UserConfig {
private int age;
private String name;
private Map<String, Object> map;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
@Override
public String toString() {
return "UserConfig{" + "age=" + age + ", name='" + name + '\'' + ", map=" + map
+ '}';
}
} }
@Component @Component
@ -101,19 +150,27 @@ class SampleRunner implements ApplicationRunner {
@RefreshScope @RefreshScope
class SampleController { class SampleController {
@Autowired
UserConfig userConfig;
@Autowired
private NacosConfigManager nacosConfigManager;
@Value("${user.name}") @Value("${user.name}")
String userName; String userName;
@Value("${user.age:25}") @Value("${user.age:25}")
Integer age; Integer age;
@Autowired
private NacosConfigManager nacosConfigManager;
@RequestMapping("/user") @RequestMapping("/user")
public String simple() { public String simple() {
return "Hello Nacos Config!" + "Hello " + userName + " " + age + "!" return "Hello Nacos Config!" + "Hello " + userName + " " + age + " [UserConfig]: "
+ nacosConfigManager.getConfigService(); + userConfig + "!" + nacosConfigManager.getConfigService();
}
@RequestMapping("/bool")
public boolean bool() {
return (Boolean) (userConfig.getMap().get("2"));
} }
} }

@ -13,6 +13,7 @@ spring.cloud.nacos.config.shared-configs[2]= common222.properties
spring.cloud.nacos.config.extension-configs[0].data-id= extension1.properties spring.cloud.nacos.config.extension-configs[0].data-id= extension1.properties
spring.cloud.nacos.config.extension-configs[0].refresh= true spring.cloud.nacos.config.extension-configs[0].refresh= true
spring.cloud.nacos.config.extension-configs[1]= extension2.properties spring.cloud.nacos.config.extension-configs[1]= extension2.properties
spring.cloud.nacos.config.extension-configs[2].data-id= extension3.json
#spring.cloud.nacos.config.refresh-enabled=true #spring.cloud.nacos.config.refresh-enabled=true

@ -0,0 +1,74 @@
<?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">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>nacos-discovery-example</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-discovery-consumer-sclb-example</artifactId>
<packaging>jar</packaging>
<description>Example demonstrating how to use nacos discovery</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,7 @@
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/echo-feign/openfeign`
let n++
done

@ -0,0 +1,7 @@
#!/usr/bin/env bash
n=1
while [ $n -le 10 ]
do
echo `curl -s http://localhost:18083/echo-rest/resttemplate`
let n++
done

@ -0,0 +1,155 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.cloud.examples;
import java.util.List;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.reactive.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.reactive.Request;
import org.springframework.cloud.client.loadbalancer.reactive.Response;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@SpringBootApplication
@EnableDiscoveryClient(autoRegister = false)
@EnableFeignClients
public class ConsumerSCLBApplication {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerSCLBApplication.class, args);
}
@Configuration
@LoadBalancerClient(value = "service-provider",
configuration = MyLoadBalancerConfiguration.class)
class MySCLBConfiguration {
}
static class RandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Logger log = LoggerFactory
.getLogger(RandomLoadBalancer.class);
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private final String serviceId;
private final Random random;
RandomLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId) {
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.serviceId = serviceId;
this.random = new Random();
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
log.info("random spring cloud loadbalacer active -.-");
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
private Response<ServiceInstance> getInstanceResponse(
List<ServiceInstance> instances) {
if (instances.isEmpty()) {
return new EmptyResponse();
}
ServiceInstance instance = instances.get(random.nextInt(instances.size()));
return new DefaultResponse(instance);
}
}
@FeignClient(name = "service-provider")
public interface EchoService {
@GetMapping("/echo/{str}")
String echo(@PathVariable("str") String str);
@GetMapping("/divide")
String divide(@RequestParam("a") Integer a, @RequestParam("b") Integer b);
default String divide(Integer a) {
return divide(a, 0);
}
@GetMapping("/notFound")
String notFound();
}
@RestController
class TestController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private EchoService echoService;
@GetMapping("/echo-rest/{str}")
public String rest(@PathVariable String str) {
return restTemplate.getForObject("http://service-provider/echo/" + str,
String.class);
}
@GetMapping("/echo-feign/{str}")
public String feign(@PathVariable String str) {
return echoService.echo(str);
}
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.cloud.examples;
import com.alibaba.cloud.examples.ConsumerSCLBApplication.RandomLoadBalancer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public class MyLoadBalancerConfiguration {
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
ServiceInstanceListSupplier.class), name);
}
}

@ -0,0 +1,6 @@
spring.application.name=service-consumer-sclb
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.loadbalancer.ribbon.enabled=false

@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RestController;
/** /**
* @author xiaojing * @author xiaojing
*/ */
@EnableDiscoveryClient(autoRegister = false) @EnableDiscoveryClient
@SpringBootApplication @SpringBootApplication
public class ProviderApplication { public class ProviderApplication {

@ -0,0 +1,63 @@
<?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">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>nacos-discovery-example</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-reactivediscovery-consumer-example</artifactId>
<packaging>jar</packaging>
<description>Example demonstrating how to use nacos discovery</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,74 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.cloud.examples;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@SpringBootApplication
public class ConsumerReactiveApplication {
@Bean
@LoadBalanced
public WebClient.Builder webClient() {
return WebClient.builder();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerReactiveApplication.class, args);
}
@RestController
class MyController {
@Autowired
private ReactiveDiscoveryClient reactiveDiscoveryClient;
@Autowired
private WebClient.Builder webClientBuilder;
@GetMapping("/all-services")
public Flux<String> allServices() {
return reactiveDiscoveryClient.getInstances("service-provider")
.map(serviceInstance -> serviceInstance.getHost() + ":"
+ serviceInstance.getPort());
}
@GetMapping("/service-call/{name}")
public Mono<String> serviceCall(@PathVariable("name") String name) {
return webClientBuilder.build().get()
.uri("http://service-provider/echo/" + name).retrieve()
.bodyToMono(String.class);
}
}
}

@ -0,0 +1,6 @@
spring.application.name=service-consumer-reactive
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.loadbalancer.ribbon.enabled=false

@ -18,6 +18,8 @@
<modules> <modules>
<module>nacos-discovery-consumer-example</module> <module>nacos-discovery-consumer-example</module>
<module>nacos-discovery-consumer-sclb-example</module>
<module>nacos-reactivediscovery-consumer-example</module>
<module>nacos-discovery-provider-example</module> <module>nacos-discovery-provider-example</module>
<module>nacos-discovery-spring-cloud-config-server-example</module> <module>nacos-discovery-spring-cloud-config-server-example</module>
<module>nacos-discovery-spring-cloud-config-client-example</module> <module>nacos-discovery-spring-cloud-config-client-example</module>

@ -30,6 +30,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--<dependency>--> <!--<dependency>-->
<!--<groupId>com.alibaba.csp</groupId>--> <!--<groupId>com.alibaba.csp</groupId>-->

@ -16,11 +16,18 @@
package com.alibaba.cloud.examples; package com.alibaba.cloud.examples;
import java.util.Collections;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelCircuitBreakerFactory;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelConfigBuilder;
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate; import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -47,6 +54,18 @@ public class ServiceApplication {
return new JsonFlowRuleListConverter(); return new JsonFlowRuleListConverter();
} }
@Bean
public Customizer<SentinelCircuitBreakerFactory> defaultConfig() {
return factory -> {
factory.configureDefault(
id -> new SentinelConfigBuilder().resourceName(id)
.rules(Collections.singletonList(new DegradeRule(id)
.setGrade(RuleConstant.DEGRADE_GRADE_RT).setCount(100)
.setTimeWindow(10)))
.build());
};
}
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args); SpringApplication.run(ServiceApplication.class, args);
} }

@ -19,6 +19,7 @@ package com.alibaba.cloud.examples;
import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -32,6 +33,9 @@ public class TestController {
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
@GetMapping("/hello") @GetMapping("/hello")
@SentinelResource("resource") @SentinelResource("resource")
public String hello() { public String hello() {
@ -54,4 +58,17 @@ public class TestController {
return restTemplate.getForObject("http://www.taobao.com/test", String.class); return restTemplate.getForObject("http://www.taobao.com/test", String.class);
} }
@GetMapping("/slow")
public String slow() {
return circuitBreakerFactory.create("show").run(() -> {
try {
Thread.sleep(1000L);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return "success";
}, throwable -> "fallback");
}
} }

@ -0,0 +1,36 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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.cloud.examples;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author yuhuangbin
*/
@Configuration
@EnableWebMvc
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/errorPage").setViewName("errorPage");
}
}

@ -9,6 +9,9 @@ management.health.diskspace.enabled=false
spring.cloud.sentinel.transport.dashboard=localhost:8080 spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true spring.cloud.sentinel.eager=true
#spring.cloud.sentinel.block-page=/errorPage
#spring.cloud.sentinel.filter.enabled=false
#spring.cloud.sentinel.http-method-specify=false #spring.cloud.sentinel.http-method-specify=false
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
This is error page.
</body>
</html>

@ -64,7 +64,8 @@ public class NacosConfigAutoConfiguration {
public NacosContextRefresher nacosContextRefresher( public NacosContextRefresher nacosContextRefresher(
NacosConfigManager nacosConfigManager, NacosConfigManager nacosConfigManager,
NacosRefreshHistory nacosRefreshHistory) { NacosRefreshHistory nacosRefreshHistory) {
// Consider that it is not necessary to be compatible with the previous configuration // Consider that it is not necessary to be compatible with the previous
// configuration
// and use the new configuration if necessary. // and use the new configuration if necessary.
return new NacosContextRefresher(nacosConfigManager, nacosRefreshHistory); return new NacosContextRefresher(nacosConfigManager, nacosRefreshHistory);
} }

@ -17,7 +17,6 @@
package com.alibaba.cloud.nacos.client; package com.alibaba.cloud.nacos.client;
import java.util.Date; import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -111,17 +110,7 @@ public class NacosPropertySourceBuilder {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Map<String, Object> propertiesToMap(Properties properties) { private Map<String, Object> propertiesToMap(Properties properties) {
Map<String, Object> result = new HashMap<>(16); Map<String, Object> result = new HashMap<>(16);
Enumeration<String> keys = (Enumeration<String>) properties.propertyNames(); properties.forEach((k, v) -> result.put(String.valueOf(k), v));
while (keys.hasMoreElements()) {
String key = keys.nextElement();
String value = properties.getProperty(key);
if (value != null) {
result.put(key, value.trim());
}
else {
result.put(key, null);
}
}
return result; return result;
} }

@ -111,12 +111,12 @@ public abstract class AbstractNacosDataParser {
/** /**
* Generate key-value pairs from the map. * Generate key-value pairs from the map.
*/ */
protected Properties generateProperties(Map<String, String> map) { protected Properties generateProperties(Map<String, Object> map) {
if (null == map || map.isEmpty()) { if (null == map || map.isEmpty()) {
return null; return null;
} }
Properties properties = new Properties(); Properties properties = new Properties();
for (Map.Entry<String, String> entry : map.entrySet()) { for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
if (StringUtils.isEmpty(key)) { if (StringUtils.isEmpty(key)) {
continue; continue;
@ -130,12 +130,12 @@ public abstract class AbstractNacosDataParser {
/** /**
* Reload the key ending in `value` if need. * Reload the key ending in `value` if need.
*/ */
protected Map<String, String> reloadMap(Map<String, String> map) { protected Map<String, Object> reloadMap(Map<String, Object> map) {
if (map == null || map.isEmpty()) { if (map == null || map.isEmpty()) {
return null; return null;
} }
Map<String, String> result = new HashMap<>(map); Map<String, Object> result = new HashMap<>(map);
for (Map.Entry<String, String> entry : map.entrySet()) { for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
if (key.contains(DOT)) { if (key.contains(DOT)) {
int idx = key.lastIndexOf(DOT); int idx = key.lastIndexOf(DOT);

@ -17,18 +17,22 @@
package com.alibaba.cloud.nacos.parser; package com.alibaba.cloud.nacos.parser;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* @author zkz * @author zkz
* @author yuhuangbin
*/ */
public class NacosDataJsonParser extends AbstractNacosDataParser { public class NacosDataJsonParser extends AbstractNacosDataParser {
@ -41,7 +45,7 @@ public class NacosDataJsonParser extends AbstractNacosDataParser {
if (StringUtils.isEmpty(data)) { if (StringUtils.isEmpty(data)) {
return null; return null;
} }
Map<String, String> map = parseJSON2Map(data); Map<String, Object> map = parseJSON2Map(data);
return this.generateProperties(this.reloadMap(map)); return this.generateProperties(this.reloadMap(map));
} }
@ -51,44 +55,48 @@ public class NacosDataJsonParser extends AbstractNacosDataParser {
* @return the map convert by json string * @return the map convert by json string
* @throws IOException thrown if there is a problem parsing config. * @throws IOException thrown if there is a problem parsing config.
*/ */
public static Map<String, String> parseJSON2Map(String json) throws IOException { public static Map<String, Object> parseJSON2Map(String json) throws IOException {
Map<String, String> map = new HashMap<>(32); Map<String, Object> result = new HashMap<>(32);
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(json); Map<String, Object> nacosDataMap = mapper.readValue(json, Map.class);
if (null == jsonNode) {
return map; if (CollectionUtils.isEmpty(nacosDataMap)) {
return result;
} }
parseJsonNode(map, jsonNode, ""); parseNacosDataMap(result, nacosDataMap, "");
return map; return result;
} }
private static void parseJsonNode(Map<String, String> jsonMap, JsonNode jsonNode, private static void parseNacosDataMap(Map<String, Object> result,
String parentKey) { Map<String, Object> dataMap, String parentKey) {
Iterator<String> fieldNames = jsonNode.fieldNames(); Set<Map.Entry<String, Object>> entries = dataMap.entrySet();
while (fieldNames.hasNext()) { for (Iterator<Map.Entry<String, Object>> iterator = entries.iterator(); iterator
String name = fieldNames.next(); .hasNext();) {
String fullKey = StringUtils.isEmpty(parentKey) ? name Map.Entry<String, Object> entry = iterator.next();
: parentKey + DOT + name; String key = entry.getKey();
JsonNode resultValue = jsonNode.findValue(name); Object value = entry.getValue();
if (null == resultValue) {
continue; String fullKey = StringUtils.isEmpty(parentKey) ? key : key.startsWith("[")
} ? parentKey.concat(key) : parentKey.concat(DOT).concat(key);
if (resultValue.isArray()) {
Iterator<JsonNode> iterator = resultValue.elements(); if (value instanceof Map) {
while (iterator != null && iterator.hasNext()) { Map<String, Object> map = (Map<String, Object>) value;
JsonNode next = iterator.next(); parseNacosDataMap(result, map, fullKey);
if (null == next) {
continue; continue;
} }
parseJsonNode(jsonMap, next, fullKey); else if (value instanceof Collection) {
} int count = 0;
continue; Collection<Object> collection = (Collection<Object>) value;
for (Object object : collection) {
parseNacosDataMap(result,
Collections.singletonMap("[" + (count++) + "]", object),
fullKey);
} }
if (resultValue.isObject()) {
parseJsonNode(jsonMap, resultValue, fullKey);
continue; continue;
} }
jsonMap.put(fullKey, resultValue.asText());
result.put(fullKey, value);
} }
} }

@ -50,13 +50,13 @@ public class NacosDataXmlParser extends AbstractNacosDataParser {
if (StringUtils.isEmpty(data)) { if (StringUtils.isEmpty(data)) {
return null; return null;
} }
Map<String, String> map = parseXml2Map(data); Map<String, Object> map = parseXml2Map(data);
return this.generateProperties(this.reloadMap(map)); return this.generateProperties(this.reloadMap(map));
} }
private Map<String, String> parseXml2Map(String xml) throws IOException { private Map<String, Object> parseXml2Map(String xml) throws IOException {
xml = xml.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll("\\t", ""); xml = xml.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll("\\t", "");
Map<String, String> map = new HashMap<>(32); Map<String, Object> map = new HashMap<>(32);
try { try {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance() DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder(); .newDocumentBuilder();
@ -73,7 +73,7 @@ public class NacosDataXmlParser extends AbstractNacosDataParser {
return map; return map;
} }
private void parseNodeList(NodeList nodeList, Map<String, String> map, private void parseNodeList(NodeList nodeList, Map<String, Object> map,
String parentKey) { String parentKey) {
if (nodeList == null || nodeList.getLength() < 1) { if (nodeList == null || nodeList.getLength() < 1) {
return; return;
@ -104,7 +104,7 @@ public class NacosDataXmlParser extends AbstractNacosDataParser {
} }
} }
private void parseNodeAttr(NamedNodeMap nodeMap, Map<String, String> map, private void parseNodeAttr(NamedNodeMap nodeMap, Map<String, Object> map,
String parentKey) { String parentKey) {
if (null == nodeMap || nodeMap.getLength() < 1) { if (null == nodeMap || nodeMap.getLength() < 1) {
return; return;

@ -39,6 +39,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -51,8 +52,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
@PowerMockIgnore("javax.management.*") @PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class) @PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class }) @PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, @SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, properties = {
properties = { "spring.application.name=xmlApp", "spring.profiles.active=dev", "spring.application.name=xmlApp", "spring.profiles.active=dev",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848", "spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.namespace=test-namespace", "spring.cloud.nacos.config.namespace=test-namespace",
"spring.cloud.nacos.config.encode=utf-8", "spring.cloud.nacos.config.encode=utf-8",
@ -65,10 +66,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.config.ext-config[0].data-id=ext-json-test.json", "spring.cloud.nacos.config.ext-config[0].data-id=ext-json-test.json",
"spring.cloud.nacos.config.ext-config[1].data-id=ext-common02.properties", "spring.cloud.nacos.config.ext-config[1].data-id=ext-common02.properties",
"spring.cloud.nacos.config.ext-config[1].group=GLOBAL_GROUP", "spring.cloud.nacos.config.ext-config[1].group=GLOBAL_GROUP",
"spring.cloud.nacos.config.shared-dataids=shared-data1.properties", "spring.cloud.nacos.config.shared-dataids=shared-data1.properties,shared-data.json",
"spring.cloud.nacos.config.accessKey=test-accessKey", "spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey" }, "spring.cloud.nacos.config.secretKey=test-secretKey" }, webEnvironment = NONE)
webEnvironment = NONE)
public class NacosConfigurationXmlJsonTest { public class NacosConfigurationXmlJsonTest {
static { static {
@ -136,6 +136,22 @@ public class NacosConfigurationXmlJsonTest {
return "shared-name=shared-value-1"; return "shared-name=shared-value-1";
} }
if ("shared-data.json".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "{\n" + " \"test\" : {\n"
+ " \"name\" : \"test\",\n"
+ " \"list\" : [\n" + " {\n"
+ " \"name\" :\"listname1\",\n"
+ " \"age\":1\n" + " },\n"
+ " {\n"
+ " \"name\" :\"listname2\",\n"
+ " \"age\":2\n" + " }\n"
+ " ],\n" + " \"metadata\" : {\n"
+ " \"intKey\" : 123,\n"
+ " \"booleanKey\" : true\n" + " }\n"
+ " }\n" + "}";
}
return ""; return "";
} }
}); });
@ -156,6 +172,9 @@ public class NacosConfigurationXmlJsonTest {
@Autowired @Autowired
private NacosRefreshHistory refreshHistory; private NacosRefreshHistory refreshHistory;
@Autowired
private Environment environment;
@Test @Test
public void contextLoads() throws Exception { public void contextLoads() throws Exception {
@ -176,6 +195,27 @@ public class NacosConfigurationXmlJsonTest {
checkoutEndpoint(); checkoutEndpoint();
checkJsonParser();
}
private void checkJsonParser() {
assertThat(environment.getProperty("test.name", String.class)).isEqualTo("test");
assertThat(environment.getProperty("test.list[0].name", String.class))
.isEqualTo("listname1");
assertThat(environment.getProperty("test.list[0].age", Integer.class))
.isEqualTo(1);
assertThat(environment.getProperty("test.list[1].name", String.class))
.isEqualTo("listname2");
assertThat(environment.getProperty("test.list[1].age", Integer.class))
.isEqualTo(2);
assertThat(
(Integer) environment.getProperty("test.metadata.intKey", Object.class))
.isEqualTo(123);
assertThat((Boolean) environment.getProperty("test.metadata.booleanKey",
Object.class)).isEqualTo(true);
} }
private void checkoutNacosConfigServerAddr() { private void checkoutNacosConfigServerAddr() {

@ -35,13 +35,11 @@ import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
/** /**
* @author liujunjie * @author liujunjie
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = @SpringBootTest(classes = NacosRibbonClientPropertyOverrideTests.TestConfiguration.class,
NacosRibbonClientPropertyOverrideTests.TestConfiguration.class,
properties = { "spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848", properties = { "spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.discovery.port=18080", "spring.cloud.nacos.discovery.port=18080",
"spring.cloud.nacos.discovery.service=remoteApp", "spring.cloud.nacos.discovery.service=remoteApp",
@ -54,7 +52,6 @@ public class NacosRibbonClientPropertyOverrideTests {
@Autowired @Autowired
private SpringClientFactory factory; private SpringClientFactory factory;
@Test @Test
public void serverListOverridesToTest() { public void serverListOverridesToTest() {
ConfigurationBasedServerList.class ConfigurationBasedServerList.class
@ -63,8 +60,7 @@ public class NacosRibbonClientPropertyOverrideTests {
@Test @Test
public void serverListRemoteTest() { public void serverListRemoteTest() {
NacosServerList.class NacosServerList.class.cast(getLoadBalancer("remoteApp").getServerListImpl());
.cast(getLoadBalancer("remoteApp").getServerListImpl());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -75,10 +71,11 @@ public class NacosRibbonClientPropertyOverrideTests {
@Configuration @Configuration
@RibbonClients @RibbonClients
@EnableAutoConfiguration @EnableAutoConfiguration
@ImportAutoConfiguration({UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, @ImportAutoConfiguration({ UtilAutoConfiguration.class,
ArchaiusAutoConfiguration.class, RibbonNacosAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class,
NacosDiscoveryClientConfiguration.class}) RibbonNacosAutoConfiguration.class, NacosDiscoveryClientConfiguration.class })
protected static class TestConfiguration { protected static class TestConfiguration {
} }
} }

@ -41,11 +41,6 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
@ -57,6 +52,11 @@
<artifactId>sentinel-spring-webflux-adapter</artifactId> <artifactId>sentinel-spring-webflux-adapter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-webmvc-adapter</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId> <artifactId>spring-boot-starter-webflux</artifactId>

@ -26,6 +26,11 @@ public final class SentinelConstants {
*/ */
public static final String PROPERTY_PREFIX = "spring.cloud.sentinel"; public static final String PROPERTY_PREFIX = "spring.cloud.sentinel";
/**
* Block page key.
*/
public static final String BLOCK_PAGE_URL_CONF_KEY = "csp.sentinel.web.servlet.block.page";
/** /**
* Block type. * Block type.
*/ */
@ -41,6 +46,21 @@ public final class SentinelConstants {
*/ */
public static final String URLCLEANER_TYPE = "urlCleaner"; public static final String URLCLEANER_TYPE = "urlCleaner";
/**
* The cold factor.
*/
public static final String COLD_FACTOR = "3";
/**
* The charset.
*/
public static final String CHARSET = "UTF-8";
/**
* The Sentinel api port.
*/
public static final String API_PORT = "8719";
private SentinelConstants() { private SentinelConstants() {
throw new AssertionError("Must not instantiate constant utility class"); throw new AssertionError("Must not instantiate constant utility class");
} }

@ -16,6 +16,7 @@
package com.alibaba.cloud.sentinel; package com.alibaba.cloud.sentinel;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@ -26,7 +27,9 @@ import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
/** /**
@ -52,6 +55,11 @@ public class SentinelProperties {
*/ */
private boolean enabled = true; private boolean enabled = true;
/**
* The process page when the flow control is triggered.
*/
private String blockPage;
/** /**
* Configurations about datasource, like 'nacos', 'apollo', 'file', 'zookeeper'. * Configurations about datasource, like 'nacos', 'apollo', 'file', 'zookeeper'.
*/ */
@ -75,7 +83,7 @@ public class SentinelProperties {
private Servlet servlet = new Servlet(); private Servlet servlet = new Servlet();
/** /**
* Sentinel filter when the application is web, the configuration is effective. * Sentinel interceptor when the application is web, the configuration is effective.
*/ */
private Filter filter = new Filter(); private Filter filter = new Filter();
@ -174,12 +182,23 @@ public class SentinelProperties {
this.httpMethodSpecify = httpMethodSpecify; this.httpMethodSpecify = httpMethodSpecify;
} }
public String getBlockPage() {
if (StringUtils.hasText(this.blockPage)) {
return this.blockPage;
}
return this.servlet.getBlockPage();
}
public void setBlockPage(String blockPage) {
this.blockPage = blockPage;
}
public static class Flow { public static class Flow {
/** /**
* The cold factor {@link SentinelConfig#COLD_FACTOR}. * The cold factor {@link SentinelConfig#COLD_FACTOR}.
*/ */
private String coldFactor = "3"; private String coldFactor = SentinelConstants.COLD_FACTOR;
public String getColdFactor() { public String getColdFactor() {
return coldFactor; return coldFactor;
@ -198,10 +217,15 @@ public class SentinelProperties {
*/ */
private String blockPage; private String blockPage;
@Deprecated
@DeprecatedConfigurationProperty(
reason = "replaced to SentinelProperties#blockPage.",
replacement = SentinelConstants.PROPERTY_PREFIX + ".block-page")
public String getBlockPage() { public String getBlockPage() {
return blockPage; return blockPage;
} }
@Deprecated
public void setBlockPage(String blockPage) { public void setBlockPage(String blockPage) {
this.blockPage = blockPage; this.blockPage = blockPage;
} }
@ -224,7 +248,7 @@ public class SentinelProperties {
* Charset when sentinel write or search metric file. * Charset when sentinel write or search metric file.
* {@link SentinelConfig#CHARSET} * {@link SentinelConfig#CHARSET}
*/ */
private String charset = "UTF-8"; private String charset = SentinelConstants.CHARSET;
public String getFileSingleSize() { public String getFileSingleSize() {
return fileSingleSize; return fileSingleSize;
@ -257,7 +281,7 @@ public class SentinelProperties {
/** /**
* Sentinel api port, default value is 8719 {@link TransportConfig#SERVER_PORT}. * Sentinel api port, default value is 8719 {@link TransportConfig#SERVER_PORT}.
*/ */
private String port = "8719"; private String port = SentinelConstants.API_PORT;
/** /**
* Sentinel dashboard address, won't try to connect dashboard when address is * Sentinel dashboard address, won't try to connect dashboard when address is
@ -314,18 +338,18 @@ public class SentinelProperties {
public static class Filter { public static class Filter {
/** /**
* Sentinel filter chain order. * SentinelWebInterceptor order, will be register to InterceptorRegistry.
*/ */
private int order = Ordered.HIGHEST_PRECEDENCE; private int order = Ordered.HIGHEST_PRECEDENCE;
/** /**
* URL pattern for sentinel filter, default is /*. * URL pattern for SentinelWebInterceptor, default is /*.
*/ */
private List<String> urlPatterns; private List<String> urlPatterns = Arrays.asList("/*");
/** /**
* Enable to instance * Enable to instance
* {@link com.alibaba.csp.sentinel.adapter.servlet.CommonFilter}. * {@link com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor}.
*/ */
private boolean enabled = true; private boolean enabled = true;

@ -16,18 +16,14 @@
package com.alibaba.cloud.sentinel; package com.alibaba.cloud.sentinel;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.annotation.PostConstruct; import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import javax.servlet.Filter; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.DefaultBlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -37,19 +33,22 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** /**
* @author xiaojing * @author xiaojing
* @author yuhuangbin
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(CommonFilter.class)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true) @ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@ConditionalOnClass(SentinelWebInterceptor.class)
@EnableConfigurationProperties(SentinelProperties.class) @EnableConfigurationProperties(SentinelProperties.class)
public class SentinelWebAutoConfiguration { public class SentinelWebAutoConfiguration implements WebMvcConfigurer {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(SentinelWebAutoConfiguration.class); .getLogger(SentinelWebAutoConfiguration.class);
@ -61,44 +60,61 @@ public class SentinelWebAutoConfiguration {
private Optional<UrlCleaner> urlCleanerOptional; private Optional<UrlCleaner> urlCleanerOptional;
@Autowired @Autowired
private Optional<UrlBlockHandler> urlBlockHandlerOptional; private Optional<BlockExceptionHandler> blockExceptionHandlerOptional;
@Autowired @Autowired
private Optional<RequestOriginParser> requestOriginParserOptional; private Optional<RequestOriginParser> requestOriginParserOptional;
@PostConstruct @Autowired
public void init() { private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner); @Override
requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser); public void addInterceptors(InterceptorRegistry registry) {
if (!sentinelWebInterceptorOptional.isPresent()) {
return;
}
SentinelProperties.Filter filterConfig = properties.getFilter();
registry.addInterceptor(sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info(
"[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.",
filterConfig.getUrlPatterns());
} }
@Bean @Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", @ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled",
matchIfMissing = true) matchIfMissing = true)
public FilterRegistrationBean sentinelFilter() { public SentinelWebInterceptor sentinelWebInterceptor(
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); SentinelWebMvcConfig sentinelWebMvcConfig) {
return new SentinelWebInterceptor(sentinelWebMvcConfig);
}
SentinelProperties.Filter filterConfig = properties.getFilter(); @Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled",
matchIfMissing = true)
public SentinelWebMvcConfig sentinelWebMvcConfig() {
SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
sentinelWebMvcConfig.setHttpMethodSpecify(properties.getHttpMethodSpecify());
if (filterConfig.getUrlPatterns() == null if (blockExceptionHandlerOptional.isPresent()) {
|| filterConfig.getUrlPatterns().isEmpty()) { blockExceptionHandlerOptional
List<String> defaultPatterns = new ArrayList<>(); .ifPresent(sentinelWebMvcConfig::setBlockExceptionHandler);
defaultPatterns.add("/*"); }
filterConfig.setUrlPatterns(defaultPatterns); else {
if (StringUtils.hasText(properties.getBlockPage())) {
sentinelWebMvcConfig.setBlockExceptionHandler(((request, response,
e) -> response.sendRedirect(properties.getBlockPage())));
}
else {
sentinelWebMvcConfig
.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
}
} }
registration.addUrlPatterns(filterConfig.getUrlPatterns().toArray(new String[0])); urlCleanerOptional.ifPresent(sentinelWebMvcConfig::setUrlCleaner);
Filter filter = new CommonFilter(); requestOriginParserOptional.ifPresent(sentinelWebMvcConfig::setOriginParser);
registration.setFilter(filter); return sentinelWebMvcConfig;
registration.setOrder(filterConfig.getOrder());
registration.addInitParameter("HTTP_METHOD_SPECIFY",
String.valueOf(properties.getHttpMethodSpecify()));
log.info(
"[Sentinel Starter] register Sentinel CommonFilter with urlPatterns: {}.",
filterConfig.getUrlPatterns());
return registration;
} }
} }

@ -21,7 +21,6 @@ import javax.annotation.PostConstruct;
import com.alibaba.cloud.sentinel.SentinelProperties; import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.cloud.sentinel.datasource.converter.JsonConverter; import com.alibaba.cloud.sentinel.datasource.converter.JsonConverter;
import com.alibaba.cloud.sentinel.datasource.converter.XmlConverter; import com.alibaba.cloud.sentinel.datasource.converter.XmlConverter;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.init.InitExecutor; import com.alibaba.csp.sentinel.init.InitExecutor;
@ -50,6 +49,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static com.alibaba.cloud.sentinel.SentinelConstants.BLOCK_PAGE_URL_CONF_KEY;
import static com.alibaba.csp.sentinel.config.SentinelConfig.setConfig;
/** /**
* @author xiaojing * @author xiaojing
* @author jiashuai.xie * @author jiashuai.xie
@ -124,8 +126,8 @@ public class SentinelAutoConfiguration {
System.setProperty(SentinelConfig.COLD_FACTOR, System.setProperty(SentinelConfig.COLD_FACTOR,
properties.getFlow().getColdFactor()); properties.getFlow().getColdFactor());
} }
if (StringUtils.hasText(properties.getServlet().getBlockPage())) { if (StringUtils.hasText(properties.getBlockPage())) {
WebServletConfig.setBlockPage(properties.getServlet().getBlockPage()); setConfig(BLOCK_PAGE_URL_CONF_KEY, properties.getBlockPage());
} }
// earlier initialize // earlier initialize

@ -20,7 +20,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.alibaba.cloud.sentinel.SentinelProperties; import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase; import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
@ -34,6 +33,8 @@ import com.alibaba.csp.sentinel.util.AppNameUtil;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import static com.alibaba.cloud.sentinel.SentinelConstants.BLOCK_PAGE_URL_CONF_KEY;
/** /**
* Endpoint for Sentinel, contains ans properties and rules. * Endpoint for Sentinel, contains ans properties and rules.
* *
@ -56,7 +57,7 @@ public class SentinelEndpoint {
result.put("appName", AppNameUtil.getAppName()); result.put("appName", AppNameUtil.getAppName());
result.put("logDir", LogBase.getLogBaseDir()); result.put("logDir", LogBase.getLogBaseDir());
result.put("logUsePid", LogBase.isLogNameUsePid()); result.put("logUsePid", LogBase.isLogNameUsePid());
result.put("blockPage", WebServletConfig.getBlockPage()); result.put("blockPage", SentinelConfig.getConfig(BLOCK_PAGE_URL_CONF_KEY));
result.put("metricsFileSize", SentinelConfig.singleMetricFileSize()); result.put("metricsFileSize", SentinelConfig.singleMetricFileSize());
result.put("metricsFileCharset", SentinelConfig.charset()); result.put("metricsFileCharset", SentinelConfig.charset());
result.put("totalMetricsFileCount", SentinelConfig.totalMetricFileCount()); result.put("totalMetricsFileCount", SentinelConfig.totalMetricFileCount());

@ -43,13 +43,13 @@
"name": "spring.cloud.sentinel.filter.order", "name": "spring.cloud.sentinel.filter.order",
"type": "java.lang.Integer", "type": "java.lang.Integer",
"defaultValue": "Integer.MIN_VALUE", "defaultValue": "Integer.MIN_VALUE",
"description": "sentinel filter chain order, will be set to FilterRegistrationBean." "description": "SentinelWebInterceptor order, will be register to InterceptorRegistry."
}, },
{ {
"name": "spring.cloud.sentinel.filter.enabled", "name": "spring.cloud.sentinel.filter.enabled",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
"defaultValue": true, "defaultValue": true,
"description": "Enable to instance com.alibaba.csp.sentinel.adapter.servlet.CommonFilter." "description": "Enable to register com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor."
}, },
{ {
"name": "spring.cloud.sentinel.metric.charset", "name": "spring.cloud.sentinel.metric.charset",
@ -79,10 +79,15 @@
"description": "log file should with pid." "description": "log file should with pid."
}, },
{ {
"name": "spring.cloud.sentinel.servlet.blockPage", "name": "spring.cloud.sentinel.block-page",
"type": "java.lang.String", "type": "java.lang.String",
"description": "the process page when the flow control is triggered." "description": "the process page when the flow control is triggered."
}, },
{
"name": "spring.cloud.sentinel.servlet.block-page",
"type": "java.lang.String",
"description": "recommoned use spring.cloud.sentinel.block-page."
},
{ {
"name": "spring.cloud.sentinel.flow.coldFactor", "name": "spring.cloud.sentinel.flow.coldFactor",
"type": "java.lang.String", "type": "java.lang.String",

@ -24,7 +24,6 @@ import com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration;
import com.alibaba.cloud.sentinel.custom.SentinelBeanPostProcessor; import com.alibaba.cloud.sentinel.custom.SentinelBeanPostProcessor;
import com.alibaba.cloud.sentinel.endpoint.SentinelEndpoint; import com.alibaba.cloud.sentinel.endpoint.SentinelEndpoint;
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse; import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase; import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.BlockException;
@ -43,7 +42,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
@ -55,6 +53,7 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import static com.alibaba.cloud.sentinel.SentinelConstants.BLOCK_PAGE_URL_CONF_KEY;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -70,7 +69,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.sentinel.filter.urlPatterns=/*,/test", "spring.cloud.sentinel.filter.urlPatterns=/*,/test",
"spring.cloud.sentinel.metric.fileSingleSize=9999", "spring.cloud.sentinel.metric.fileSingleSize=9999",
"spring.cloud.sentinel.metric.fileTotalCount=100", "spring.cloud.sentinel.metric.fileTotalCount=100",
"spring.cloud.sentinel.servlet.blockPage=/error", "spring.cloud.sentinel.blockPage=/error",
"spring.cloud.sentinel.flow.coldFactor=3", "spring.cloud.sentinel.flow.coldFactor=3",
"spring.cloud.sentinel.eager=true", "spring.cloud.sentinel.eager=true",
"spring.cloud.sentinel.log.switchPid=true", "spring.cloud.sentinel.log.switchPid=true",
@ -84,9 +83,6 @@ public class SentinelAutoConfigurationTests {
@Autowired @Autowired
private SentinelProperties sentinelProperties; private SentinelProperties sentinelProperties;
@Autowired
private FilterRegistrationBean filterRegistrationBean;
@Autowired @Autowired
private SentinelBeanPostProcessor sentinelBeanPostProcessor; private SentinelBeanPostProcessor sentinelBeanPostProcessor;
@ -130,9 +126,6 @@ public class SentinelAutoConfigurationTests {
@Test @Test
public void contextLoads() throws Exception { public void contextLoads() throws Exception {
assertThat(filterRegistrationBean).isNotNull();
assertThat(filterRegistrationBean).isNotNull();
assertThat(sentinelBeanPostProcessor).isNotNull(); assertThat(sentinelBeanPostProcessor).isNotNull();
checkSentinelLog(); checkSentinelLog();
@ -195,12 +188,6 @@ public class SentinelAutoConfigurationTests {
assertThat(sentinelProperties.getLog().isSwitchPid()).isEqualTo(true); assertThat(sentinelProperties.getLog().isSwitchPid()).isEqualTo(true);
} }
@Test
public void testFilter() {
assertThat(123).isEqualTo(filterRegistrationBean.getOrder());
assertThat(2).isEqualTo(filterRegistrationBean.getUrlPatterns().size());
}
@Test @Test
public void testSentinelSystemProperties() { public void testSentinelSystemProperties() {
assertThat(LogBase.isLogNameUsePid()).isEqualTo(true); assertThat(LogBase.isLogNameUsePid()).isEqualTo(true);
@ -212,7 +199,7 @@ public class SentinelAutoConfigurationTests {
assertThat(SentinelConfig.singleMetricFileSize()).isEqualTo(9999); assertThat(SentinelConfig.singleMetricFileSize()).isEqualTo(9999);
assertThat(SentinelConfig.totalMetricFileCount()).isEqualTo(100); assertThat(SentinelConfig.totalMetricFileCount()).isEqualTo(100);
assertThat(SentinelConfig.charset()).isEqualTo("UTF-8"); assertThat(SentinelConfig.charset()).isEqualTo("UTF-8");
assertThat(WebServletConfig.getBlockPage()).isEqualTo("/error"); assertThat(SentinelConfig.getConfig(BLOCK_PAGE_URL_CONF_KEY)).isEqualTo("/error");
} }
@Test @Test

@ -16,18 +16,14 @@
package com.alibaba.cloud.sentinel; package com.alibaba.cloud.sentinel;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration; import com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.DefaultBlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -53,7 +49,7 @@ public class SentinelBeanAutowiredTests {
private UrlCleaner urlCleaner; private UrlCleaner urlCleaner;
@Autowired @Autowired
private UrlBlockHandler urlBlockHandler; private BlockExceptionHandler blockExceptionHandler;
@Autowired @Autowired
private RequestOriginParser requestOriginParser; private RequestOriginParser requestOriginParser;
@ -61,10 +57,13 @@ public class SentinelBeanAutowiredTests {
@Autowired @Autowired
private SentinelProperties sentinelProperties; private SentinelProperties sentinelProperties;
@Autowired
private SentinelWebMvcConfig sentinelWebMvcConfig;
@Test @Test
public void contextLoads() throws Exception { public void contextLoads() throws Exception {
assertThat(urlCleaner).isNotNull(); assertThat(urlCleaner).isNotNull();
assertThat(urlBlockHandler).isNotNull(); assertThat(blockExceptionHandler).isNotNull();
assertThat(requestOriginParser).isNotNull(); assertThat(requestOriginParser).isNotNull();
assertThat(sentinelProperties).isNotNull(); assertThat(sentinelProperties).isNotNull();
@ -80,10 +79,10 @@ public class SentinelBeanAutowiredTests {
@Test @Test
public void testBeanAutowired() { public void testBeanAutowired() {
assertThat(WebCallbackManager.getUrlCleaner()).isEqualTo(urlCleaner); assertThat(sentinelWebMvcConfig.getUrlCleaner()).isEqualTo(urlCleaner);
assertThat(WebCallbackManager.getUrlBlockHandler()).isEqualTo(urlBlockHandler); assertThat(sentinelWebMvcConfig.getBlockExceptionHandler())
assertThat(WebCallbackManager.getRequestOriginParser()) .isEqualTo(blockExceptionHandler);
.isEqualTo(requestOriginParser); assertThat(sentinelWebMvcConfig.getOriginParser()).isEqualTo(requestOriginParser);
} }
@Configuration @Configuration
@ -113,15 +112,8 @@ public class SentinelBeanAutowiredTests {
} }
@Bean @Bean
public UrlBlockHandler urlBlockHandler() { public BlockExceptionHandler blockExceptionHandler() {
return new UrlBlockHandler() { return new DefaultBlockExceptionHandler();
@Override
public void blocked(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, BlockException e)
throws IOException {
FilterUtil.blockRequest(httpServletRequest, httpServletResponse);
}
};
} }
} }

@ -42,7 +42,8 @@ public final class RocketMQBinderUtils {
result.setNameServer(rocketBinderConfigurationProperties.getNameServer()); result.setNameServer(rocketBinderConfigurationProperties.getNameServer());
} }
else { else {
result.setNameServer(Arrays.asList(rocketMQProperties.getNameServer().split(";"))); result.setNameServer(
Arrays.asList(rocketMQProperties.getNameServer().split(";")));
} }
if (rocketMQProperties.getProducer() == null if (rocketMQProperties.getProducer() == null
|| StringUtils.isEmpty(rocketMQProperties.getProducer().getAccessKey())) { || StringUtils.isEmpty(rocketMQProperties.getProducer().getAccessKey())) {

Loading…
Cancel
Save