init
This commit is contained in:
		@@ -0,0 +1,41 @@
 | 
			
		||||
# Sentinel DataSource Spring Cloud Config
 | 
			
		||||
 | 
			
		||||
Sentinel DataSource Spring Cloud Config provides integration with Spring Cloud Config
 | 
			
		||||
so that Spring Cloud Config can be the dynamic rule data source of Sentinel.
 | 
			
		||||
 | 
			
		||||
To use Sentinel DataSource Spring Cloud Config, you should add the following dependency:
 | 
			
		||||
 | 
			
		||||
```xml
 | 
			
		||||
<dependency>
 | 
			
		||||
    <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
    <artifactId>sentinel-datasource-spring-cloud-config</artifactId>
 | 
			
		||||
    <version>x.y.z</version>
 | 
			
		||||
</dependency>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then you can create an `SpringCloudConfigDataSource` and register to rule managers.
 | 
			
		||||
For instance:
 | 
			
		||||
 | 
			
		||||
```Java
 | 
			
		||||
ReadableDataSource<String, List<FlowRule>> flowRuleDs = new SpringCloudConfigDataSource<>(ruleKey, s -> JSON.parseArray(s, FlowRule.class));
 | 
			
		||||
FlowRuleManager.register2Property(flowRuleDs.getProperty());
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To notify the client that the remote config has changed, we could bind a git webhook callback with the
 | 
			
		||||
`com.alibaba.csp.sentinel.datasource.spring.cloud.config.SentinelRuleLocator.refresh` API.
 | 
			
		||||
We may refer to the the sample `com.alibaba.csp.sentinel.datasource.spring.cloud.config.test.SpringCouldDataSourceTest#refresh` in test cases.
 | 
			
		||||
 | 
			
		||||
We offer test cases and demo in the package: `com.alibaba.csp.sentinel.datasource.spring.cloud.config.test`.
 | 
			
		||||
When you are running test cases, please follow the steps:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
// First, start the Spring Cloud config server
 | 
			
		||||
com.alibaba.csp.sentinel.datasource.spring.cloud.config.server.ConfigServer
 | 
			
		||||
 | 
			
		||||
// Second, start the Spring Cloud config client
 | 
			
		||||
com.alibaba.csp.sentinel.datasource.spring.cloud.config.client.ConfigClient
 | 
			
		||||
 | 
			
		||||
// Third, run the test cases and demo
 | 
			
		||||
com.alibaba.csp.sentinel.datasource.spring.cloud.config.test.SentinelRuleLocatorTests
 | 
			
		||||
com.alibaba.csp.sentinel.datasource.spring.cloud.config.test.SpringCouldDataSourceTest
 | 
			
		||||
