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

Merge pull request #361 from fangjian0423/1.x

sync sentinel to 1.x branch
This commit is contained in:
Xiaolong Zuo 2019-02-20 15:55:06 +08:00 committed by GitHub
commit 5d69156395
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1162 additions and 1258 deletions

View File

@ -16,7 +16,7 @@
<description>Spring Cloud Alibaba Dependencies</description> <description>Spring Cloud Alibaba Dependencies</description>
<properties> <properties>
<sentinel.version>1.4.0</sentinel.version> <sentinel.version>1.4.1</sentinel.version>
<oss.version>3.1.0</oss.version> <oss.version>3.1.0</oss.version>
<nacos.version>0.8.1</nacos.version> <nacos.version>0.8.1</nacos.version>
<fescar.version>0.1.3</fescar.version> <fescar.version>0.1.3</fescar.version>

View File

@ -26,7 +26,7 @@ public class ServiceApplication {
} }
@Bean @Bean
public Converter myParser() { public Converter myConverter() {
return new JsonFlowRuleListConverter(); return new JsonFlowRuleListConverter();
} }

View File

@ -7,10 +7,22 @@ spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json #spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
#spring.cloud.sentinel.datasource.ds1.file.data-type=custom #spring.cloud.sentinel.datasource.ds1.file.data-type=custom
#spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter #spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds2.file.data-type=json spring.cloud.sentinel.datasource.ds2.file.data-type=json
spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade
spring.cloud.sentinel.datasource.ds3.file.file=classpath: authority.json
spring.cloud.sentinel.datasource.ds3.file.rule-type=authority
spring.cloud.sentinel.datasource.ds4.file.file=classpath: system.json
spring.cloud.sentinel.datasource.ds4.file.rule-type=system
spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json
spring.cloud.sentinel.datasource.ds5.file.rule-type=param-flow

View File

@ -0,0 +1,17 @@
[
{
"resource": "good",
"limitApp": "abc",
"strategy": 0
},
{
"resource": "bad",
"limitApp": "bcd",
"strategy": 1
},
{
"resource": "terrible",
"limitApp": "aaa",
"strategy": 1
}
]

View File

@ -0,0 +1,16 @@
[
{
"resource": "hotResource",
"count": 0,
"grade": 1,
"limitApp": "default",
"paramIdx": 0,
"paramFlowItemList": [
{
"object": "2",
"classType": "int",
"count": 1
}
]
}
]

View File

@ -0,0 +1,8 @@
[
{
"highestSystemLoad": -1,
"qps": 100,
"avgRt": -1,
"maxThread": 10
}
]

View File

@ -83,13 +83,18 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,135 +0,0 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
/**
* {@link NacosDataSource} now is not support aksknamespace and endpoint. This class may
* be delete when {@link NacosDataSource} support commercialized
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public class NacosDataSourceWithAuthorization<T> extends AbstractDataSource<String, T> {
private static final int DEFAULT_TIMEOUT = 3000;
private final ExecutorService pool = new ThreadPoolExecutor(1, 1, 0,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1),
new NamedThreadFactory("sentinel-nacos-auth-ds-update"),
new ThreadPoolExecutor.DiscardOldestPolicy());
private final Listener configListener;
private final Properties properties;
private final String dataId;
private final String groupId;
private ConfigService configService = null;
public NacosDataSourceWithAuthorization(final Properties properties,
final String groupId, final String dataId, Converter<String, T> parser) {
super(parser);
if (StringUtil.isBlank(groupId) || StringUtil.isBlank(dataId)) {
throw new IllegalArgumentException(String
.format("Bad argument: groupId=[%s], dataId=[%s]", groupId, dataId));
}
this.groupId = groupId;
this.dataId = dataId;
this.properties = properties;
this.configListener = new Listener() {
@Override
public Executor getExecutor() {
return pool;
}
@Override
public void receiveConfigInfo(final String configInfo) {
RecordLog.info(String.format(
"[NacosDataSourceWithAuthorization] New property value received for %s",
properties.toString()));
T newValue = NacosDataSourceWithAuthorization.this.parser
.convert(configInfo);
// Update the new value to the property.
getProperty().updateValue(newValue);
}
};
initNacosListener();
loadInitialConfig();
}
private void loadInitialConfig() {
try {
T newValue = loadConfig();
if (newValue == null) {
RecordLog.warn(
"[NacosDataSourceWithAuthorization] WARN: initial config is null, you may have to check your data source");
}
getProperty().updateValue(newValue);
}
catch (Exception ex) {
RecordLog.warn(
"[NacosDataSourceWithAuthorization] Error when loading initial config",
ex);
}
}
private void initNacosListener() {
try {
this.configService = NacosFactory.createConfigService(properties);
// Add config listener.
configService.addListener(dataId, groupId, configListener);
}
catch (Exception e) {
RecordLog.warn(
"[NacosDataSourceWithAuthorization] Error occurred when initializing Nacos data source",
e);
e.printStackTrace();
}
}
@Override
public String readSource() throws Exception {
if (configService == null) {
throw new IllegalStateException(
"Nacos config service has not been initialized or error occurred");
}
return configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
}
@Override
public void close() {
if (configService != null) {
configService.removeListener(dataId, groupId, configListener);
}
pool.shutdownNow();
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource;
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
/**
* Enum for {@link AbstractRule} class, using in
* {@link AbstractDataSourceProperties#ruleType}
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public enum RuleType {
/**
* flow
*/
FLOW("flow", FlowRule.class),
/**
* degrade
*/
DEGRADE("degrade", DegradeRule.class),
/**
* param flow
*/
PARAM_FLOW("param-flow", ParamFlowRule.class),
/**
* system
*/
SYSTEM("system", SystemRule.class),
/**
* authority
*/
AUTHORITY("authority", AuthorityRule.class);
/**
* alias for {@link AbstractRule}
*/
private final String name;
/**
* concrete {@link AbstractRule} class
*/
private final Class clazz;
RuleType(String name, Class clazz) {
this.name = name;
this.clazz = clazz;
}
public String getName() {
return name;
}
public Class getClazz() {
return clazz;
}
public static RuleType getByName(String name) {
if (StringUtils.isEmpty(name)) {
return null;
}
for (RuleType ruleType : RuleType.values()) {
if (name.equals(ruleType.getName())) {
return ruleType;
}
}
return null;
}
public static RuleType getByClass(Class clazz) {
for (RuleType ruleType : RuleType.values()) {
if (clazz.equals(ruleType.getClazz())) {
return ruleType;
}
}
return null;
}
}

View File

@ -23,14 +23,4 @@ public interface SentinelDataSourceConstants {
String PROPERTY_PREFIX = "spring.cloud.sentinel"; String PROPERTY_PREFIX = "spring.cloud.sentinel";
String NACOS_DATASOURCE_AK = PROPERTY_PREFIX + ".nacos.config.access-key";
String NACOS_DATASOURCE_SK = PROPERTY_PREFIX + ".nacos.config.secret-key";
String NACOS_DATASOURCE_NAMESPACE = PROPERTY_PREFIX + ".nacos.config.namespace";
String NACOS_DATASOURCE_ENDPOINT = PROPERTY_PREFIX + ".nacos.config.endpoint";
String PROJECT_NAME = PROPERTY_PREFIX + ".nacos.config.project-name";
} }

View File

@ -1,5 +1,32 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config; package org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotNull;
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
/** /**
@ -9,10 +36,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/ */
public class AbstractDataSourceProperties { public class AbstractDataSourceProperties {
@NotNull
private String dataType = "json"; private String dataType = "json";
@NotNull
private RuleType ruleType;
private String converterClass; private String converterClass;
@JsonIgnore @JsonIgnore
protected String factoryBeanName; private final String factoryBeanName;
public AbstractDataSourceProperties(String factoryBeanName) { public AbstractDataSourceProperties(String factoryBeanName) {
this.factoryBeanName = factoryBeanName; this.factoryBeanName = factoryBeanName;
@ -26,6 +56,14 @@ public class AbstractDataSourceProperties {
this.dataType = dataType; this.dataType = dataType;
} }
public RuleType getRuleType() {
return ruleType;
}
public void setRuleType(RuleType ruleType) {
this.ruleType = ruleType;
}
public String getConverterClass() { public String getConverterClass() {
return converterClass; return converterClass;
} }
@ -38,12 +76,29 @@ public class AbstractDataSourceProperties {
return factoryBeanName; return factoryBeanName;
} }
public void setFactoryBeanName(String factoryBeanName) { public void preCheck(String dataSourceName) {
this.factoryBeanName = factoryBeanName;
}
public void preCheck() {
} }
public void postRegister(AbstractDataSource dataSource) {
switch (this.getRuleType()) {
case FLOW:
FlowRuleManager.register2Property(dataSource.getProperty());
break;
case DEGRADE:
DegradeRuleManager.register2Property(dataSource.getProperty());
break;
case PARAM_FLOW:
ParamFlowRuleManager.register2Property(dataSource.getProperty());
break;
case SYSTEM:
SystemRuleManager.register2Property(dataSource.getProperty());
break;
case AUTHORITY:
AuthorityRuleManager.register2Property(dataSource.getProperty());
break;
default:
break;
}
}
} }

View File

