1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

upgrade to Spring Cloud Hoxton, close #917

This commit is contained in:
fangjian0423
2019-09-06 16:33:11 +08:00
parent 1b8973d874
commit e8ee68998e
89 changed files with 1260 additions and 85 deletions

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.adapter.reactor.EntryConfig;
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
import org.springframework.util.Assert;
/**
* Sentinel implementation of {@link ReactiveCircuitBreaker}.
*
* @author Eric Zhao
*/
public class ReactiveSentinelCircuitBreaker implements ReactiveCircuitBreaker {
private final String resourceName;
private final EntryType entryType;
private final List<DegradeRule> rules;
public ReactiveSentinelCircuitBreaker(String resourceName, EntryType entryType,
List<DegradeRule> rules) {
Assert.hasText(resourceName, "resourceName cannot be blank");
Assert.notNull(rules, "rules should not be null");
this.resourceName = resourceName;
this.entryType = entryType;
this.rules = Collections.unmodifiableList(rules);
applyToSentinelRuleManager();
}
public ReactiveSentinelCircuitBreaker(String resourceName, List<DegradeRule> rules) {
this(resourceName, EntryType.OUT, rules);
}
public ReactiveSentinelCircuitBreaker(String resourceName) {
this(resourceName, EntryType.OUT, Collections.emptyList());
}
private void applyToSentinelRuleManager() {
if (this.rules == null || this.rules.isEmpty()) {
return;
}
Set<DegradeRule> ruleSet = new HashSet<>(DegradeRuleManager.getRules());
for (DegradeRule rule : this.rules) {
if (rule == null) {
continue;
}
rule.setResource(resourceName);
ruleSet.add(rule);
}
DegradeRuleManager.loadRules(new ArrayList<>(ruleSet));
}
@Override
public <T> Mono<T> run(Mono<T> toRun, Function<Throwable, Mono<T>> fallback) {
Mono<T> toReturn = toRun.transform(new SentinelReactorTransformer<>(
new EntryConfig(resourceName, entryType)));
if (fallback != null) {
toReturn = toReturn.onErrorResume(fallback);
}
return toReturn;
}
@Override
public <T> Flux<T> run(Flux<T> toRun, Function<Throwable, Flux<T>> fallback) {
Flux<T> toReturn = toRun.transform(new SentinelReactorTransformer<>(
new EntryConfig(resourceName, entryType)));
if (fallback != null) {
toReturn = toReturn.onErrorResume(fallback);
}
return toReturn;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Eric Zhao
*/
@Configuration
@ConditionalOnClass(name = { "reactor.core.publisher.Mono",
"reactor.core.publisher.Flux" })
public class ReactiveSentinelCircuitBreakerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
public ReactiveCircuitBreakerFactory reactiveSentinelCircuitBreakerFactory() {
return new ReactiveSentinelCircuitBreakerFactory();
}
@Configuration
@ConditionalOnClass(name = { "reactor.core.publisher.Mono",
"reactor.core.publisher.Flux" })
public static class ReactiveSentinelCustomizerConfiguration {
@Autowired(required = false)
private List<Customizer<ReactiveSentinelCircuitBreakerFactory>> customizers = new ArrayList<>();
@Autowired(required = false)
private ReactiveSentinelCircuitBreakerFactory factory;
@PostConstruct
public void init() {
customizers.forEach(customizer -> customizer.customize(factory));
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.function.Function;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelConfigBuilder.SentinelCircuitBreakerConfiguration;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.util.Assert;
/**
* Factory for {@link ReactiveSentinelCircuitBreaker}.
*
* @author Eric Zhao
*/
public class ReactiveSentinelCircuitBreakerFactory extends
ReactiveCircuitBreakerFactory<SentinelCircuitBreakerConfiguration, SentinelConfigBuilder> {
private Function<String, SentinelConfigBuilder.SentinelCircuitBreakerConfiguration> defaultConfiguration = id -> new SentinelConfigBuilder()
.resourceName(id).rules(new ArrayList<>()).build();
@Override
public ReactiveCircuitBreaker create(String id) {
Assert.hasText(id, "A CircuitBreaker must have an id.");
SentinelConfigBuilder.SentinelCircuitBreakerConfiguration conf = getConfigurations()
.computeIfAbsent(id, defaultConfiguration);
return new ReactiveSentinelCircuitBreaker(id, conf.getEntryType(),
conf.getRules());
}
@Override
protected SentinelConfigBuilder configBuilder(String id) {
return new SentinelConfigBuilder(id);
}
@Override
public void configureDefault(
Function<String, SentinelCircuitBreakerConfiguration> defaultConfiguration) {
this.defaultConfiguration = defaultConfiguration;
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.util.Assert;
/**
* Sentinel implementation of {@link CircuitBreaker}.
*
* @author Eric Zhao
*/
public class SentinelCircuitBreaker implements CircuitBreaker {
private final String resourceName;
private final EntryType entryType;
private final List<DegradeRule> rules;
public SentinelCircuitBreaker(String resourceName, EntryType entryType,
List<DegradeRule> rules) {
Assert.hasText(resourceName, "resourceName cannot be blank");
Assert.notNull(rules, "rules should not be null");
this.resourceName = resourceName;
this.entryType = entryType;
this.rules = Collections.unmodifiableList(rules);
applyToSentinelRuleManager();
}
public SentinelCircuitBreaker(String resourceName, List<DegradeRule> rules) {
this(resourceName, EntryType.OUT, rules);
}
public SentinelCircuitBreaker(String resourceName) {
this(resourceName, EntryType.OUT, Collections.emptyList());
}
private void applyToSentinelRuleManager() {
if (this.rules == null || this.rules.isEmpty()) {
return;
}
Set<DegradeRule> ruleSet = new HashSet<>(DegradeRuleManager.getRules());
for (DegradeRule rule : this.rules) {
if (rule == null) {
continue;
}
rule.setResource(resourceName);
ruleSet.add(rule);
}
DegradeRuleManager.loadRules(new ArrayList<>(ruleSet));
}
@Override
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
Entry entry = null;
try {
entry = SphU.entry(resourceName, entryType);
// If the SphU.entry() does not throw `BlockException`, it means that the
// request can pass.
return toRun.get();
}
catch (BlockException ex) {
// SphU.entry() may throw BlockException which indicates that
// the request was rejected (flow control or circuit breaking triggered).
// So it should not be counted as the business exception.
return fallback.apply(ex);
}
catch (Exception ex) {
// For other kinds of exceptions, we'll trace the exception count via
// Tracer.trace(ex).
Tracer.trace(ex);
return fallback.apply(ex);
}
finally {
// Guarantee the invocation has been completed.
if (entry != null) {
entry.exit();
}
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import com.alibaba.csp.sentinel.SphU;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto configuration for {@link SentinelCircuitBreaker}.
*
* @author Eric Zhao
*/
@Configuration
@ConditionalOnClass({ SphU.class })
public class SentinelCircuitBreakerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(CircuitBreakerFactory.class)
public CircuitBreakerFactory sentinelCircuitBreakerFactory() {
return new SentinelCircuitBreakerFactory();
}
@Configuration
public static class SentinelCustomizerConfiguration {
@Autowired(required = false)
private List<Customizer<SentinelCircuitBreakerFactory>> customizers = new ArrayList<>();
@Autowired(required = false)
private SentinelCircuitBreakerFactory factory;
@PostConstruct
public void init() {
customizers.forEach(customizer -> customizer.customize(factory));
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.function.Function;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelConfigBuilder.SentinelCircuitBreakerConfiguration;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.util.Assert;
/**
* @author Eric Zhao
*/
public class SentinelCircuitBreakerFactory extends
CircuitBreakerFactory<SentinelCircuitBreakerConfiguration, SentinelConfigBuilder> {
private Function<String, SentinelConfigBuilder.SentinelCircuitBreakerConfiguration> defaultConfiguration = id -> new SentinelConfigBuilder()
.resourceName(id).entryType(EntryType.OUT).rules(new ArrayList<>()).build();
@Override
public CircuitBreaker create(String id) {
Assert.hasText(id, "A CircuitBreaker must have an id.");
SentinelConfigBuilder.SentinelCircuitBreakerConfiguration conf = getConfigurations()
.computeIfAbsent(id, defaultConfiguration);
return new SentinelCircuitBreaker(id, conf.getEntryType(), conf.getRules());
}
@Override
protected SentinelConfigBuilder configBuilder(String id) {
return new SentinelConfigBuilder(id);
}
@Override
public void configureDefault(
Function<String, SentinelCircuitBreakerConfiguration> defaultConfiguration) {
this.defaultConfiguration = defaultConfiguration;
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2013-2019 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.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import org.springframework.cloud.client.circuitbreaker.ConfigBuilder;
import org.springframework.util.Assert;
/**
* @author Eric Zhao
*/
public class SentinelConfigBuilder implements
ConfigBuilder<SentinelConfigBuilder.SentinelCircuitBreakerConfiguration> {
private String resourceName;
private EntryType entryType;
private List<DegradeRule> rules;
public SentinelConfigBuilder() {
}
public SentinelConfigBuilder(String resourceName) {
this.resourceName = resourceName;
}
public SentinelConfigBuilder resourceName(String resourceName) {
this.resourceName = resourceName;
return this;
}
public SentinelConfigBuilder entryType(EntryType entryType) {
this.entryType = entryType;
return this;
}
public SentinelConfigBuilder rules(List<DegradeRule> rules) {
this.rules = rules;
return this;
}
@Override
public SentinelCircuitBreakerConfiguration build() {
Assert.hasText(resourceName, "resourceName cannot be empty");
List<DegradeRule> rules = Optional.ofNullable(this.rules)
.orElse(new ArrayList<>());
EntryType entryType = Optional.ofNullable(this.entryType).orElse(EntryType.OUT);
return new SentinelCircuitBreakerConfiguration()
.setResourceName(this.resourceName).setEntryType(entryType)
.setRules(rules);
}
public static class SentinelCircuitBreakerConfiguration {
private String resourceName;
private EntryType entryType;
private List<DegradeRule> rules;
public String getResourceName() {
return resourceName;
}
public SentinelCircuitBreakerConfiguration setResourceName(String resourceName) {
this.resourceName = resourceName;
return this;
}
public EntryType getEntryType() {
return entryType;
}
public SentinelCircuitBreakerConfiguration setEntryType(EntryType entryType) {
this.entryType = entryType;
return this;
}
public List<DegradeRule> getRules() {
return rules;
}
public SentinelCircuitBreakerConfiguration setRules(List<DegradeRule> rules) {
this.rules = rules;
return this;
}
}
}

View File

@@ -0,0 +1,3 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.circuitbreaker.sentinel.SentinelCircuitBreakerAutoConfiguration,\
com.alibaba.cloud.circuitbreaker.sentinel.ReactiveSentinelCircuitBreakerAutoConfiguration