```
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
			
		||||
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
    <parent>
 | 
			
		||||
        <artifactId>sentinel-extension</artifactId>
 | 
			
		||||
        <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
        <version>1.8.3</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
 | 
			
		||||
    <artifactId>sentinel-datasource-spring-cloud-config</artifactId>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
        <spring.cloud.version>2.0.0.RELEASE</spring.cloud.version>
 | 
			
		||||
    </properties>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
            <artifactId>sentinel-datasource-extension</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.cloud</groupId>
 | 
			
		||||
            <artifactId>spring-cloud-starter-config</artifactId>
 | 
			
		||||
            <version>${spring.cloud.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.retry</groupId>
 | 
			
		||||
            <artifactId>spring-retry</artifactId>
 | 
			
		||||
            <version>1.2.4.RELEASE</version>
 | 
			
		||||
            <exclusions>
 | 
			
		||||
                <exclusion>
 | 
			
		||||
                    <groupId>org.springframework</groupId>
 | 
			
		||||
                    <artifactId>spring-core</artifactId>
 | 
			
		||||
                </exclusion>
 | 
			
		||||
            </exclusions>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.boot</groupId>
 | 
			
		||||
            <artifactId>spring-boot-starter-test</artifactId>
 | 
			
		||||
            <version>${spring.cloud.version}</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.cloud</groupId>
 | 
			
		||||
            <artifactId>spring-cloud-config-server</artifactId>
 | 
			
		||||
            <version>${spring.cloud.version}</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.boot</groupId>
 | 
			
		||||
            <artifactId>spring-boot-starter-web</artifactId>
 | 
			
		||||
            <version>${spring.cloud.version}</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework</groupId>
 | 
			
		||||
            <artifactId>spring-expression</artifactId>
 | 
			
		||||
            <version>5.1.8.RELEASE</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba</groupId>
 | 
			
		||||
            <artifactId>fastjson</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>junit</groupId>
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</project>
 | 
			
		||||
@@ -0,0 +1,301 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2019 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.log.RecordLog;
 | 
			
		||||
 | 
			
		||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
 | 
			
		||||
import org.springframework.cloud.config.client.ConfigClientProperties;
 | 
			
		||||
import org.springframework.cloud.config.client.ConfigClientStateHolder;
 | 
			
		||||
import org.springframework.cloud.config.environment.Environment;
 | 
			
		||||
import org.springframework.cloud.config.environment.PropertySource;
 | 
			
		||||
import org.springframework.core.annotation.Order;
 | 
			
		||||
import org.springframework.core.env.CompositePropertySource;
 | 
			
		||||
import org.springframework.core.env.MapPropertySource;
 | 
			
		||||
import org.springframework.http.HttpEntity;
 | 
			
		||||
import org.springframework.http.HttpHeaders;
 | 
			
		||||
import org.springframework.http.HttpMethod;
 | 
			
		||||
import org.springframework.http.HttpRequest;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.http.client.ClientHttpRequestExecution;
 | 
			
		||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
 | 
			
		||||
import org.springframework.http.client.ClientHttpResponse;
 | 
			
		||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
 | 
			
		||||
import org.springframework.retry.annotation.Retryable;
 | 
			
		||||
import org.springframework.util.Base64Utils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
import org.springframework.web.client.HttpClientErrorException;
 | 
			
		||||
import org.springframework.web.client.HttpServerErrorException;
 | 
			
		||||
import org.springframework.web.client.ResourceAccessException;
 | 
			
		||||
import org.springframework.web.client.RestTemplate;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.cloud.config.client.ConfigClientProperties.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>
 | 
			
		||||
 * {@link SentinelRuleLocator} which pulls Sentinel rules from remote server.
 | 
			
		||||
 * It retrieves configurations of spring-cloud-config client configurations from
 | 
			
		||||
 * {@link org.springframework.core.env.Environment}, such as {@code spring.cloud.config.uri=uri},
 | 
			
		||||
 * {@code spring.cloud.config.profile=profile}, and so on.
 | 
			
		||||
 * When rules are pulled successfully, it will be stored to {@link SentinelRuleStorage}.
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@Order(0)
 | 
			
		||||
public class SentinelRuleLocator implements PropertySourceLocator {
 | 
			
		||||
 | 
			
		||||
    private RestTemplate restTemplate;
 | 
			
		||||
    private ConfigClientProperties defaultProperties;
 | 
			
		||||
    private org.springframework.core.env.Environment environment;
 | 
			
		||||
 | 
			
		||||
    public SentinelRuleLocator(ConfigClientProperties defaultProperties,
 | 
			
		||||
                               org.springframework.core.env.Environment environment) {
 | 
			
		||||
        this.defaultProperties = defaultProperties;
 | 
			
		||||
        this.environment = environment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Responsible for pull data from remote server
 | 
			
		||||
     *
 | 
			
		||||
     * @param environment
 | 
			
		||||
     * @return correct data if success else a empty propertySource or null
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Retryable(interceptor = "configServerRetryInterceptor")
 | 
			
		||||
    public org.springframework.core.env.PropertySource<?> locate(
 | 
			
		||||
        org.springframework.core.env.Environment environment) {
 | 
			
		||||
        ConfigClientProperties properties = this.defaultProperties.override(environment);
 | 
			
		||||
        CompositePropertySource composite = new CompositePropertySource("configService");
 | 
			
		||||
        RestTemplate restTemplate = this.restTemplate == null
 | 
			
		||||
            ? getSecureRestTemplate(properties)
 | 
			
		||||
            : this.restTemplate;
 | 
			
		||||
        Exception error = null;
 | 
			
		||||
        String errorBody = null;
 | 
			
		||||
        try {
 | 
			
		||||
            String[] labels = new String[] {""};
 | 
			
		||||
            if (StringUtils.hasText(properties.getLabel())) {
 | 
			
		||||
                labels = StringUtils
 | 
			
		||||
                    .commaDelimitedListToStringArray(properties.getLabel());
 | 
			
		||||
            }
 | 
			
		||||
            String state = ConfigClientStateHolder.getState();
 | 
			
		||||
            // Try all the labels until one works
 | 
			
		||||
            for (String label : labels) {
 | 
			
		||||
                Environment result = getRemoteEnvironment(restTemplate, properties,
 | 
			
		||||
                    label.trim(), state);
 | 
			
		||||
                if (result != null) {
 | 
			
		||||
                    log(result);
 | 
			
		||||
                    // result.getPropertySources() can be null if using xml
 | 
			
		||||
                    if (result.getPropertySources() != null) {
 | 
			
		||||
                        for (PropertySource source : result.getPropertySources()) {
 | 
			
		||||
                            @SuppressWarnings("unchecked")
 | 
			
		||||
                            Map<String, Object> map = (Map<String, Object>)source
 | 
			
		||||
                                .getSource();
 | 
			
		||||
                            composite.addPropertySource(
 | 
			
		||||
                                new MapPropertySource(source.getName(), map));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    SentinelRuleStorage.setRulesSource(composite);
 | 
			
		||||
                    return composite;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (HttpServerErrorException e) {
 | 
			
		||||
            error = e;
 | 
			
		||||
            if (MediaType.APPLICATION_JSON.includes(e.getResponseHeaders().getContentType())) {
 | 
			
		||||
                errorBody = e.getResponseBodyAsString();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            error = e;
 | 
			
		||||
        }
 | 
			
		||||
        if (properties.isFailFast()) {
 | 
			
		||||
            throw new IllegalStateException(
 | 
			
		||||
                "Could not locate PropertySource and the fail fast property is set, failing",
 | 
			
		||||
                error);
 | 
			
		||||
        }
 | 
			
		||||
        RecordLog.warn("Could not locate PropertySource: " + (errorBody == null
 | 
			
		||||
            ? error == null ? "label not found" : error.getMessage()
 | 
			
		||||
            : errorBody));
 | 
			
		||||
        return null;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public org.springframework.core.env.PropertySource<?> refresh() {
 | 
			
		||||
        return locate(environment);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void log(Environment result) {
 | 
			
		||||
 | 
			
		||||
        RecordLog.info("Located environment: name={}, profiles={}, label={}, version={}, state={}",
 | 
			
		||||
            result.getName(),
 | 
			
		||||
            result.getProfiles() == null ? "" : Arrays.asList(result.getProfiles()),
 | 
			
		||||
            result.getLabel(), result.getVersion(), result.getState());
 | 
			
		||||
 | 
			
		||||
        List<PropertySource> propertySourceList = result.getPropertySources();
 | 
			
		||||
        if (propertySourceList != null) {
 | 
			
		||||
            int propertyCount = 0;
 | 
			
		||||
            for (PropertySource propertySource : propertySourceList) {
 | 
			
		||||
                propertyCount += propertySource.getSource().size();
 | 
			
		||||
            }
 | 
			
		||||
            RecordLog.info("[SentinelRuleLocator] Environment {} has {} property sources with {} properties",
 | 
			
		||||
                result.getName(), result.getPropertySources().size(), propertyCount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Environment getRemoteEnvironment(RestTemplate restTemplate,
 | 
			
		||||
                                             ConfigClientProperties properties, String label, String state) {
 | 
			
		||||
        String path = "/{name}/{profile}";
 | 
			
		||||
        String name = properties.getName();
 | 
			
		||||
        String profile = properties.getProfile();
 | 
			
		||||
        String token = properties.getToken();
 | 
			
		||||
        int noOfUrls = properties.getUri().length;
 | 
			
		||||
        if (noOfUrls > 1) {
 | 
			
		||||
            RecordLog.debug("[SentinelRuleLocator] Multiple Config Server Urls found listed.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        RecordLog.info("[SentinelRuleLocator] getRemoteEnvironment, properties={}, label={}, state={}",
 | 
			
		||||
            properties, label, state);
 | 
			
		||||
 | 
			
		||||
        Object[] args = new String[] {name, profile};
 | 
			
		||||
        if (StringUtils.hasText(label)) {
 | 
			
		||||
            if (label.contains("/")) {
 | 
			
		||||
                label = label.replace("/", "(_)");
 | 
			
		||||
            }
 | 
			
		||||
            args = new String[] {name, profile, label};
 | 
			
		||||
            path = path + "/{label}";
 | 
			
		||||
        }
 | 
			
		||||
        ResponseEntity<Environment> response = null;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < noOfUrls; i++) {
 | 
			
		||||
            Credentials credentials = properties.getCredentials(i);
 | 
			
		||||
            String uri = credentials.getUri();
 | 
			
		||||
            String username = credentials.getUsername();
 | 
			
		||||
            String password = credentials.getPassword();
 | 
			
		||||
 | 
			
		||||
            RecordLog.info("[SentinelRuleLocator] Fetching config from server at: {}", uri);
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                HttpHeaders headers = new HttpHeaders();
 | 
			
		||||
                addAuthorizationToken(properties, headers, username, password);
 | 
			
		||||
                if (StringUtils.hasText(token)) {
 | 
			
		||||
                    headers.add(TOKEN_HEADER, token);
 | 
			
		||||
                }
 | 
			
		||||
                if (StringUtils.hasText(state) && properties.isSendState()) {
 | 
			
		||||
                    headers.add(STATE_HEADER, state);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                final HttpEntity<Void> entity = new HttpEntity<>((Void)null, headers);
 | 
			
		||||
                response = restTemplate.exchange(uri + path, HttpMethod.GET, entity,
 | 
			
		||||
                    Environment.class, args);
 | 
			
		||||
            } catch (HttpClientErrorException e) {
 | 
			
		||||
                if (e.getStatusCode() != HttpStatus.NOT_FOUND) {
 | 
			
		||||
                    throw e;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (ResourceAccessException e) {
 | 
			
		||||
                RecordLog.warn("[SentinelRuleLocator] ConnectTimeoutException on url <{}>."
 | 
			
		||||
                    + " Will be trying the next url if available", uri);
 | 
			
		||||
                if (i == noOfUrls - 1) {
 | 
			
		||||
                    throw e;
 | 
			
		||||
                } else {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (response == null || response.getStatusCode() != HttpStatus.OK) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Environment result = response.getBody();
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RestTemplate getSecureRestTemplate(ConfigClientProperties client) {
 | 
			
		||||
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
 | 
			
		||||
        if (client.getRequestReadTimeout() < 0) {
 | 
			
		||||
            throw new IllegalStateException("Invalid Value for Read Timeout set.");
 | 
			
		||||
        }
 | 
			
		||||
        requestFactory.setReadTimeout(client.getRequestReadTimeout());
 | 
			
		||||
        RestTemplate template = new RestTemplate(requestFactory);
 | 
			
		||||
        Map<String, String> headers = new HashMap<>(client.getHeaders());
 | 
			
		||||
        if (headers.containsKey(AUTHORIZATION)) {
 | 
			
		||||
            // To avoid redundant addition of header
 | 
			
		||||
            headers.remove(AUTHORIZATION);
 | 
			
		||||
        }
 | 
			
		||||
        if (!headers.isEmpty()) {
 | 
			
		||||
            template.setInterceptors(Arrays.<ClientHttpRequestInterceptor>asList(
 | 
			
		||||
                new GenericRequestHeaderInterceptor(headers)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return template;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addAuthorizationToken(ConfigClientProperties configClientProperties,
 | 
			
		||||
                                       HttpHeaders httpHeaders, String username, String password) {
 | 
			
		||||
        String authorization = configClientProperties.getHeaders().get(AUTHORIZATION);
 | 
			
		||||
 | 
			
		||||
        if (password != null && authorization != null) {
 | 
			
		||||
            throw new IllegalStateException(
 | 
			
		||||
                "You must set either 'password' or 'authorization'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (password != null) {
 | 
			
		||||
            byte[] token = Base64Utils.encode((username + ":" + password).getBytes());
 | 
			
		||||
            httpHeaders.add("Authorization", "Basic " + new String(token));
 | 
			
		||||
        } else if (authorization != null) {
 | 
			
		||||
            httpHeaders.add("Authorization", authorization);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRestTemplate(RestTemplate restTemplate) {
 | 
			
		||||
        this.restTemplate = restTemplate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class GenericRequestHeaderInterceptor
 | 
			
		||||
        implements ClientHttpRequestInterceptor {
 | 
			
		||||
 | 
			
		||||
        private final Map<String, String> headers;
 | 
			
		||||
 | 
			
		||||
        public GenericRequestHeaderInterceptor(Map<String, String> headers) {
 | 
			
		||||
            this.headers = headers;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public ClientHttpResponse intercept(HttpRequest request, byte[] body,
 | 
			
		||||
                                            ClientHttpRequestExecution execution) throws IOException {
 | 
			
		||||
            for (Map.Entry<String, String> header : headers.entrySet()) {
 | 
			
		||||
                request.getHeaders().add(header.getKey(), header.getValue());
 | 
			
		||||
            }
 | 
			
		||||
            return execution.execute(request, body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Map<String, String> getHeaders() {
 | 
			
		||||
            return headers;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.core.env.PropertySource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Storage data pull from spring-config-cloud server
 | 
			
		||||
 * And notice ${@link SpringCloudConfigDataSource} update latest values
 | 
			
		||||
 *
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
public class SentinelRuleStorage {
 | 
			
		||||
 | 
			
		||||
    public static PropertySource<?> rulesSource;
 | 
			
		||||
 | 
			
		||||
    public static void setRulesSource(PropertySource<?> source) {
 | 
			
		||||
        rulesSource = source;
 | 
			
		||||
        noticeSpringCloudDataSource();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String retrieveRule(String ruleKey) {
 | 
			
		||||
        return rulesSource == null ? null : (String) rulesSource.getProperty(ruleKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void noticeSpringCloudDataSource(){
 | 
			
		||||
        SpringCloudConfigDataSource.updateValues();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,111 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.Converter;
 | 
			
		||||
import com.alibaba.csp.sentinel.log.RecordLog;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.StringUtil;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>A read-only {@code DataSource} with Spring Cloud Config backend.</p>
 | 
			
		||||
 * <p>
 | 
			
		||||
 * It retrieves the Spring Cloud Config data stored in {@link SentinelRuleStorage}.
 | 
			
		||||
 * When the data in the backend has been modified, {@link SentinelRuleStorage} will
 | 
			
		||||
 * invoke {@link SpringCloudConfigDataSource#updateValues()} to update values dynamically.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * <p>
 | 
			
		||||
 * To notify the client that the remote config has changed, users could bind a git
 | 
			
		||||
 * webhook callback with the {@link SentinelRuleLocator#refresh()} API.
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
public class SpringCloudConfigDataSource<T> extends AbstractDataSource<String, T> {
 | 
			
		||||
 | 
			
		||||
    private final static Map<SpringCloudConfigDataSource, SpringConfigListener> listeners;
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        listeners = new ConcurrentHashMap<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final String ruleKey;
 | 
			
		||||
 | 
			
		||||
    public SpringCloudConfigDataSource(final String ruleKey, Converter<String, T> converter) {
 | 
			
		||||
        super(converter);
 | 
			
		||||
        if (StringUtil.isBlank(ruleKey)) {
 | 
			
		||||
            throw new IllegalArgumentException(String.format("Bad argument: ruleKey=[%s]", ruleKey));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.ruleKey = ruleKey;
 | 
			
		||||
        loadInitialConfig();
 | 
			
		||||
        initListener();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void loadInitialConfig() {
 | 
			
		||||
        try {
 | 
			
		||||
            T newValue = loadConfig();
 | 
			
		||||
            if (newValue == null) {
 | 
			
		||||
                RecordLog.warn("[SpringCloudConfigDataSource] WARN: initial application is null, you may have to check your data source");
 | 
			
		||||
            }
 | 
			
		||||
            getProperty().updateValue(newValue);
 | 
			
		||||
        } catch (Exception ex) {
 | 
			
		||||
            RecordLog.warn("[SpringCloudConfigDataSource] Error when loading initial application", ex);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initListener() {
 | 
			
		||||
        listeners.put(this, new SpringConfigListener(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String readSource() {
 | 
			
		||||
        return SentinelRuleStorage.retrieveRule(ruleKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() throws Exception {
 | 
			
		||||
        listeners.remove(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void updateValues() {
 | 
			
		||||
        for (SpringConfigListener listener : listeners.values()) {
 | 
			
		||||
            listener.listenChanged();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class SpringConfigListener {
 | 
			
		||||
 | 
			
		||||
        private SpringCloudConfigDataSource dataSource;
 | 
			
		||||
 | 
			
		||||
        public SpringConfigListener(SpringCloudConfigDataSource dataSource) {
 | 
			
		||||
            this.dataSource = dataSource;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void listenChanged() {
 | 
			
		||||
            try {
 | 
			
		||||
                Object newValue = dataSource.loadConfig();
 | 
			
		||||
                dataSource.getProperty().updateValue(newValue);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                RecordLog.warn("[SpringConfigListener] load config error: ", e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config.config;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.SentinelRuleLocator;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.cloud.config.client.ConfigClientProperties;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.env.ConfigurableEnvironment;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Define the configuration Loaded when spring application start.
 | 
			
		||||
 * Put it in META-INF/spring.factories, it will be auto loaded by Spring
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class DataSourceBootstrapConfiguration {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ConfigurableEnvironment environment;
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public SentinelRuleLocator sentinelPropertySourceLocator(ConfigClientProperties properties) {
 | 
			
		||||
        SentinelRuleLocator locator = new SentinelRuleLocator(
 | 
			
		||||
                properties, environment);
 | 
			
		||||
        return locator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
 | 
			
		||||
com.alibaba.csp.sentinel.datasource.spring.cloud.config.config.DataSourceBootstrapConfiguration
 | 
			
		||||
@@ -0,0 +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 com.alibaba.csp.sentinel.datasource.spring.cloud.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
public abstract class SimpleSpringApplication {
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        SpringApplication.run(SimpleSpringApplication.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config.client;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
import org.springframework.context.annotation.ComponentScan;
 | 
			
		||||
import org.springframework.context.annotation.PropertySource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
@ComponentScan("com.alibaba.csp.sentinel.datasource.spring.cloud.config.test")
 | 
			
		||||
@PropertySource("classpath:config-client-application.properties")
 | 
			
		||||
public class ConfigClient {
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        SpringApplication.run(ConfigClient.class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config.server;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
import org.springframework.cloud.config.server.EnableConfigServer;
 | 
			
		||||
import org.springframework.context.annotation.PropertySource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@EnableConfigServer
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
@PropertySource("classpath:config-server-application.properties")
 | 
			
		||||
public class ConfigServer {
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        SpringApplication.run(ConfigServer.class);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,71 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2018-2019 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config.test;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.SentinelRuleLocator;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.SentinelRuleStorage;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.config.DataSourceBootstrapConfiguration;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.server.ConfigServer;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.StringUtil;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
			
		||||
import org.springframework.cloud.config.client.ConfigClientProperties;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.test.context.junit4.SpringRunner;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(SpringRunner.class)
 | 
			
		||||
@SpringBootTest(classes = DataSourceBootstrapConfiguration.class, properties = {
 | 
			
		||||
        "spring.application.name=sentinel"
 | 
			
		||||
})
 | 
			
		||||
public class SentinelRuleLocatorTests {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private SentinelRuleLocator sentinelRulesSourceLocator;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private Environment environment;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAutoLoad() {
 | 
			
		||||
        Assert.assertTrue(sentinelRulesSourceLocator != null);
 | 
			
		||||
        Assert.assertTrue(environment != null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Before run this test case, please start the Config Server ${@link ConfigServer}
 | 
			
		||||
     */
 | 
			
		||||
    public void testLocate() {
 | 
			
		||||
        ConfigClientProperties configClientProperties = new ConfigClientProperties(environment);
 | 
			
		||||
        configClientProperties.setLabel("master");
 | 
			
		||||
        configClientProperties.setProfile("dev");
 | 
			
		||||
        configClientProperties.setUri(new String[]{"http://localhost:10086/"});
 | 
			
		||||
        SentinelRuleLocator sentinelRulesSourceLocator = new SentinelRuleLocator(configClientProperties, environment);
 | 
			
		||||
        sentinelRulesSourceLocator.locate(environment);
 | 
			
		||||
        Assert.assertTrue(StringUtil.isNotBlank(SentinelRuleStorage.retrieveRule("flow_rule")));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.datasource.spring.cloud.config.test;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.Converter;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.SentinelRuleLocator;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.SpringCloudConfigDataSource;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.client.ConfigClient;
 | 
			
		||||
import com.alibaba.csp.sentinel.datasource.spring.cloud.config.server.ConfigServer;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
 | 
			
		||||
import com.alibaba.fastjson.JSON;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.ResponseBody;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Before test, please start ${@link ConfigServer} and ${@link ConfigClient}
 | 
			
		||||
 *
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = "/test/dataSource/")
 | 
			
		||||
public class SpringCouldDataSourceTest {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private SentinelRuleLocator locator;
 | 
			
		||||
 | 
			
		||||
    Converter<String, List<FlowRule>> converter = new Converter<String, List<FlowRule>>() {
 | 
			
		||||
        @Override
 | 
			
		||||
        public List<FlowRule> convert(String source) {
 | 
			
		||||
            return JSON.parseArray(source, FlowRule.class);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public List<FlowRule> get() {
 | 
			
		||||
        SpringCloudConfigDataSource dataSource = new SpringCloudConfigDataSource("flow_rule", converter);
 | 
			
		||||
        FlowRuleManager.register2Property(dataSource.getProperty());
 | 
			
		||||
        return FlowRuleManager.getRules();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * WebHook refresh config
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/refresh")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public List<FlowRule> refresh() {
 | 
			
		||||
        locator.refresh();
 | 
			
		||||
        return FlowRuleManager.getRules();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
spring:
 | 
			
		||||
  application:
 | 
			
		||||
    name: sentinel
 | 
			
		||||
  cloud:
 | 
			
		||||
    config:
 | 
			
		||||
      uri: http://localhost:10086/
 | 
			
		||||
      profile: dev
 | 
			
		||||
      label: master
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
spring.application.name=sentinel
 | 
			
		||||
server.port=8080
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
spring.cloud.config.server.git.uri=git@github.com:linlinisme/spring-cloud-config-datasource.git
 | 
			
		||||
spring.cloud.config.server.git.search-paths=sentinel
 | 
			
		||||
server.port=10086
 | 
			
		||||
spring.cloud.config.label=master 
 | 
			
		||||
		Reference in New Issue
	
	Block a user