@ -1,5 +1,23 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config; package org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotNull;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ApolloDataSourceFactoryBean; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ApolloDataSourceFactoryBean;
/** /**
@ -10,7 +28,9 @@ import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ApolloD
*/ */
public class ApolloDataSourceProperties extends AbstractDataSourceProperties { public class ApolloDataSourceProperties extends AbstractDataSourceProperties {
@NotNull
private String namespaceName; private String namespaceName;
@NotNull
private String flowRulesKey; private String flowRulesKey;
private String defaultFlowRuleValue; private String defaultFlowRuleValue;

View File

@ -4,6 +4,8 @@ import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.Valid;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
@ -19,12 +21,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/ */
public class DataSourcePropertiesConfiguration { public class DataSourcePropertiesConfiguration {
@Valid
private FileDataSourceProperties file; private FileDataSourceProperties file;
@Valid
private NacosDataSourceProperties nacos; private NacosDataSourceProperties nacos;
@Valid
private ZookeeperDataSourceProperties zk; private ZookeeperDataSourceProperties zk;
@Valid
private ApolloDataSourceProperties apollo; private ApolloDataSourceProperties apollo;
public DataSourcePropertiesConfiguration() { public DataSourcePropertiesConfiguration() {

View File

@ -1,7 +1,25 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config; package org.springframework.cloud.alibaba.sentinel.datasource.config;
import java.io.IOException; import java.io.IOException;
import javax.validation.constraints.NotNull;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.FileRefreshableDataSourceFactoryBean; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.FileRefreshableDataSourceFactoryBean;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -14,6 +32,7 @@ import org.springframework.util.StringUtils;
*/ */
public class FileDataSourceProperties extends AbstractDataSourceProperties { public class FileDataSourceProperties extends AbstractDataSourceProperties {
@NotNull
private String file; private String file;
private String charset = "utf-8"; private String charset = "utf-8";
private long recommendRefreshMs = 3000L; private long recommendRefreshMs = 3000L;
@ -56,16 +75,17 @@ public class FileDataSourceProperties extends AbstractDataSourceProperties {
} }
@Override @Override
public void preCheck() { public void preCheck(String dataSourceName) {
super.preCheck(); super.preCheck(dataSourceName);
try { try {
this.setFile( this.setFile(
ResourceUtils.getFile(StringUtils.trimAllWhitespace(this.getFile())) ResourceUtils.getFile(StringUtils.trimAllWhitespace(this.getFile()))
.getAbsolutePath()); .getAbsolutePath());
} }
catch (IOException e) { catch (IOException e) {
throw new RuntimeException("[Sentinel Starter] " + " handle file [" throw new RuntimeException("[Sentinel Starter] DataSource " + dataSourceName
+ this.getFile() + "] error: " + e.getMessage(), e); + " handle file [" + this.getFile() + "] error: " + e.getMessage(),
e);
} }
} }

View File

@ -1,8 +1,24 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config; package org.springframework.cloud.alibaba.sentinel.datasource.config;
import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants; import javax.validation.constraints.NotNull;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceWithAuthorizationFactoryBean;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -14,10 +30,12 @@ import org.springframework.util.StringUtils;
public class NacosDataSourceProperties extends AbstractDataSourceProperties { public class NacosDataSourceProperties extends AbstractDataSourceProperties {
private String serverAddr; private String serverAddr;
private String groupId;
private String dataId;
// commercialized usage @NotNull
private String groupId = "DEFAULT_GROUP";
@NotNull
private String dataId;
private String endpoint; private String endpoint;
private String namespace; private String namespace;
@ -29,20 +47,10 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
} }
@Override @Override
public void preCheck() { public void preCheck(String dataSourceName) {
if (!StringUtils.isEmpty(System.getProperties() if (StringUtils.isEmpty(serverAddr) && acmPropertiesInvalid()) {
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) { throw new IllegalArgumentException(
this.setServerAddr(null); "NacosDataSource properties value not correct. serverAddr is empty but there is empty value in accessKey, secretKey, endpoint, namespace property");
this.setFactoryBeanName(
NacosDataSourceWithAuthorizationFactoryBean.class.getName());
this.setEndpoint(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT));
this.setNamespace(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE));
this.setAccessKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK));
this.setSecretKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK));
} }
} }
@ -102,30 +110,9 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
this.secretKey = secretKey; this.secretKey = secretKey;
} }
public static NacosDataSourceProperties buildFlowByEDAS() { public boolean acmPropertiesInvalid() {
return buildByEDAS("flow"); return StringUtils.isEmpty(endpoint) || StringUtils.isEmpty(accessKey)
|| StringUtils.isEmpty(secretKey) || StringUtils.isEmpty(namespace);
} }
public static NacosDataSourceProperties buildDegradeByEDAS() {
return buildByEDAS("degrade");
}
public static NacosDataSourceProperties buildByEDAS(String type) {
NacosDataSourceProperties result = new NacosDataSourceProperties();
result.setFactoryBeanName(
NacosDataSourceWithAuthorizationFactoryBean.class.getName());
result.setEndpoint(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT));
result.setNamespace(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE));
result.setAccessKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK));
result.setSecretKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK));
result.setDataType("json");
result.setDataId(System.getProperties()
.getProperty(SentinelDataSourceConstants.PROJECT_NAME) + "-" + type);
result.setGroupId("nacos-sentinel");
return result;
}
} }

View File

@ -1,5 +1,23 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config; package org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotNull;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
/** /**
@ -14,6 +32,7 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties
super(ZookeeperDataSourceFactoryBean.class.getName()); super(ZookeeperDataSourceFactoryBean.class.getName());
} }
@NotNull
private String serverAddr; private String serverAddr;
private String path; private String path;

View File

@ -1,27 +1,27 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.converter; package org.springframework.cloud.alibaba.sentinel.datasource.converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
/** /**
@ -35,138 +35,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* @see ParamFlowRule * @see ParamFlowRule
* @see ObjectMapper * @see ObjectMapper
*/ */
public class JsonConverter implements Converter<String, List<AbstractRule>> { public class JsonConverter<T> extends SentinelConverter {
private static final Logger logger = LoggerFactory.getLogger(JsonConverter.class); public JsonConverter(ObjectMapper objectMapper, Class<T> ruleClass) {
super(objectMapper, ruleClass);
private final ObjectMapper objectMapper;
public JsonConverter(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
if (StringUtils.isEmpty(source)) {
logger.warn(
"Sentinel JsonConverter can not convert rules because source is empty");
return ruleList;
}
try {
List jsonArray = objectMapper.readValue(source,
new TypeReference<List<HashMap>>() {
});
for (Object obj : jsonArray) {
String itemJson = null;
try {
itemJson = objectMapper.writeValueAsString(obj);
}
catch (JsonProcessingException e) {
// won't be happen
}
List<AbstractRule> rules = Arrays.asList(convertFlowRule(itemJson),
convertDegradeRule(itemJson), convertSystemRule(itemJson),
convertAuthorityRule(itemJson), convertParamFlowRule(itemJson));
List<AbstractRule> convertRuleList = new ArrayList<>();
for (AbstractRule rule : rules) {
if (!ObjectUtils.isEmpty(rule)) {
convertRuleList.add(rule);
}
}
if (convertRuleList.size() == 0) {
logger.warn(
"Sentinel JsonConverter can not convert {} to any rules, ignore",
itemJson);
}
else if (convertRuleList.size() > 1) {
logger.warn(
"Sentinel JsonConverter convert {} and match multi rules, ignore",
itemJson);
}
else {
ruleList.add(convertRuleList.get(0));
}
}
if (jsonArray.size() != ruleList.size()) {
logger.warn(
"Sentinel JsonConverter Source list size is not equals to Target List, maybe a "
+ "part of json is invalid. Source List: " + jsonArray
+ ", Target List: " + ruleList);
}
}
catch (Exception e) {
logger.error("Sentinel JsonConverter convert error: " + e.getMessage());
throw new RuntimeException(
"Sentinel JsonConverter convert error: " + e.getMessage(), e);
}
return ruleList;
}
private FlowRule convertFlowRule(String json) {
try {
FlowRule rule = objectMapper.readValue(json, FlowRule.class);
if (FlowRuleUtil.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private DegradeRule convertDegradeRule(String json) {
try {
DegradeRule rule = objectMapper.readValue(json, DegradeRule.class);
if (DegradeRuleManager.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private SystemRule convertSystemRule(String json) {
SystemRule rule = null;
try {
rule = objectMapper.readValue(json, SystemRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private AuthorityRule convertAuthorityRule(String json) {
AuthorityRule rule = null;
try {
rule = objectMapper.readValue(json, AuthorityRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private ParamFlowRule convertParamFlowRule(String json) {
ParamFlowRule rule = null;
try {
rule = objectMapper.readValue(json, ParamFlowRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
} }
} }

View File

@ -0,0 +1,133 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.converter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Convert sentinel rules for json or xml array Using strict mode to parse json or xml
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see FlowRule
* @see DegradeRule
* @see SystemRule
* @see AuthorityRule
* @see ParamFlowRule
* @see ObjectMapper
*/
public abstract class SentinelConverter<T extends AbstractRule>
implements Converter<String, List<AbstractRule>> {
private static final Logger logger = LoggerFactory.getLogger(SentinelConverter.class);
private final ObjectMapper objectMapper;
private final Class<T> ruleClass;
public SentinelConverter(ObjectMapper objectMapper, Class<T> ruleClass) {
this.objectMapper = objectMapper;
this.ruleClass = ruleClass;
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
if (StringUtils.isEmpty(source)) {
logger.warn("converter can not convert rules because source is empty");
return ruleList;
}
try {
List sourceArray = objectMapper.readValue(source,
new TypeReference<List<HashMap>>() {
});
for (Object obj : sourceArray) {
String item = null;
try {
item = objectMapper.writeValueAsString(obj);
}
catch (JsonProcessingException e) {
// won't be happen
}
AbstractRule rule = convertRule(item);
if (rule != null) {
ruleList.add(rule);
}
}
if (ruleList.size() != sourceArray.size()) {
throw new IllegalArgumentException("convert " + ruleList.size()
+ " rules but there are " + sourceArray.size()
+ " rules from datasource. RuleClass: "
+ ruleClass.getSimpleName());
}
}
catch (Exception e) {
throw new RuntimeException("convert error: " + e.getMessage(), e);
}
return ruleList;
}
private AbstractRule convertRule(String ruleStr) {
try {
final AbstractRule rule = objectMapper.readValue(ruleStr, ruleClass);
RuleType ruleType = RuleType.getByClass(ruleClass);
switch (ruleType) {
case FLOW:
if (!FlowRuleUtil.isValidRule((FlowRule) rule)) {
return null;
}
break;
case DEGRADE:
if (!DegradeRuleManager.isValidRule((DegradeRule) rule)) {
return null;
}
default:
break;
}
return rule;
}
catch (Exception e) {
// ignore
}
return null;
}
}

View File

@ -1,27 +1,28 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.converter; package org.springframework.cloud.alibaba.sentinel.datasource.converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper;
/** /**
@ -33,139 +34,12 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper;
* @see SystemRule * @see SystemRule
* @see AuthorityRule * @see AuthorityRule
* @see ParamFlowRule * @see ParamFlowRule
* @see XmlMapper * @see ObjectMapper
*/ */
public class XmlConverter implements Converter<String, List<AbstractRule>> { public class XmlConverter<T> extends SentinelConverter {
private static final Logger logger = LoggerFactory.getLogger(XmlConverter.class); public XmlConverter(XmlMapper xmlMapper, Class<T> ruleClass) {
super(xmlMapper, ruleClass);
private final XmlMapper xmlMapper;
public XmlConverter(XmlMapper xmlMapper) {
this.xmlMapper = xmlMapper;
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
if (StringUtils.isEmpty(source)) {
logger.warn(
"Sentinel XmlConverter can not convert rules because source is empty");
return ruleList;
}
try {
List xmlArray = xmlMapper.readValue(source,
new TypeReference<List<HashMap>>() {
});
for (Object obj : xmlArray) {
String itemXml = null;
try {
itemXml = xmlMapper.writeValueAsString(obj);
}
catch (JsonProcessingException e) {
// won't be happen
}
List<AbstractRule> rules = Arrays.asList(convertFlowRule(itemXml),
convertDegradeRule(itemXml), convertSystemRule(itemXml),
convertAuthorityRule(itemXml), convertParamFlowRule(itemXml));
List<AbstractRule> convertRuleList = new ArrayList<>();
for (AbstractRule rule : rules) {
if (!ObjectUtils.isEmpty(rule)) {
convertRuleList.add(rule);
}
}
if (convertRuleList.size() == 0) {
logger.warn(
"Sentinel XmlConverter can not convert {} to any rules, ignore",
itemXml);
}
else if (convertRuleList.size() > 1) {
logger.warn(
"Sentinel XmlConverter convert {} and match multi rules, ignore",
itemXml);
}
else {
ruleList.add(convertRuleList.get(0));
}
}
if (xmlArray.size() != ruleList.size()) {
logger.warn(
"Sentinel XmlConverter Source list size is not equals to Target List, maybe a "
+ "part of xml is invalid. Source List: " + xmlArray
+ ", Target List: " + ruleList);
}
}
catch (Exception e) {
logger.error("Sentinel XmlConverter convert error: " + e.getMessage());
throw new RuntimeException(
"Sentinel XmlConverter convert error: " + e.getMessage(), e);
}
return ruleList;
}
private FlowRule convertFlowRule(String xml) {
try {
FlowRule rule = xmlMapper.readValue(xml, FlowRule.class);
if (FlowRuleUtil.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private DegradeRule convertDegradeRule(String xml) {
try {
DegradeRule rule = xmlMapper.readValue(xml, DegradeRule.class);
if (DegradeRuleManager.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private SystemRule convertSystemRule(String xml) {
SystemRule rule = null;
try {
rule = xmlMapper.readValue(xml, SystemRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private AuthorityRule convertAuthorityRule(String xml) {
AuthorityRule rule = null;
try {
rule = xmlMapper.readValue(xml, AuthorityRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private ParamFlowRule convertParamFlowRule(String json) {
ParamFlowRule rule = null;
try {
rule = xmlMapper.readValue(json, ParamFlowRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
} }
} }

View File

@ -1,9 +1,29 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.factorybean; package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.util.Properties;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource; import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.nacos.api.PropertyKeyConst;
import org.springframework.beans.factory.FactoryBean;
/** /**
* A {@link FactoryBean} for creating {@link NacosDataSource} instance. * A {@link FactoryBean} for creating {@link NacosDataSource} instance.
@ -18,14 +38,26 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
private String dataId; private String dataId;
private Converter converter; private Converter converter;
@Override private String endpoint;
public NacosDataSource getObject() throws Exception { private String namespace;
return new NacosDataSource(serverAddr, groupId, dataId, converter); private String accessKey;
} private String secretKey;
@Override @Override
public Class<?> getObjectType() { public NacosDataSource getObject() throws Exception {
return NacosDataSource.class; Properties properties = new Properties();
if (!StringUtils.isEmpty(this.serverAddr)) {
properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr);
}
else {
properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey);
properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey);
properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
}
if (!StringUtils.isEmpty(this.namespace)) {
properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace);
}
return new NacosDataSource(properties, groupId, dataId, converter);
} }
@Override @Override
@ -33,6 +65,11 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
return true; return true;
} }
@Override
public Class<?> getObjectType() {
return NacosDataSource.class;
}
public String getServerAddr() { public String getServerAddr() {
return serverAddr; return serverAddr;
} }
@ -64,4 +101,36 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
public void setConverter(Converter converter) { public void setConverter(Converter converter) {
this.converter = converter; this.converter = converter;
} }
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
} }

View File

@ -1,106 +0,0 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.util.Properties;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.cloud.alibaba.sentinel.datasource.NacosDataSourceWithAuthorization;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.nacos.api.PropertyKeyConst;
/**
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see NacosDataSource
*/
public class NacosDataSourceWithAuthorizationFactoryBean
implements FactoryBean<NacosDataSourceWithAuthorization> {
private String endpoint;
private String namespace;
private String accessKey;
private String secretKey;
private String groupId;
private String dataId;
private Converter converter;
@Override
public NacosDataSourceWithAuthorization getObject() throws Exception {
Properties properties = new Properties();
properties.put(PropertyKeyConst.ACCESS_KEY, accessKey);
properties.put(PropertyKeyConst.SECRET_KEY, secretKey);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
properties.put(PropertyKeyConst.ENDPOINT, endpoint);
return new NacosDataSourceWithAuthorization(properties, groupId, dataId,
converter);
}
@Override
public Class<?> getObjectType() {
return NacosDataSourceWithAuthorization.class;
}
@Override
public boolean isSingleton() {
return true;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
}

View File

@ -52,6 +52,12 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba.csp</groupId> <groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId> <artifactId>sentinel-parameter-flow-control</artifactId>

View File

@ -23,7 +23,10 @@ public interface SentinelConstants {
String PROPERTY_PREFIX = "spring.cloud.sentinel"; String PROPERTY_PREFIX = "spring.cloud.sentinel";
// commercialized String BLOCK_TYPE = "block";
String FALLBACK_TYPE = "fallback";
// commercialization
String FLOW_DATASOURCE_NAME = "edas-flow"; String FLOW_DATASOURCE_NAME = "edas-flow";
String DEGRADE_DATASOURCE_NAME = "edas-degrade"; String DEGRADE_DATASOURCE_NAME = "edas-degrade";

View File

@ -20,77 +20,76 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import javax.validation.Valid;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration; import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.validation.annotation.Validated;
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.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
/** /**
* {@link ConfigurationProperties} for Sentinel.
*
* @author xiaojing * @author xiaojing
* @author hengyunabc * @author hengyunabc
* @author jiashuai.xie * @author jiashuai.xie
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a> * @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/ */
@ConfigurationProperties(prefix = SentinelConstants.PROPERTY_PREFIX) @ConfigurationProperties(prefix = SentinelConstants.PROPERTY_PREFIX)
@Validated
public class SentinelProperties { public class SentinelProperties {
/** /**
* earlier initialize heart-beat when the spring container starts <note> when the * Earlier initialize heart-beat when the spring container starts when the transport
* transport dependency is on classpath ,the configuration is effective </note> * dependency is on classpath, the configuration is effective.
*/ */
private boolean eager = false; private boolean eager = false;
/** /**
* enable sentinel auto configure, the default value is true * Enable sentinel auto configure, the default value is true.
*/ */
private boolean enabled = true; private boolean enabled = true;
/** /**
* configurations about datasource, like 'nacos', 'apollo', 'file', 'zookeeper' * Configurations about datasource, like 'nacos', 'apollo', 'file', 'zookeeper'.
*/ */
@Valid
private Map<String, DataSourcePropertiesConfiguration> datasource = new TreeMap<>( private Map<String, DataSourcePropertiesConfiguration> datasource = new TreeMap<>(
String.CASE_INSENSITIVE_ORDER); String.CASE_INSENSITIVE_ORDER);
/** /**
* transport configuration about dashboard and client * Transport configuration about dashboard and client.
*/ */
@NestedConfigurationProperty
private Transport transport = new Transport(); private Transport transport = new Transport();
/** /**
* metric configuration about resource * Metric configuration about resource.
*/ */
@NestedConfigurationProperty
private Metric metric = new Metric(); private Metric metric = new Metric();
/** /**
* web servlet configuration <note> when the application is web ,the configuration is * Web servlet configuration when the application is web, the configuration is
* effective </note> * effective.
*/ */
@NestedConfigurationProperty
private Servlet servlet = new Servlet(); private Servlet servlet = new Servlet();
/** /**
* sentinel filter <note> when the application is web ,the configuration is effective * Sentinel filter when the application is web, the configuration is effective.
* </note>
*/ */
@NestedConfigurationProperty
private Filter filter = new Filter(); private Filter filter = new Filter();
/** /**
* flow configuration * Sentinel Flow configuration.
*/ */
@NestedConfigurationProperty
private Flow flow = new Flow(); private Flow flow = new Flow();
/** /**
* sentinel log configuration {@link LogBase} * Sentinel log configuration {@link LogBase}.
*/ */
@NestedConfigurationProperty
private Log log = new Log(); private Log log = new Log();
public boolean isEager() { public boolean isEager() {
@ -168,7 +167,7 @@ public class SentinelProperties {
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 = "3";
@ -185,7 +184,7 @@ public class SentinelProperties {
public static class Servlet { public static class Servlet {
/** /**
* The process page when the flow control is triggered * The process page when the flow control is triggered.
*/ */
private String blockPage; private String blockPage;
@ -201,17 +200,17 @@ public class SentinelProperties {
public static class Metric { public static class Metric {
/** /**
* the metric file size {@link SentinelConfig#SINGLE_METRIC_FILE_SIZE} * The metric file size {@link SentinelConfig#SINGLE_METRIC_FILE_SIZE}.
*/ */
private String fileSingleSize; private String fileSingleSize;
/** /**
* the total metric file count {@link SentinelConfig#TOTAL_METRIC_FILE_COUNT} * The total metric file count {@link SentinelConfig#TOTAL_METRIC_FILE_COUNT}.
*/ */
private String fileTotalCount; private String fileTotalCount;
/** /**
* 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 = "UTF-8";
@ -244,22 +243,28 @@ public class SentinelProperties {
public static class Transport { public static class Transport {
/** /**
* 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 = "8719";
/** /**
* sentinel dashboard address, won't try to connect dashboard when address is * Sentinel dashboard address, won't try to connect dashboard when address is
* empty {@link TransportConfig#CONSOLE_SERVER} * empty {@link TransportConfig#CONSOLE_SERVER}.
*/ */
private String dashboard = ""; private String dashboard = "";
/** /**
* send heartbeat interval millisecond * Send heartbeat interval millisecond
* {@link TransportConfig#HEARTBEAT_INTERVAL_MS} * {@link TransportConfig#HEARTBEAT_INTERVAL_MS}.
*/ */
private String heartbeatIntervalMs; private String heartbeatIntervalMs;
/**
* Get heartbeat client local ip. If the client ip not configured, it will be the
* address of local host.
*/
private String clientIp;
public String getHeartbeatIntervalMs() { public String getHeartbeatIntervalMs() {
return heartbeatIntervalMs; return heartbeatIntervalMs;
} }
@ -284,12 +289,19 @@ public class SentinelProperties {
this.dashboard = dashboard; this.dashboard = dashboard;
} }
public String getClientIp() {
return clientIp;
}
public void setClientIp(String clientIp) {
this.clientIp = clientIp;
}
} }
public static class Filter { public static class Filter {
/** /**
* sentinel filter chain order. * Sentinel filter chain order.
*/ */
private int order = Ordered.HIGHEST_PRECEDENCE; private int order = Ordered.HIGHEST_PRECEDENCE;
@ -318,12 +330,12 @@ public class SentinelProperties {
public static class Log { public static class Log {
/** /**
* sentinel log base dir * Sentinel log base dir.
*/ */
private String dir; private String dir;
/** /**
* distinguish the log file by pid number * Distinguish the log file by pid number.
*/ */
private boolean switchPid = false; private boolean switchPid = false;

View File

@ -21,8 +21,6 @@ import java.util.List;
import javax.servlet.Filter; import javax.servlet.Filter;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -33,6 +31,8 @@ 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 com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
/** /**
* @author xiaojing * @author xiaojing
*/ */
@ -54,11 +54,6 @@ public class SentinelWebAutoConfiguration {
SentinelProperties.Filter filterConfig = properties.getFilter(); SentinelProperties.Filter filterConfig = properties.getFilter();
if (null == filterConfig) {
filterConfig = new SentinelProperties.Filter();
properties.setFilter(filterConfig);
}
if (filterConfig.getUrlPatterns() == null if (filterConfig.getUrlPatterns() == null
|| filterConfig.getUrlPatterns().isEmpty()) { || filterConfig.getUrlPatterns().isEmpty()) {
List<String> defaultPatterns = new ArrayList<>(); List<String> defaultPatterns = new ArrayList<>();

View File

@ -20,6 +20,7 @@ import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -27,10 +28,12 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.alibaba.sentinel.SentinelProperties; import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter; import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter; import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
import org.springframework.context.ApplicationContext;
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.util.StringUtils;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
@ -39,6 +42,11 @@ 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;
import com.alibaba.csp.sentinel.log.LogBase; import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.AppNameUtil; import com.alibaba.csp.sentinel.util.AppNameUtil;
@ -47,6 +55,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper;
/** /**
* @author xiaojing * @author xiaojing
* @author jiashuai.xie
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a> * @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/ */
@Configuration @Configuration
@ -66,8 +75,20 @@ public class SentinelAutoConfiguration {
@Autowired(required = false) @Autowired(required = false)
private UrlBlockHandler urlBlockHandler; private UrlBlockHandler urlBlockHandler;
@Autowired(required = false)
private RequestOriginParser requestOriginParser;
@PostConstruct @PostConstruct
private void init() { private void init() {
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
&& StringUtils.hasText(properties.getLog().getDir())) {
System.setProperty(LogBase.LOG_DIR, properties.getLog().getDir());
}
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_NAME_USE_PID))
&& properties.getLog().isSwitchPid()) {
System.setProperty(LogBase.LOG_NAME_USE_PID,
String.valueOf(properties.getLog().isSwitchPid()));
}
if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME)) if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME))
&& StringUtils.hasText(projectName)) { && StringUtils.hasText(projectName)) {
System.setProperty(AppNameUtil.APP_NAME, projectName); System.setProperty(AppNameUtil.APP_NAME, projectName);
@ -88,6 +109,11 @@ public class SentinelAutoConfiguration {
System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS, System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS,
properties.getTransport().getHeartbeatIntervalMs()); properties.getTransport().getHeartbeatIntervalMs());
} }
if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_CLIENT_IP))
&& StringUtils.hasText(properties.getTransport().getClientIp())) {
System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP,
properties.getTransport().getClientIp());
}
if (StringUtils.isEmpty(System.getProperty(SentinelConfig.CHARSET)) if (StringUtils.isEmpty(System.getProperty(SentinelConfig.CHARSET))
&& StringUtils.hasText(properties.getMetric().getCharset())) { && StringUtils.hasText(properties.getMetric().getCharset())) {
System.setProperty(SentinelConfig.CHARSET, System.setProperty(SentinelConfig.CHARSET,
@ -110,30 +136,25 @@ public class SentinelAutoConfiguration {
System.setProperty(SentinelConfig.COLD_FACTOR, System.setProperty(SentinelConfig.COLD_FACTOR,
properties.getFlow().getColdFactor()); properties.getFlow().getColdFactor());
} }
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
&& StringUtils.hasText(properties.getLog().getDir())) {
System.setProperty(LogBase.LOG_DIR, properties.getLog().getDir());
}
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_NAME_USE_PID))
&& properties.getLog().isSwitchPid()) {
System.setProperty(LogBase.LOG_NAME_USE_PID,
String.valueOf(properties.getLog().isSwitchPid()));
}
if (StringUtils.hasText(properties.getServlet().getBlockPage())) { if (StringUtils.hasText(properties.getServlet().getBlockPage())) {
WebServletConfig.setBlockPage(properties.getServlet().getBlockPage()); WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
} }
if (urlBlockHandler != null) { if (urlBlockHandler != null) {
WebCallbackManager.setUrlBlockHandler(urlBlockHandler); WebCallbackManager.setUrlBlockHandler(urlBlockHandler);
} }
if (urlCleaner != null) { if (urlCleaner != null) {
WebCallbackManager.setUrlCleaner(urlCleaner); WebCallbackManager.setUrlCleaner(urlCleaner);
} }
if (requestOriginParser != null) {
WebCallbackManager.setRequestOriginParser(requestOriginParser);
}
// earlier initialize // earlier initialize
if (properties.isEager()) { if (properties.isEager()) {
InitExecutor.doInit(); InitExecutor.doInit();
} }
} }
@Bean @Bean
@ -145,34 +166,78 @@ public class SentinelAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
public SentinelBeanPostProcessor sentinelBeanPostProcessor() { public SentinelBeanPostProcessor sentinelBeanPostProcessor(
return new SentinelBeanPostProcessor(); ApplicationContext applicationContext) {
return new SentinelBeanPostProcessor(applicationContext);
} }
@Bean @Bean
public SentinelDataSourceHandler sentinelDataSourceHandler() { public SentinelDataSourceHandler sentinelDataSourceHandler(
return new SentinelDataSourceHandler(); DefaultListableBeanFactory beanFactory) {
return new SentinelDataSourceHandler(beanFactory);
} }
@Bean("sentinel-json-converter") protected static class SentinelConverterConfiguration {
public JsonConverter jsonConverter() {
return new JsonConverter(objectMapper()); private ObjectMapper objectMapper = new ObjectMapper();
@Bean("sentinel-json-flow-converter")
public JsonConverter jsonFlowConverter() {
return new JsonConverter(objectMapper, FlowRule.class);
}
@Bean("sentinel-json-degrade-converter")
public JsonConverter jsonDegradeConverter() {
return new JsonConverter(objectMapper, DegradeRule.class);
}
@Bean("sentinel-json-system-converter")
public JsonConverter jsonSystemConverter() {
return new JsonConverter(objectMapper, SystemRule.class);
}
@Bean("sentinel-json-authority-converter")
public JsonConverter jsonAuthorityConverter() {
return new JsonConverter(objectMapper, AuthorityRule.class);
}
@Bean("sentinel-json-param-flow-converter")
public JsonConverter jsonParamFlowConverter() {
return new JsonConverter(objectMapper, ParamFlowRule.class);
} }
private ObjectMapper objectMapper() {
return new ObjectMapper();
} }
@ConditionalOnClass(XmlMapper.class) @ConditionalOnClass(XmlMapper.class)
protected static class SentinelXmlConfiguration { protected static class SentinelXmlConfiguration {
@Bean("sentinel-xml-converter")
public XmlConverter xmlConverter() { private XmlMapper xmlMapper = new XmlMapper();
return new XmlConverter(xmlMapper());
@Bean("sentinel-xml-flow-converter")
public XmlConverter xmlFlowConverter() {
return new XmlConverter(xmlMapper, FlowRule.class);
} }
private XmlMapper xmlMapper() { @Bean("sentinel-xml-degrade-converter")
return new XmlMapper(); public XmlConverter xmlDegradeConverter() {
return new XmlConverter(xmlMapper, DegradeRule.class);
} }
@Bean("sentinel-xml-system-converter")
public XmlConverter xmlSystemConverter() {
return new XmlConverter(xmlMapper, SystemRule.class);
}
@Bean("sentinel-xml-authority-converter")
public XmlConverter xmlAuthorityConverter() {
return new XmlConverter(xmlMapper, AuthorityRule.class);
}
@Bean("sentinel-xml-param-flow-converter")
public XmlConverter xmlParamFlowConverter() {
return new XmlConverter(xmlMapper, ParamFlowRule.class);
}
} }
} }

View File

@ -16,21 +16,34 @@
package org.springframework.cloud.alibaba.sentinel.custom; package org.springframework.cloud.alibaba.sentinel.custom;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.cloud.alibaba.sentinel.SentinelConstants;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate; import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.type.StandardMethodMetadata; import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.core.type.classreading.MethodMetadataReadingVisitor;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import com.alibaba.csp.sentinel.slots.block.BlockException;
/** /**
* PostProcessor handle @SentinelRestTemplate Annotation, add interceptor for RestTemplate * PostProcessor handle @SentinelRestTemplate Annotation, add interceptor for RestTemplate
* *
@ -40,8 +53,14 @@ import org.springframework.web.client.RestTemplate;
*/ */
public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProcessor { public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
@Autowired private static final Logger logger = LoggerFactory
private ApplicationContext applicationContext; .getLogger(SentinelBeanPostProcessor.class);
private final ApplicationContext applicationContext;
public SentinelBeanPostProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
private ConcurrentHashMap<String, SentinelRestTemplate> cache = new ConcurrentHashMap<>(); private ConcurrentHashMap<String, SentinelRestTemplate> cache = new ConcurrentHashMap<>();
@ -49,21 +68,113 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, String beanName) { Class<?> beanType, String beanName) {
if (checkSentinelProtect(beanDefinition, beanType)) { if (checkSentinelProtect(beanDefinition, beanType)) {
SentinelRestTemplate sentinelRestTemplate = ((StandardMethodMetadata) beanDefinition SentinelRestTemplate sentinelRestTemplate;
if (beanDefinition.getSource() instanceof StandardMethodMetadata) {
sentinelRestTemplate = ((StandardMethodMetadata) beanDefinition
.getSource()).getIntrospectedMethod() .getSource()).getIntrospectedMethod()
.getAnnotation(SentinelRestTemplate.class); .getAnnotation(SentinelRestTemplate.class);
}
else {
sentinelRestTemplate = beanDefinition.getResolvedFactoryMethod()
.getAnnotation(SentinelRestTemplate.class);
}
// check class and method validation
checkSentinelRestTemplate(sentinelRestTemplate, beanName);
cache.put(beanName, sentinelRestTemplate); cache.put(beanName, sentinelRestTemplate);
} }
} }
private void checkSentinelRestTemplate(SentinelRestTemplate sentinelRestTemplate,
String beanName) {
checkBlock4RestTemplate(sentinelRestTemplate.blockHandlerClass(),
sentinelRestTemplate.blockHandler(), beanName,
SentinelConstants.BLOCK_TYPE);
checkBlock4RestTemplate(sentinelRestTemplate.fallbackClass(),
sentinelRestTemplate.fallback(), beanName,
SentinelConstants.FALLBACK_TYPE);
}
private void checkBlock4RestTemplate(Class<?> blockClass, String blockMethod,
String beanName, String type) {
if (blockClass == void.class && StringUtils.isEmpty(blockMethod)) {
return;
}
if (blockClass != void.class && StringUtils.isEmpty(blockMethod)) {
logger.error(
"{} class attribute exists but {} method attribute is not exists in bean[{}]",
type, type, beanName);
throw new IllegalArgumentException(type + " class attribute exists but "
+ type + " method attribute is not exists in bean[" + beanName + "]");
}
else if (blockClass == void.class && !StringUtils.isEmpty(blockMethod)) {
logger.error(
"{} method attribute exists but {} class attribute is not exists in bean[{}]",
type, type, beanName);
throw new IllegalArgumentException(type + " method attribute exists but "
+ type + " class attribute is not exists in bean[" + beanName + "]");
}
Class[] args = new Class[] { HttpRequest.class, byte[].class,
ClientHttpRequestExecution.class, BlockException.class };
List<String> argList = new ArrayList<>();
for (Class argClazz : args) {
argList.add(argClazz.getSimpleName());
}
String argsStr = Arrays.toString(argList.toArray());
Method foundMethod = ClassUtils.getStaticMethod(blockClass, blockMethod, args);
if (foundMethod == null) {
logger.error(
"{} static method can not be found in bean[{}]. The right method signature is {}#{}{}, please check your class name, method name and arguments",
type, beanName, blockClass.getName(), blockMethod, argsStr);
throw new IllegalArgumentException(type
+ " static method can not be found in bean[" + beanName
+ "]. The right method signature is " + blockClass.getName() + "#"
+ blockMethod + argsStr
+ ", please check your class name, method name and arguments");
}
if (!ClientHttpResponse.class.isAssignableFrom(foundMethod.getReturnType())) {
logger.error(
"{} method return value in bean[{}] is not ClientHttpResponse: {}#{}{}",
type, beanName, blockClass.getName(), blockMethod, argsStr);
throw new IllegalArgumentException(type + " method return value in bean["
+ beanName + "] is not ClientHttpResponse: " + blockClass.getName()
+ "#" + blockMethod + argsStr);
}
if (type.equals(SentinelConstants.BLOCK_TYPE)) {
BlockClassRegistry.updateBlockHandlerFor(blockClass, blockMethod,
foundMethod);
}
else {
BlockClassRegistry.updateFallbackFor(blockClass, blockMethod, foundMethod);
}
}
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition, private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
Class<?> beanType) { Class<?> beanType) {
return beanType == RestTemplate.class return beanType == RestTemplate.class
&& beanDefinition.getSource() instanceof StandardMethodMetadata && (checkStandardMethodMetadata(beanDefinition)
|| checkMethodMetadataReadingVisitor(beanDefinition));
}
private boolean checkStandardMethodMetadata(RootBeanDefinition beanDefinition) {
return beanDefinition.getSource() instanceof StandardMethodMetadata
&& ((StandardMethodMetadata) beanDefinition.getSource()) && ((StandardMethodMetadata) beanDefinition.getSource())
.isAnnotated(SentinelRestTemplate.class.getName()); .isAnnotated(SentinelRestTemplate.class.getName());
} }
private boolean checkMethodMetadataReadingVisitor(RootBeanDefinition beanDefinition) {
return beanDefinition.getSource() instanceof MethodMetadataReadingVisitor
&& ((MethodMetadataReadingVisitor) beanDefinition.getSource())
.isAnnotated(SentinelRestTemplate.class.getName());
}
@Override
public Object postProcessBeforeInitialization(Object o, String s)
throws BeansException {
return o;
}
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException { throws BeansException {
@ -84,7 +195,7 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
.getBean(interceptorBeanName.toString(), .getBean(interceptorBeanName.toString(),
SentinelProtectInterceptor.class); SentinelProtectInterceptor.class);
restTemplate.getInterceptors().add(sentinelProtectInterceptor); restTemplate.getInterceptors().add(0, sentinelProtectInterceptor);
} }
return bean; return bean;
} }
@ -103,10 +214,4 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces
interceptorBeanDefinition); interceptorBeanDefinition);
} }
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
} }

View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alibaba.sentinel.custom;
import org.springframework.context.annotation.Configuration;
/**
* @author lengleng
* <p>
* support @EnableCircuitBreaker ,Do nothing
*/
@Configuration
public class SentinelCircuitBreakerConfiguration {
}

View File

@ -17,47 +17,29 @@
package org.springframework.cloud.alibaba.sentinel.custom; package org.springframework.cloud.alibaba.sentinel.custom;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cloud.alibaba.sentinel.SentinelConstants;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties; import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants;
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties; import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration; import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import org.springframework.cloud.alibaba.sentinel.datasource.config.NacosDataSourceProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter; import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter; import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
import org.springframework.context.event.EventListener;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.AbstractDataSource; import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource; import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.property.SentinelProperty;
import com.alibaba.csp.sentinel.slots.block.AbstractRule; import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
/** /**
* Sentinel {@link ReadableDataSource} Handler Handle the configurations of * Sentinel {@link ReadableDataSource} Handler Handle the configurations of
@ -68,59 +50,32 @@ import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
* @see JsonConverter * @see JsonConverter
* @see XmlConverter * @see XmlConverter
*/ */
public class SentinelDataSourceHandler { public class SentinelDataSourceHandler implements SmartInitializingSingleton {
private static final Logger logger = LoggerFactory private static final Logger logger = LoggerFactory
.getLogger(SentinelDataSourceHandler.class); .getLogger(SentinelDataSourceHandler.class);
private List<String> dataTypeList = Arrays.asList("json", "xml"); private List<String> dataTypeList = Arrays.asList("json", "xml");
private List<Class<? extends AbstractRule>> rulesList = Arrays.asList(FlowRule.class, private final String DATA_TYPE_FIELD = "dataType";
DegradeRule.class, SystemRule.class, AuthorityRule.class, private final String CUSTOM_DATA_TYPE = "custom";
ParamFlowRule.class); private final String CONVERTER_CLASS_FIELD = "converterClass";
private List<String> dataSourceBeanNameList = Collections private final DefaultListableBeanFactory beanFactory;
.synchronizedList(new ArrayList<String>());
private final String DATATYPE_FIELD = "dataType"; public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory) {
private final String CUSTOM_DATATYPE = "custom"; this.beanFactory = beanFactory;
private final String CONVERTERCLASS_FIELD = "converterClass"; }
@Autowired @Autowired
private SentinelProperties sentinelProperties; private SentinelProperties sentinelProperties;
@EventListener(classes = ApplicationReadyEvent.class) @Override
public void buildDataSource(ApplicationReadyEvent event) throws Exception { public void afterSingletonsInstantiated() {
for (String dataSourceName : sentinelProperties.getDatasource().keySet()) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) event DataSourcePropertiesConfiguration dataSourceProperties = sentinelProperties
.getApplicationContext().getAutowireCapableBeanFactory(); .getDatasource().get(dataSourceName);
try {
// commercialization
if (!StringUtils.isEmpty(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) {
Map<String, DataSourcePropertiesConfiguration> newDataSourceMap = new TreeMap<>(
String.CASE_INSENSITIVE_ORDER);
for (Map.Entry<String, DataSourcePropertiesConfiguration> entry : sentinelProperties
.getDatasource().entrySet()) {
if (entry.getValue().getValidDataSourceProperties()
.getClass() != NacosDataSourceProperties.class) {
newDataSourceMap.put(entry.getKey(), entry.getValue());
}
}
newDataSourceMap.put(SentinelConstants.FLOW_DATASOURCE_NAME,
new DataSourcePropertiesConfiguration(
NacosDataSourceProperties.buildFlowByEDAS()));
newDataSourceMap.put(SentinelConstants.DEGRADE_DATASOURCE_NAME,
new DataSourcePropertiesConfiguration(
NacosDataSourceProperties.buildDegradeByEDAS()));
sentinelProperties.setDatasource(newDataSourceMap);
}
for (Map.Entry<String, DataSourcePropertiesConfiguration> entry : sentinelProperties
.getDatasource().entrySet()) {
String dataSourceName = entry.getKey();
DataSourcePropertiesConfiguration dataSourceProperties = entry.getValue();
List<String> validFields = dataSourceProperties.getValidField(); List<String> validFields = dataSourceProperties.getValidField();
if (validFields.size() != 1) { if (validFields.size() != 1) {
logger.error("[Sentinel Starter] DataSource " + dataSourceName logger.error("[Sentinel Starter] DataSource " + dataSourceName
@ -128,53 +83,20 @@ public class SentinelDataSourceHandler {
+ dataSourceProperties.getValidField()); + dataSourceProperties.getValidField());
return; return;
} }
AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
.getValidDataSourceProperties(); .getValidDataSourceProperties();
abstractDataSourceProperties.preCheck(); abstractDataSourceProperties.preCheck(dataSourceName);
registerBean(beanFactory, abstractDataSourceProperties, registerBean(abstractDataSourceProperties, dataSourceName + "-sentinel-"
dataSourceName + "-sentinel-" + validFields.get(0) + "-datasource"); + validFields.get(0) + "-datasource");
}
for (String beanName : dataSourceBeanNameList) {
ReadableDataSource dataSource = beanFactory.getBean(beanName,
ReadableDataSource.class);
Object ruleConfig;
try {
logger.info("[Sentinel Starter] DataSource " + beanName
+ " start to loadConfig");
ruleConfig = dataSource.loadConfig();
} }
catch (Exception e) { catch (Exception e) {
logger.error("[Sentinel Starter] DataSource " + beanName logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ " loadConfig error: " + e.getMessage(), e); + " build error: " + e.getMessage(), e);
return;
}
SentinelProperty sentinelProperty = dataSource.getProperty();
Class ruleType = getAndCheckRuleType(ruleConfig, beanName);
if (ruleType != null) {
if (ruleType == FlowRule.class) {
FlowRuleManager.register2Property(sentinelProperty);
}
else if (ruleType == DegradeRule.class) {
DegradeRuleManager.register2Property(sentinelProperty);
}
else if (ruleType == SystemRule.class) {
SystemRuleManager.register2Property(sentinelProperty);
}
else if (ruleType == AuthorityRule.class) {
AuthorityRuleManager.register2Property(sentinelProperty);
}
else {
ParamFlowRuleManager.register2Property(sentinelProperty);
}
} }
} }
} }
private void registerBean(DefaultListableBeanFactory beanFactory, private void registerBean(final AbstractDataSourceProperties dataSourceProperties,
final AbstractDataSourceProperties dataSourceProperties,
String dataSourceName) { String dataSourceName) {
Map<String, Object> propertyMap = new HashMap<>(); Map<String, Object> propertyMap = new HashMap<>();
@ -194,8 +116,9 @@ public class SentinelDataSourceHandler {
e); e);
} }
} }
propertyMap.put(CONVERTERCLASS_FIELD, dataSourceProperties.getConverterClass());
propertyMap.put(DATATYPE_FIELD, dataSourceProperties.getDataType()); propertyMap.put(CONVERTER_CLASS_FIELD, dataSourceProperties.getConverterClass());
propertyMap.put(DATA_TYPE_FIELD, dataSourceProperties.getDataType());
BeanDefinitionBuilder builder = BeanDefinitionBuilder BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(dataSourceProperties.getFactoryBeanName()); .genericBeanDefinition(dataSourceProperties.getFactoryBeanName());
@ -205,16 +128,17 @@ public class SentinelDataSourceHandler {
Object propertyValue = entry.getValue(); Object propertyValue = entry.getValue();
Field field = ReflectionUtils.findField(dataSourceProperties.getClass(), Field field = ReflectionUtils.findField(dataSourceProperties.getClass(),
propertyName); propertyName);
if (field != null) { if (null == field) {
if (DATATYPE_FIELD.equals(propertyName)) { continue;
String dataType = StringUtils }
.trimAllWhitespace(propertyValue.toString()); if (DATA_TYPE_FIELD.equals(propertyName)) {
if (CUSTOM_DATATYPE.equals(dataType)) { String dataType = StringUtils.trimAllWhitespace(propertyValue.toString());
if (CUSTOM_DATA_TYPE.equals(dataType)) {
try { try {
if (StringUtils if (StringUtils
.isEmpty(dataSourceProperties.getConverterClass())) { .isEmpty(dataSourceProperties.getConverterClass())) {
throw new RuntimeException( throw new RuntimeException("[Sentinel Starter] DataSource "
"[Sentinel Starter] DataSource " + dataSourceName + dataSourceName
+ "dataType is custom, please set converter-class " + "dataType is custom, please set converter-class "
+ "property"); + "property");
} }
@ -222,16 +146,15 @@ public class SentinelDataSourceHandler {
// configuration and register // configuration and register
String customConvertBeanName = "sentinel-" String customConvertBeanName = "sentinel-"
+ dataSourceProperties.getConverterClass(); + dataSourceProperties.getConverterClass();
if (!beanFactory.containsBean(customConvertBeanName)) { if (!this.beanFactory.containsBean(customConvertBeanName)) {
beanFactory.registerBeanDefinition(customConvertBeanName, this.beanFactory.registerBeanDefinition(customConvertBeanName,
BeanDefinitionBuilder BeanDefinitionBuilder
.genericBeanDefinition( .genericBeanDefinition(
Class.forName(dataSourceProperties Class.forName(dataSourceProperties
.getConverterClass())) .getConverterClass()))
.getBeanDefinition()); .getBeanDefinition());
} }
builder.addPropertyReference("converter", builder.addPropertyReference("converter", customConvertBeanName);
customConvertBeanName);
} }
catch (ClassNotFoundException e) { catch (ClassNotFoundException e) {
logger.error("[Sentinel Starter] DataSource " + dataSourceName logger.error("[Sentinel Starter] DataSource " + dataSourceName
@ -239,19 +162,16 @@ public class SentinelDataSourceHandler {
+ dataSourceProperties.getClass().getSimpleName() + dataSourceProperties.getClass().getSimpleName()
+ " error, class name: " + " error, class name: "
+ dataSourceProperties.getConverterClass()); + dataSourceProperties.getConverterClass());
throw new RuntimeException( throw new RuntimeException("[Sentinel Starter] DataSource "
"[Sentinel Starter] DataSource " + dataSourceName + dataSourceName + " handle "
+ " handle " + dataSourceProperties.getClass().getSimpleName()
+ dataSourceProperties.getClass()
.getSimpleName()
+ " error, class name: " + " error, class name: "
+ dataSourceProperties.getConverterClass(), + dataSourceProperties.getConverterClass(), e);
e);
} }
} }
else { else {
if (!dataTypeList.contains(StringUtils if (!dataTypeList.contains(
.trimAllWhitespace(propertyValue.toString()))) { StringUtils.trimAllWhitespace(propertyValue.toString()))) {
throw new RuntimeException("[Sentinel Starter] DataSource " throw new RuntimeException("[Sentinel Starter] DataSource "
+ dataSourceName + " dataType: " + propertyValue + dataSourceName + " dataType: " + propertyValue
+ " is not support now. please using these types: " + " is not support now. please using these types: "
@ -259,12 +179,14 @@ public class SentinelDataSourceHandler {
} }
// converter type now support xml or json. // converter type now support xml or json.
// The bean name of these converters wrapped by // The bean name of these converters wrapped by
// 'sentinel-{converterType}-converter' // 'sentinel-{converterType}-{ruleType}-converter'
builder.addPropertyReference("converter", builder.addPropertyReference("converter",
"sentinel-" + propertyValue.toString() + "-converter"); "sentinel-" + propertyValue.toString() + "-"
+ dataSourceProperties.getRuleType().getName()
+ "-converter");
} }
} }
else if (CONVERTERCLASS_FIELD.equals(propertyName)) { else if (CONVERTER_CLASS_FIELD.equals(propertyName)) {
continue; continue;
} }
else { else {
@ -274,97 +196,68 @@ public class SentinelDataSourceHandler {
} }
} }
} }
}
beanFactory.registerBeanDefinition(dataSourceName, builder.getBeanDefinition()); this.beanFactory.registerBeanDefinition(dataSourceName,
builder.getBeanDefinition());
// init in Spring // init in Spring
AbstractDataSource newDataSource = (AbstractDataSource) beanFactory AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory
.getBean(dataSourceName); .getBean(dataSourceName);
// commercialization
if (!StringUtils.isEmpty(System.getProperties() logAndCheckRuleType(newDataSource, dataSourceName,
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) { dataSourceProperties.getRuleType().getClazz());
if (dataSourceName.contains(SentinelConstants.FLOW_DATASOURCE_NAME)) {
FlowRuleManager.register2Property(newDataSource.getProperty()); // register property in RuleManager
} dataSourceProperties.postRegister(newDataSource);
else if (dataSourceName.contains(SentinelConstants.DEGRADE_DATASOURCE_NAME)) {
DegradeRuleManager.register2Property(newDataSource.getProperty());
}
}
dataSourceBeanNameList.add(dataSourceName);
} }
private Class getAndCheckRuleType(Object ruleConfig, String dataSourceName) { private void logAndCheckRuleType(AbstractDataSource dataSource, String dataSourceName,
if (rulesList.contains(ruleConfig.getClass())) { Class<? extends AbstractRule> ruleClass) {
logger.info("[Sentinel Starter] DataSource {} load {} {}", dataSourceName, 1, Object ruleConfig;
ruleConfig.getClass().getSimpleName()); try {
return ruleConfig.getClass(); ruleConfig = dataSource.loadConfig();
} }
else if (ruleConfig instanceof List) { catch (Exception e) {
logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ " loadConfig error: " + e.getMessage(), e);
return;
}
if (ruleConfig instanceof List) {
List convertedRuleList = (List) ruleConfig; List convertedRuleList = (List) ruleConfig;
if (CollectionUtils.isEmpty(convertedRuleList)) { if (CollectionUtils.isEmpty(convertedRuleList)) {
logger.warn("[Sentinel Starter] DataSource {} rule list is empty.", logger.warn("[Sentinel Starter] DataSource {} rule list is empty.",
dataSourceName); dataSourceName);
return null; return;
} }
int matchCount = 0;
if (checkRuleTypeValid(convertedRuleList)) {
if (checkAllRuleTypeSame(convertedRuleList)) {
logger.info("[Sentinel Starter] DataSource {} load {} {}",
dataSourceName, convertedRuleList.size(),
convertedRuleList.get(0).getClass().getSimpleName());
return convertedRuleList.get(0).getClass();
}
else {
logger.warn(
"[Sentinel Starter] DataSource {} all rules are not same rule type and it will not be used. "
+ "Rule List: {}",
dataSourceName, convertedRuleList.toString());
}
}
else {
List<Class> classList = new ArrayList<>();
for (Object rule : convertedRuleList) { for (Object rule : convertedRuleList) {
classList.add(rule.getClass()); if (rule.getClass() == ruleClass) {
matchCount++;
} }
logger.error("[Sentinel Starter] DataSource " + dataSourceName }
+ " rule class is invalid. Class List: " + classList); if (matchCount == 0) {
throw new RuntimeException( logger.error("[Sentinel Starter] DataSource {} none rules are {} type.",
"[Sentinel Starter] DataSource " + dataSourceName dataSourceName, ruleClass.getSimpleName());
+ " rule class is invalid. Class List: " + classList); throw new IllegalArgumentException("[Sentinel Starter] DataSource "
+ dataSourceName + " none rules are " + ruleClass.getSimpleName()
+ " type.");
}
else if (matchCount != convertedRuleList.size()) {
logger.warn("[Sentinel Starter] DataSource {} all rules are not {} type.",
dataSourceName, ruleClass.getSimpleName());
}
else {
logger.info("[Sentinel Starter] DataSource {} load {} {}", dataSourceName,
convertedRuleList.size(), ruleClass.getSimpleName());
} }
} }
else { else {
logger.error("[Sentinel Starter] DataSource " + dataSourceName logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ " rule class is invalid. Class: " + ruleConfig.getClass()); + " rule class is not List<" + ruleClass.getSimpleName()
throw new RuntimeException("[Sentinel Starter] DataSource " + dataSourceName + ">. Class: " + ruleConfig.getClass());
+ " rule class is invalid. Class: " + ruleConfig.getClass()); throw new IllegalArgumentException("[Sentinel Starter] DataSource "
+ dataSourceName + " rule class is not List<"
+ ruleClass.getSimpleName() + ">. Class: " + ruleConfig.getClass());
} }
return null;
}
private boolean checkRuleTypeValid(List convertedRuleList) {
int matchCount = 0;
for (Object rule : convertedRuleList) {
if (rulesList.contains(rule.getClass())) {
matchCount++;
}
}
return matchCount == convertedRuleList.size();
}
private boolean checkAllRuleTypeSame(List convertedRuleList) {
int matchCount = 0;
for (Object rule : convertedRuleList) {
if (rulesList.contains(rule.getClass())
&& rule.getClass() == convertedRuleList.get(0).getClass()) {
matchCount++;
}
}
return matchCount == convertedRuleList.size();
}
public List<String> getDataSourceBeanNameList() {
return dataSourceBeanNameList;
} }
} }

View File

@ -17,9 +17,9 @@
package org.springframework.cloud.alibaba.sentinel.custom; package org.springframework.cloud.alibaba.sentinel.custom;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import java.util.Arrays;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -29,7 +29,6 @@ import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.ClassUtils;
import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.SphU;
@ -37,19 +36,18 @@ import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.util.StringUtil;
/** /**
* Interceptor using by SentinelRestTemplate * Interceptor using by SentinelRestTemplate
* *
* @author fangjian * @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/ */
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor { public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory private static final Logger logger = LoggerFactory
.getLogger(SentinelProtectInterceptor.class); .getLogger(SentinelProtectInterceptor.class);
private SentinelRestTemplate sentinelRestTemplate; private final SentinelRestTemplate sentinelRestTemplate;
public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate) { public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate) {
this.sentinelRestTemplate = sentinelRestTemplate; this.sentinelRestTemplate = sentinelRestTemplate;
@ -82,18 +80,7 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
else { else {
try { return handleBlockException(request, body, execution, (BlockException) e);
return handleBlockException(request, body, execution,
(BlockException) e);
}
catch (Exception ex) {
if (ex instanceof IllegalStateException) {
throw (IllegalStateException) ex;
}
throw new IllegalStateException(
"sentinel handle BlockException error: " + ex.getMessage(),
ex);
}
} }
} }
finally { finally {
@ -109,84 +96,49 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
} }
private ClientHttpResponse handleBlockException(HttpRequest request, byte[] body, private ClientHttpResponse handleBlockException(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution, BlockException ex) throws Exception { ClientHttpRequestExecution execution, BlockException ex) {
Object[] args = new Object[] { request, body, execution, ex }; Object[] args = new Object[] { request, body, execution, ex };
// handle degrade // handle degrade
if (isDegradeFailure(ex)) { if (isDegradeFailure(ex)) {
Method method = extractFallbackMethod(sentinelRestTemplate.fallback(), Method fallbackMethod = extractFallbackMethod(sentinelRestTemplate.fallback(),
sentinelRestTemplate.fallbackClass()); sentinelRestTemplate.fallbackClass());
if (method != null) { if (fallbackMethod != null) {
return (ClientHttpResponse) method.invoke(null, args); return methodInvoke(fallbackMethod, args);
} }
else { else {
return new SentinelClientHttpResponse(); return new SentinelClientHttpResponse();
} }
} }
// handle block // handle flow
Method blockHandler = extractBlockHandlerMethod( Method blockHandler = extractBlockHandlerMethod(
sentinelRestTemplate.blockHandler(), sentinelRestTemplate.blockHandler(),
sentinelRestTemplate.blockHandlerClass()); sentinelRestTemplate.blockHandlerClass());
if (blockHandler != null) { if (blockHandler != null) {
return (ClientHttpResponse) blockHandler.invoke(null, args); return methodInvoke(blockHandler, args);
} }
else { else {
return new SentinelClientHttpResponse(); return new SentinelClientHttpResponse();
} }
} }
private ClientHttpResponse methodInvoke(Method method, Object... args) {
try {
return (ClientHttpResponse) method.invoke(null, args);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private Method extractFallbackMethod(String fallback, Class<?> fallbackClass) { private Method extractFallbackMethod(String fallback, Class<?> fallbackClass) {
if (StringUtil.isBlank(fallback) || fallbackClass == void.class) { return BlockClassRegistry.lookupFallback(fallbackClass, fallback);
return null;
}
Method cachedMethod = BlockClassRegistry.lookupFallback(fallbackClass, fallback);
Class[] args = new Class[] { HttpRequest.class, byte[].class,
ClientHttpRequestExecution.class, BlockException.class };
if (cachedMethod == null) {
cachedMethod = ClassUtils.getStaticMethod(fallbackClass, fallback, args);
if (cachedMethod != null) {
if (!ClientHttpResponse.class
.isAssignableFrom(cachedMethod.getReturnType())) {
throw new IllegalStateException(String.format(
"the return type of method [%s] in class [%s] is not ClientHttpResponse in degrade",
cachedMethod.getName(), fallbackClass.getCanonicalName()));
}
BlockClassRegistry.updateFallbackFor(fallbackClass, fallback,
cachedMethod);
}
else {
throw new IllegalStateException(String.format(
"Cannot find method [%s] in class [%s] with parameters %s in degrade",
fallback, fallbackClass.getCanonicalName(), Arrays.asList(args)));
}
}
return cachedMethod;
} }
private Method extractBlockHandlerMethod(String block, Class<?> blockClass) { private Method extractBlockHandlerMethod(String block, Class<?> blockClass) {
if (StringUtil.isBlank(block) || blockClass == void.class) { return BlockClassRegistry.lookupBlockHandler(blockClass, block);
return null;
}
Method cachedMethod = BlockClassRegistry.lookupBlockHandler(blockClass, block);
Class[] args = new Class[] { HttpRequest.class, byte[].class,
ClientHttpRequestExecution.class, BlockException.class };
if (cachedMethod == null) {
cachedMethod = ClassUtils.getStaticMethod(blockClass, block, args);
if (cachedMethod != null) {
if (!ClientHttpResponse.class
.isAssignableFrom(cachedMethod.getReturnType())) {
throw new IllegalStateException(String.format(
"the return type of method [%s] in class [%s] is not ClientHttpResponse in flow control",
cachedMethod.getName(), blockClass.getCanonicalName()));
}
BlockClassRegistry.updateBlockHandlerFor(blockClass, block, cachedMethod);
}
else {
throw new IllegalStateException(String.format(
"Cannot find method [%s] in class [%s] with parameters %s in flow control",
block, blockClass.getCanonicalName(), Arrays.asList(args)));
}
}
return cachedMethod;
} }
private boolean isDegradeFailure(BlockException ex) { private boolean isDegradeFailure(BlockException ex) {

View File

@ -17,24 +17,20 @@
package org.springframework.cloud.alibaba.sentinel.endpoint; package org.springframework.cloud.alibaba.sentinel.endpoint;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint; import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties; import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelDataSourceHandler;
import org.springframework.context.ApplicationContext;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource; import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager; import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
/** /**
* Endpoint for Sentinel, contains ans properties and rules * Endpoint for Sentinel, contains ans properties and rules
@ -42,45 +38,39 @@ import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
*/ */
public class SentinelEndpoint extends AbstractEndpoint<Map<String, Object>> { public class SentinelEndpoint extends AbstractEndpoint<Map<String, Object>> {
@Autowired private final SentinelProperties sentinelProperties;
private SentinelProperties sentinelProperties;
@Autowired public SentinelEndpoint(SentinelProperties sentinelProperties) {
private SentinelDataSourceHandler dataSourceHandler;
@Autowired
private ApplicationContext applicationContext;
public SentinelEndpoint() {
super("sentinel"); super("sentinel");
this.sentinelProperties = sentinelProperties;
} }
@Override @Override
public Map<String, Object> invoke() { public Map<String, Object> invoke() {
Map<String, Object> result = new HashMap<>(); final Map<String, Object> result = new HashMap<>();
if (sentinelProperties.isEnabled()) {
List<FlowRule> flowRules = FlowRuleManager.getRules(); result.put("logDir", LogBase.getLogBaseDir());
List<DegradeRule> degradeRules = DegradeRuleManager.getRules(); result.put("logUsePid", LogBase.isLogNameUsePid());
List<SystemRule> systemRules = SystemRuleManager.getRules(); result.put("blockPage", WebServletConfig.getBlockPage());
List<ParamFlowRule> paramFlowRules = ParamFlowRuleManager.getRules(); result.put("metricsFileSize", SentinelConfig.singleMetricFileSize());
result.put("properties", sentinelProperties); result.put("metricsFileCharset", SentinelConfig.charset());
result.put("FlowRules", flowRules); result.put("totalMetricsFileCount", SentinelConfig.totalMetricFileCount());
result.put("DegradeRules", degradeRules); result.put("consoleServer", TransportConfig.getConsoleServer());
result.put("SystemRules", systemRules); result.put("clientIp", TransportConfig.getHeartbeatClientIp());
result.put("ParamFlowRule", paramFlowRules); result.put("heartbeatIntervalMs", TransportConfig.getHeartbeatIntervalMs());
result.put("datasources", new HashMap<String, Object>()); result.put("clientPort", TransportConfig.getPort());
result.put("coldFactor", sentinelProperties.getFlow().getColdFactor());
result.put("filter", sentinelProperties.getFilter());
result.put("datasource", sentinelProperties.getDatasource());
for (String dataSourceBeanName : dataSourceHandler.getDataSourceBeanNameList()) { final Map<String, Object> rules = new HashMap<>();
ReadableDataSource dataSource = applicationContext.getBean(dataSourceBeanName, result.put("rules", rules);
ReadableDataSource.class); rules.put("flowRules", FlowRuleManager.getRules());
try { rules.put("degradeRules", DegradeRuleManager.getRules());
((HashMap) result.get("datasources")).put(dataSourceBeanName, rules.put("systemRules", SystemRuleManager.getRules());
dataSource.loadConfig()); rules.put("authorityRule", AuthorityRuleManager.getRules());
} rules.put("paramFlowRule", ParamFlowRuleManager.getRules());
catch (Exception e) {
((HashMap) result.get("datasources")).put(dataSourceBeanName,
"load error: " + e.getMessage());
}
} }
return result; return result;
} }

View File

@ -34,8 +34,8 @@ public class SentinelEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint("sentinel") @ConditionalOnEnabledEndpoint("sentinel")
public SentinelEndpoint sentinelEndPoint() { public SentinelEndpoint sentinelEndPoint(SentinelProperties sentinelProperties) {
return new SentinelEndpoint(); return new SentinelEndpoint(sentinelProperties);
} }
} }

View File

@ -16,13 +16,6 @@
package org.springframework.cloud.alibaba.sentinel.rest; package org.springframework.cloud.alibaba.sentinel.rest;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.AbstractClientHttpResponse;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -31,6 +24,13 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.AbstractClientHttpResponse;
/** /**
* Using by {@link SentinelRestTemplate} and {@link SentinelProtectInterceptor} * Using by {@link SentinelRestTemplate} and {@link SentinelProtectInterceptor}
* *
@ -41,7 +41,6 @@ public class SentinelClientHttpResponse extends AbstractClientHttpResponse {
private String blockResponse = "RestTemplate request block by sentinel"; private String blockResponse = "RestTemplate request block by sentinel";
public SentinelClientHttpResponse() { public SentinelClientHttpResponse() {
} }
public SentinelClientHttpResponse(String blockResponse) { public SentinelClientHttpResponse(String blockResponse) {

View File

@ -18,6 +18,11 @@
"defaultValue": "8719", "defaultValue": "8719",
"description": "sentinel api port." "description": "sentinel api port."
}, },
{
"name": "spring.cloud.sentinel.transport.clientIp",
"type": "java.lang.String",
"description": "sentinel client ip connect to dashboard."
},
{ {
"name": "spring.cloud.sentinel.transport.dashboard", "name": "spring.cloud.sentinel.transport.dashboard",
"type": "java.lang.String", "type": "java.lang.String",

View File

@ -3,3 +3,6 @@ org.springframework.cloud.alibaba.sentinel.SentinelWebAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpointAutoConfiguration,\ org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration,\ org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration,\
org.springframework.cloud.alibaba.sentinel.feign.SentinelFeignAutoConfiguration org.springframework.cloud.alibaba.sentinel.feign.SentinelFeignAutoConfiguration
org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
org.springframework.cloud.alibaba.sentinel.custom.SentinelCircuitBreakerConfiguration

View File

@ -27,8 +27,12 @@ import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplat
import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration; import org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor; import org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor;
import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor; import org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor;
import org.springframework.cloud.alibaba.sentinel.rest.SentinelClientHttpResponse;
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.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
@ -109,8 +113,9 @@ public class SentinelAutoConfigurationTests {
} }
static class ExceptionUtil { static class ExceptionUtil {
public static void handleException(BlockException ex) { public static ClientHttpResponse handleException(HttpRequest request, byte[] body,
System.out.println("Oops: " + ex.getClass().getCanonicalName()); ClientHttpRequestExecution execution, BlockException ex) {
return new SentinelClientHttpResponse("custom block info");
} }
} }

View File

@ -1,64 +0,0 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alicloud.context.sentinel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.cloud.alicloud.context.Constants;
import org.springframework.cloud.alicloud.context.listener.AbstractOnceApplicationListener;
import com.alibaba.cloud.context.edas.EdasChangeOrderConfiguration;
import com.alibaba.cloud.context.edas.EdasChangeOrderConfigurationFactory;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public class SentinelAliCloudListener
extends AbstractOnceApplicationListener<ApplicationEnvironmentPreparedEvent> {
private static final Logger logger = LoggerFactory
.getLogger(SentinelAliCloudListener.class);
@Override
protected void handleEvent(ApplicationEnvironmentPreparedEvent event) {
EdasChangeOrderConfiguration edasChangeOrderConfiguration = EdasChangeOrderConfigurationFactory
.getEdasChangeOrderConfiguration();
logger.info("Sentinel Nacos datasource will"
+ (edasChangeOrderConfiguration.isEdasManaged() ? " be " : " not be ")
+ "changed by edas change order.");
if (!edasChangeOrderConfiguration.isEdasManaged()) {
return;
}
System.getProperties().setProperty(Constants.Sentinel.NACOS_DATASOURCE_ENDPOINT,
edasChangeOrderConfiguration.getAddressServerDomain());
System.getProperties().setProperty(Constants.Sentinel.NACOS_DATASOURCE_NAMESPACE,
edasChangeOrderConfiguration.getTenantId());
System.getProperties().setProperty(Constants.Sentinel.NACOS_DATASOURCE_AK,
edasChangeOrderConfiguration.getDauthAccessKey());
System.getProperties().setProperty(Constants.Sentinel.NACOS_DATASOURCE_SK,
edasChangeOrderConfiguration.getDauthSecretKey());
System.getProperties().setProperty(Constants.Sentinel.PROJECT_NAME,
edasChangeOrderConfiguration.getProjectName());
}
@Override
protected String conditionalOnClass() {
return "com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource";
}
}

View File

@ -11,5 +11,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.context.ApplicationListener=\ org.springframework.context.ApplicationListener=\
org.springframework.cloud.alicloud.context.ans.AnsContextApplicationListener,\ org.springframework.cloud.alicloud.context.ans.AnsContextApplicationListener,\
org.springframework.cloud.alicloud.context.nacos.NacosConfigParameterInitListener,\ org.springframework.cloud.alicloud.context.nacos.NacosConfigParameterInitListener,\
org.springframework.cloud.alicloud.context.nacos.NacosDiscoveryParameterInitListener,\ org.springframework.cloud.alicloud.context.nacos.NacosDiscoveryParameterInitListener
org.springframework.cloud.alicloud.context.sentinel.SentinelAliCloudListener

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 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
*
* 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 org.springframework.cloud.alicloud.context.sentinel;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.BeforeClass;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.springframework.cloud.alicloud.context.BaseAliCloudSpringApplication;
import org.springframework.cloud.alicloud.context.Constants;
import org.springframework.cloud.alicloud.utils.ChangeOrderUtils;
import com.alibaba.cloud.context.edas.EdasChangeOrderConfigurationFactory;
/**
* @author xiaolongzuo
*/
@PrepareForTest({ EdasChangeOrderConfigurationFactory.class,
SentinelAliCloudListener.class })
public class SentinelAliCloudListenerTests extends BaseAliCloudSpringApplication {
@BeforeClass
public static void setUp() {
ChangeOrderUtils.mockChangeOrder();
}
@Test
public void testNacosParameterInitListener() {
assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_ENDPOINT))
.isEqualTo("testDomain");
assertThat(System.getProperty(Constants.Sentinel.PROJECT_NAME))
.isEqualTo("testProjectName");
assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_NAMESPACE))
.isEqualTo("testTenantId");
assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_AK))
.isEqualTo("testAK");
assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_SK))
.isEqualTo("testSK");
}
}