Merge pull request #6 from spring-cloud-incubator/1.x

Merge
pull/89/head
Neptune 6 years ago committed by GitHub
commit fe28674457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,40 @@
version: 2
jobs:
build:
docker:
- image: springcloud/pipeline-base
user: appuser
environment:
_JAVA_OPTIONS: "-Xms1024m -Xmx2048m"
TERM: dumb
branches:
ignore:
- gh-pages # list of branches to ignore
resource_class: large
steps:
- checkout
- restore_cache:
key: sc-alibaba-{{ .Branch }}
- run:
name: "Download dependencies"
command: ./mvnw -Pspring -U --fail-never dependency:go-offline || true
- save_cache:
key: sc-alibaba-{{ .Branch }}
paths:
- ~/.m2
- run:
name: "Running build"
command: ./mvnw -Pspring clean install -U -nsu --batch-mode -Dmaven.test.redirectTestOutputToFile=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
- run:
name: "Aggregate test results"
when: always
command: |
mkdir -p ~/junit/
find . -type f -regex ".*/target/.*-reports/.*" -exec cp {} ~/junit/ \;
bash <(curl -s https://codecov.io/bash)
- store_artifacts:
path: ~/junit/
destination: artifacts
- store_test_results:
path: ~/junit/
destination: testartifacts

1
.gitignore vendored

@ -28,4 +28,5 @@ hs_err_pid*
.project
.settings
target
.DS_Store

@ -8,7 +8,7 @@ Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解
## 主要功能
* **服务限流降级**:默认支持为 HTTP 服务的提供限流保护,也支持添加注解实现方法的自定义限流降级,且支持动态修改限流降级规则。
* **服务注册与发现**:适配 sprig cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
* **服务注册与发现**:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。
* **阿里云对象存储**:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。

@ -1,5 +1,7 @@
# Spring Cloud Alibaba
A project maintained by Alibaba.
See the [中文文档](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/README-zh.md) for Chinese readme.
Spring Cloud Alibaba provides a one-stop solution for distributed application development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications using Spring Cloud.

@ -15,7 +15,7 @@ Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解
**Nacos**
阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
**Aliyun OSS**
**AliCloud OSS**
阿里云对象存储服务Object Storage Service简称 OSS是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
## 即将加入的组件

@ -8,13 +8,13 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>1.3.10.RELEASE</version>
<version>1.3.11.RELEASE</version>
<relativePath/>
</parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Cloud Alibaba</name>
@ -28,12 +28,12 @@
</licenses>
<scm>
<url>https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud</url>
<url>https://github.com/spring-cloud-incubator/spring-cloud-alibaba</url>
<connection>
scm:git:git://github.com/spring-cloud-incubator/spring-cloud-alibabacloud.git
scm:git:git://github.com/spring-cloud-incubator/spring-cloud-alibaba.git
</connection>
<developerConnection>
scm:git:ssh://git@github.com/spring-cloud-incubator/spring-cloud-alibabacloud.git
scm:git:ssh://git@github.com/spring-cloud-incubator/spring-cloud-alibaba.git
</developerConnection>
<tag>HEAD</tag>
</scm>
@ -47,6 +47,10 @@
<name>fangjian</name>
<email>fangjian0423@gmail.com</email>
</developer>
<developer>
<name>xiaolongzuo</name>
<email>150349407@qq.com</email>
</developer>
<developer>
<name>hengyunabc</name>
<email>hengyunabc@gmail.com</email>
@ -55,8 +59,8 @@
<properties>
<!-- Dependency Versions -->
<spring-cloud-commons.version>1.3.3.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>1.4.4.RELEASE</spring-cloud-netflix.version>
<spring-cloud-commons.version>1.3.5.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>1.4.6.RELEASE</spring-cloud-netflix.version>
<junit.version>4.12</junit.version>
<javax-servlet-api>3.0</javax-servlet-api>
@ -73,7 +77,7 @@
<modules>
<module>spring-cloud-alibaba-dependencies</module>
<module>spring-cloud-alibaba-sentinel</module>
<module>spring-cloud-alibaba-sentinel-datasource</module>
<module>spring-cloud-alibaba-nacos-config</module>
<module>spring-cloud-alibaba-nacos-discovery</module>
<module>spring-cloud-alibaba-examples</module>
@ -81,6 +85,9 @@
<module>spring-cloud-starter-alibaba</module>
<module>spring-cloud-starter-alicloud</module>
<module>spring-cloud-alicloud-oss</module>
<module>spring-cloud-alicloud-context</module>
<module>spring-cloud-alicloud-acm</module>
<module>spring-cloud-alicloud-ans</module>
</modules>
<dependencyManagement>
@ -137,4 +144,69 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>spring</id>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</project>

@ -6,24 +6,60 @@
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>1.3.10.RELEASE</version>
<version>1.3.11.RELEASE</version>
<relativePath/>
</parent>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Cloud Alibaba Dependencies</name>
<description>Spring Cloud Alibaba Dependencies</description>
<properties>
<sentinel.version>0.2.0</sentinel.version>
<sentinel.version>1.3.0-GA</sentinel.version>
<oss.version>3.1.0</oss.version>
<nacos.version>0.2.1</nacos.version>
<nacos.version>0.3.0</nacos.version>
<acm.version>1.0.8</acm.version>
<ans.version>0.1.1</ans.version>
<aliyun.sdk.version>4.0.1</aliyun.sdk.version>
<alicloud.context.version>1.0.0</alicloud.context.version>
<aliyun.sdk.edas.version>2.16.0</aliyun.sdk.edas.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>alicloud-context</artifactId>
<version>${alicloud.context.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-edas</artifactId>
<version>${aliyun.sdk.edas.version}</version>
<exclusions>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>${aliyun.sdk.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.ans</groupId>
<artifactId>ans-sdk</artifactId>
<version>${ans.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.edas.acm</groupId>
<artifactId>acm-sdk</artifactId>
<version>${acm.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
@ -81,8 +117,7 @@
</dependency>
<!-- Aliyun storage dependencies -->
<!-- Aliyun OSS dependencies -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
@ -90,12 +125,17 @@
</dependency>
<!-- Own dependencies autoconfigure -->
<!-- Own dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-oss</artifactId>
@ -111,6 +151,21 @@
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-acm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-ans</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-context</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Own dependencies - Starters -->
<dependency>
@ -136,9 +191,17 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-ans</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-acm</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Testing Dependencies -->

@ -0,0 +1,27 @@
<?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>spring-cloud-alibaba-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>acm-local-example</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-acm</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,34 @@
/*
* 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.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author xiaolongzuo
*/
@SpringBootApplication
@EnableDiscoveryClient
public class AcmApplication {
public static void main(String[] args) {
SpringApplication.run(AcmApplication.class, args);
}
}

@ -0,0 +1,41 @@
/*
* 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.cloud.examples;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xiaolongzuo
*/
@RestController
public class EchoController {
private static final Logger LOGGER = LoggerFactory.getLogger(EchoController.class);
@Value("${user.id}")
private String userId;
@RequestMapping(value = "/")
public String echo() {
LOGGER.info("User id is " + userId);
return userId;
}
}

@ -0,0 +1,5 @@
spring.application.group=com.alibaba.acm
spring.application.name=acm-local
server.port=18089
spring.cloud.alicloud.acm.server-list=127.0.0.1
spring.cloud.alicloud.acm.server-port=8080

@ -0,0 +1,31 @@
<?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>spring-cloud-alibaba-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ans-consumer-feign-example</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-ans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,34 @@
/*
* 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.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
/**
* @author xiaolongzuo
*/
@SpringBootApplication
@EnableFeignClients(basePackages = { "org.springframework.cloud.alibaba.cloud.examples" })
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}

@ -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 org.springframework.cloud.alibaba.cloud.examples;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author xiaolongzuo
*/
@FeignClient(value = "ans-provider")
public interface EchoService {
@RequestMapping(path = "echo/{str}")
String echo(@RequestParam("str") String param);
}

@ -0,0 +1,47 @@
/*
* 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.cloud.examples;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xiaolongzuo
*/
@RestController
public class
HomeController {
private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
@Autowired
private EchoService echoService;
@RequestMapping(value = "/", method = RequestMethod.GET, produces = "application/json")
public String home() {
LOGGER.info("-----------------consumer调用开始-----------------");
String param = "Nice to meet you.";
LOGGER.info("消费者传递参数:" + param);
String result = echoService.echo(param);
LOGGER.info("收到提供者响应:" + result);
return param + "<br>" + result;
}
}

@ -0,0 +1,4 @@
server.port=18083
# The following configuration can be omitted.
spring.cloud.alicloud.ans.server.list=127.0.0.1
spring.cloud.alicloud.ans.server.port=8080

@ -0,0 +1,27 @@
<?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>spring-cloud-alibaba-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ans-consumer-ribbon-example</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-ans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,43 @@
/*
* 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.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaolongzuo
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}

@ -0,0 +1,47 @@
/*
* 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.cloud.examples;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaolongzuo
*/
@RestController
public class HomeController {
private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/", method = RequestMethod.GET, produces = "application/json")
public String home() {
LOGGER.info("-----------------consumer调用开始-----------------");
String param = "Nice to meet you.";
LOGGER.info("消费者传递参数:" + param);
String result = restTemplate.getForObject("http://ans-provider/echo/" + param, String.class);
LOGGER.info("收到提供者响应:" + result);
return param + "<br>" + result;
}
}

@ -0,0 +1,4 @@
server.port=18082
# The following configuration can be omitted.
spring.cloud.alicloud.ans.server.list=127.0.0.1
spring.cloud.alicloud.ans.server.port=8080

@ -0,0 +1,27 @@
<?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>spring-cloud-alibaba-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ans-provider-example</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-ans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,42 @@
/*
* 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.cloud.examples;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xiaolongzuo
*/
@RestController
public class EchoController {
private static final Logger LOGGER = LoggerFactory.getLogger(EchoController.class);
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET, produces = "application/json")
public String echo(@PathVariable String str) {
LOGGER.info("-----------收到消费者请求-----------");
LOGGER.info("收到消费者传递的参数:" + str);
String result = "Nice to meet you, too.";
LOGGER.info("提供者返回结果:" + result);
return result;
}
}

@ -0,0 +1,34 @@
/*
* 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.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author xiaolongzuo
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}

@ -0,0 +1,4 @@
spring.application.name=ans-provider
server.port=18081
spring.cloud.alicloud.ans.server.list=127.0.0.1
spring.cloud.alicloud.ans.server.port=8080

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -19,9 +19,10 @@
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2. 在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 地址
2. 在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 元数据
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
3. 完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment 的 PropertySources 中。这里我们使用 @Value 注解来将对应的配置注入到 SampleController 的 userName 和 age 字段,并添加 @RefreshScope 打开动态刷新功能
@ -70,8 +71,8 @@
1. 增加配置,在应用的 /src/main/resources/application.properties 中添加基本配置信息
spring.application.name=nacos-config-example
server.port=18084
server.port=18084
management.endpoints.web.exposure.include=*
2. 启动应用,支持 IDE 直接启动和编译打包后启动。

@ -19,9 +19,10 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2. Add Nacos server address configurations to file /src/main/resources/bootstrap.properties
2. Add Nacos config metadata configurations to file /src/main/resources/bootstrap.properties
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
3. After completing the above two steps, the application will get the externalized configuration from Nacos Server and put it in the Spring Environment's PropertySources.We use the @Value annotation to inject the corresponding configuration into the userName and age fields of the SampleController, and add @RefreshScope to turn on dynamic refresh .
@RefreshScope
@ -70,8 +71,8 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
1. Add necessary configurations to file /src/main/resources/application.properties
spring.application.name=nacos-config-example
server.port=18084
server.port=18084
management.endpoints.web.exposure.include=*
2. Start the application in IDE or by building a fatjar.

@ -16,39 +16,39 @@ import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Component
class SampleRunner implements ApplicationRunner {
@Value("${user.name}")
String userName;
@Value("${user.name}")
String userName;
@Value("${user.age}")
int userAge;
@Value("${user.age}")
int userAge;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(userName);
System.out.println(userAge);
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(userName);
System.out.println(userAge);
}
}
@RestController
@RefreshScope
class SampleController {
@Value("${user.name}")
String userName;
@Value("${user.name}")
String userName;
@Value("${user.age}")
int age;
@Value("${user.age}")
int age;
@RequestMapping("/user")
public String simple() {
return "Hello Nacos Config!" + "Hello " + userName + " " + age + "!";
}
@RequestMapping("/user")
public String simple() {
return "Hello Nacos Config!" + "Hello " + userName + " " + age + "!";
}
}

@ -1,3 +1,2 @@
spring.application.name=nacos-config-example
server.port=18084
management.endpoints.web.exposure.include=*

@ -1 +1,2 @@
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>nacos-discovery-example</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>nacos-discovery-example</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -1,51 +0,0 @@
package org.springframework.cloud.alibaba.cloud.examples;
import java.net.URISyntaxException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.aliyun.oss.OSS;
/**
* OSS Application
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@SpringBootApplication
public class OSSApplication {
public static final String BUCKET_NAME = "spring-cloud-alibaba";
public static void main(String[] args) throws URISyntaxException {
SpringApplication.run(OSSApplication.class, args);
}
@Bean
public AppRunner appRunner() {
return new AppRunner();
}
class AppRunner implements ApplicationRunner {
@Autowired
private OSS ossClient;
@Override
public void run(ApplicationArguments args) throws Exception {
try {
if (!ossClient.doesBucketExist(BUCKET_NAME)) {
ossClient.createBucket(BUCKET_NAME);
}
}
catch (Exception e) {
System.err.println("oss handle bucket error: " + e.getMessage());
System.exit(-1);
}
}
}
}

@ -1,72 +0,0 @@
package org.springframework.cloud.alibaba.cloud.examples;
import java.nio.charset.Charset;
import org.apache.commons.codec.CharEncoding;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.model.OSSObject;
/**
* OSS Controller
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@RestController
public class OSSController {
@Autowired
private OSS ossClient;
@Value("oss://" + OSSApplication.BUCKET_NAME + "/oss-test")
private Resource file;
private String dir = "custom-dir/";
@GetMapping("/upload")
public String upload() {
try {
ossClient.putObject(OSSApplication.BUCKET_NAME, dir + "oss-test", this
.getClass().getClassLoader().getResourceAsStream("oss-test.json"));
}
catch (Exception e) {
e.printStackTrace();
return "upload fail: " + e.getMessage();
}
return "upload success";
}
@GetMapping("/file-resource")
public String fileResource() {
try {
return "get file resource success. content: " + StreamUtils.copyToString(
file.getInputStream(), Charset.forName(CharEncoding.UTF_8));
}
catch (Exception e) {
e.printStackTrace();
return "get resource fail: " + e.getMessage();
}
}
@GetMapping("/download")
public String download() {
try {
OSSObject ossObject = ossClient.getObject(OSSApplication.BUCKET_NAME,
dir + "oss-test");
return "download success, content: " + IOUtils
.readStreamAsString(ossObject.getObjectContent(), CharEncoding.UTF_8);
}
catch (Exception e) {
e.printStackTrace();
return "download fail: " + e.getMessage();
}
}
}

@ -0,0 +1,51 @@
package org.springframework.cloud.alibaba.cloud.examples;
import java.net.URISyntaxException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.aliyun.oss.OSS;
/**
* OSS Application
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@SpringBootApplication
public class OssApplication {
public static final String BUCKET_NAME = "spring-cloud-alibaba-test";
public static void main(String[] args) throws URISyntaxException {
SpringApplication.run(OssApplication.class, args);
}
@Bean
public AppRunner appRunner() {
return new AppRunner();
}
class AppRunner implements ApplicationRunner {
@Autowired
private OSS ossClient;
@Override
public void run(ApplicationArguments args) throws Exception {
try {
if (!ossClient.doesBucketExist(BUCKET_NAME)) {
ossClient.createBucket(BUCKET_NAME);
}
}
catch (Exception e) {
System.err.println("oss handle bucket error: " + e.getMessage());
System.exit(-1);
}
}
}
}

@ -0,0 +1,70 @@
package org.springframework.cloud.alibaba.cloud.examples;
import java.nio.charset.Charset;
import org.apache.commons.codec.CharEncoding;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.model.OSSObject;
/**
* OSS Controller
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@RestController
public class OssController {
@Autowired
private OSS ossClient;
@Value("oss://" + OssApplication.BUCKET_NAME + "/oss-test.json")
private Resource file;
@GetMapping("/upload")
public String upload() {
try {
ossClient.putObject(OssApplication.BUCKET_NAME, "oss-test.json", this
.getClass().getClassLoader().getResourceAsStream("oss-test.json"));
}
catch (Exception e) {
e.printStackTrace();
return "upload fail: " + e.getMessage();
}
return "upload success";
}
@GetMapping("/file-resource")
public String fileResource() {
try {
return "get file resource success. content: " + StreamUtils.copyToString(
file.getInputStream(), Charset.forName(CharEncoding.UTF_8));
}
catch (Exception e) {
e.printStackTrace();
return "get resource fail: " + e.getMessage();
}
}
@GetMapping("/download")
public String download() {
try {
OSSObject ossObject = ossClient.getObject(OssApplication.BUCKET_NAME,
"oss-test.json");
return "download success, content: " + IOUtils
.readStreamAsString(ossObject.getObjectContent(), CharEncoding.UTF_8);
}
catch (Exception e) {
e.printStackTrace();
return "download fail: " + e.getMessage();
}
}
}

@ -1,8 +1,6 @@
spring.application.name=oss-example
server.port=18084
spring.cloud.alibaba.oss.accessKeyId=[your-ak]
spring.cloud.alibaba.oss.secretAccessKey=[your-sk]
spring.cloud.alibaba.oss.region=[your-region]
management.security.enabled=false
spring.cloud.alicloud.access-key=AK
spring.cloud.alicloud.secret-key=SK
spring.cloud.alicloud.oss.endpoint=***.aliyuncs.com
management.endpoints.web.exposure.include=*

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -23,6 +23,10 @@
<module>nacos-example/nacos-discovery-example</module>
<module>nacos-example/nacos-config-example</module>
<module>oss-example</module>
<module>ans-example/ans-consumer-feign-example</module>
<module>ans-example/ans-consumer-ribbon-example</module>
<module>ans-example/ans-provider-example</module>
<module>acm-example/acm-local-example</module>
</modules>
<build>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -192,9 +192,9 @@ Sentinel 控制台支持实时监控查看,您可以通过 Sentinel 控制台
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180' ></p>
## DataSource 支持
## ReadableDataSource 支持
Sentinel 内部提供了[动态规则的扩展实现 DataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。
Sentinel 内部提供了[动态规则的扩展实现 ReadableDataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。
Sentinel starter 整合了目前存在的几类 DataSource。只需要在配置文件中进行相关配置即可在 Spring 容器中自动注册 DataSource。
@ -210,7 +210,7 @@ Sentinel starter 整合了目前存在的几类 DataSource。只需要在配置
然后使用`@SentinelDataSource` 注解修饰 DataSource 即可注入:
@SentinelDataSource("spring.cloud.sentinel.datasource")
private DataSource dataSource;
private ReadableDataSource dataSource;
`@SentinelDataSource` 注解的 value 属性可以不填。默认值就是 `spring.cloud.sentinel.datasource`
@ -222,7 +222,7 @@ Sentinel starter 整合了目前存在的几类 DataSource。只需要在配置
`spring.cloud.sentinel.datasource.converter`代表 `Converter` 在 Spring 容器里的 name。如果没找到会抛出异常。
type目前支持file, nacos, zk, apollo。
type目前支持file, nacos, zk, apollo。其中nacoszkapollo的使用需要加上对应的依赖`sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`, `sentinel-datasource-apollo`
### 自定义DataSource
@ -230,7 +230,7 @@ type目前支持file, nacos, zk, apollo。
1. 定义DataSource
public class CustomDataSource implements DataSource {
public class CustomDataSource implements ReadableDataSource {
private String fieldA;
private String fieldB;
...

@ -165,9 +165,9 @@ To see the metrics, click **实时监控(Real-time Monitoring)** in the left-sid
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180'></p>
## DataSource
## ReadableDataSource
Sentinel provide [DataSource](https://github.com/alibaba/Sentinel/blob/master/sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/DataSource.java) to manage dynamic rules.
Sentinel provide [ReadableDataSource](https://github.com/alibaba/Sentinel/blob/master/sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/ReadableDataSource.java) to manage dynamic rules.
Sentinel starter integrated 4 DataSources provided by Sentinel. It will be register into Spring Context if you write some configs in `application.properties`.
@ -183,7 +183,7 @@ If you want to define FileRefreshableDataSource:
then use `@SentinelDataSource` to annotate DataSource:
@SentinelDataSource("spring.cloud.sentinel.datasource")
private DataSource dataSource;
private ReadableDataSource dataSource;
The value() of `@SentinelDataSource` is not required, it means the prefix of configuration. Default value is `spring.cloud.sentinel.datasource`.
@ -193,7 +193,7 @@ spring.cloud.sentinel.datasource.recommendRefreshMs means the recommendRefreshMs
spring.cloud.sentinel.datasource.converter means the name of spring bean that type is Converter. If the bean is not exists, will throw exception.
Now datasource type support 4 categories: file, nacos, zk, apollo.
Now datasource type support 4 categories: file, nacos, zk, apollo. If you want to using nacos, zk or apollo, you should add `sentinel-datasource-nacos`, `sentinel-datasource-zookeeper` or `sentinel-datasource-apollo` dependency.
### User-defined DataSource
@ -201,7 +201,7 @@ User-defined DataSource need 2 steps.
1. Define DataSource
public class CustomDataSource implements DataSource {
public class CustomDataSource implements ReadableDataSource {
private String fieldA;
private String fieldB;
...

@ -10,5 +10,5 @@ spring.cloud.sentinel.datasource.type=file
spring.cloud.sentinel.datasource.recommendRefreshMs=3000
spring.cloud.sentinel.datasource.bufSize=4056196
spring.cloud.sentinel.datasource.charset=utf-8
spring.cloud.sentinel.datasource.configParser=myParser
spring.cloud.sentinel.datasource.converter=myParser
spring.cloud.sentinel.datasource.file=/Users/you/rule.json

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -16,8 +16,6 @@
package org.springframework.cloud.alibaba.nacos;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.refresh.NacosContextRefresher;
@ -43,14 +41,6 @@ public class NacosConfigAutoConfiguration implements ApplicationContextAware {
@Autowired
private NacosRefreshProperties nacosRefreshProperties;
@Autowired
private ConfigService configService;
@Bean
public NacosConfigProperties nacosConfigProperties() {
return new NacosConfigProperties();
}
@Bean
public NacosPropertySourceRepository nacosPropertySourceRepository() {
return new NacosPropertySourceRepository(applicationContext);
@ -69,10 +59,10 @@ public class NacosConfigAutoConfiguration implements ApplicationContextAware {
@Bean
public NacosContextRefresher nacosContextRefresher(ContextRefresher contextRefresher,
NacosRefreshHistory refreshHistory,
NacosPropertySourceRepository propertySourceRepository,
ConfigService configService) {
NacosPropertySourceRepository propertySourceRepository) {
return new NacosContextRefresher(contextRefresher, nacosConfigProperties,
nacosRefreshProperties, refreshHistory, propertySourceRepository,configService);
nacosRefreshProperties, refreshHistory, propertySourceRepository,
nacosConfigProperties.configServiceInstance());
}
@Override

@ -16,6 +16,7 @@
package org.springframework.cloud.alibaba.nacos;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -32,6 +33,7 @@ public class NacosConfigBootstrapConfiguration {
}
@Bean
@ConditionalOnMissingBean
public NacosConfigProperties nacosConfigProperties() {
return new NacosConfigProperties();
}

@ -16,9 +16,30 @@
package org.springframework.cloud.alibaba.nacos;
import java.util.Arrays;
import java.util.Objects;
import java.util.Properties;
import javax.annotation.PostConstruct;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH;
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
/**
* nacos properties
@ -29,6 +50,9 @@ import org.springframework.util.StringUtils;
@ConfigurationProperties("spring.cloud.nacos.config")
public class NacosConfigProperties {
private static final Logger LOGGER = LoggerFactory
.getLogger(NacosConfigProperties.class);
/**
* nacos config server address
*/
@ -89,6 +113,21 @@ public class NacosConfigProperties {
*/
private String clusterName;
@Value("${spring.application.name}")
private String name;
private String[] activeProfiles;
private ConfigService configService;
@Autowired
private Environment environment;
@PostConstruct
public void init() {
this.activeProfiles = environment.getActiveProfiles();
}
// todo sts support
public String getServerAddr() {
@ -187,6 +226,14 @@ public class NacosConfigProperties {
this.clusterName = clusterName;
}
public String getName() {
return name;
}
public String[] getActiveProfiles() {
return activeProfiles;
}
@Override
public String toString() {
return "NacosConfigProperties{" + "serverAddr='" + serverAddr + '\''
@ -195,46 +242,32 @@ public class NacosConfigProperties {
+ ", timeout=" + timeout + ", endpoint='" + endpoint + '\''
+ ", namespace='" + namespace + '\'' + ", accessKey='" + accessKey + '\''
+ ", secretKey='" + secretKey + '\'' + ", contextPath='" + contextPath
+ '\'' + ", clusterName='" + clusterName + '\'' + '}';
+ '\'' + ", clusterName='" + clusterName + '\'' + ", name='" + name + '\''
+ ", activeProfiles=" + Arrays.toString(activeProfiles) + '}';
}
public void overrideFromEnv(Environment env) {
public ConfigService configServiceInstance() {
if (StringUtils.isEmpty(this.getServerAddr())) {
this.setServerAddr(
env.resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}"));
}
if (StringUtils.isEmpty(this.getEncode())) {
this.setEncode(
env.resolvePlaceholders("${spring.cloud.nacos.config.encode:}"));
}
if (StringUtils.isEmpty(this.getNamespace())) {
this.setNamespace(
env.resolvePlaceholders("${spring.cloud.nacos.config.namespace:}"));
if (null != configService) {
return configService;
}
if (StringUtils.isEmpty(this.getAccessKey())) {
this.setAccessKey(
env.resolvePlaceholders("${spring.cloud.nacos.config.access-key:}"));
}
if (StringUtils.isEmpty(this.getSecretKey())) {
this.setSecretKey(
env.resolvePlaceholders("${spring.cloud.nacos.config.secret-key:}"));
}
if (StringUtils.isEmpty(this.getContextPath())) {
this.setContextPath(env
.resolvePlaceholders("${spring.cloud.nacos.config.context-path:}"));
}
if (StringUtils.isEmpty(this.getClusterName())) {
this.setClusterName(env
.resolvePlaceholders("${spring.cloud.nacos.config.cluster-name:}"));
}
if (StringUtils.isEmpty(this.getEndpoint())) {
this.setEndpoint(
env.resolvePlaceholders("${spring.cloud.nacos.config.endpoint:}"));
Properties properties = new Properties();
properties.put(SERVER_ADDR, Objects.toString(this.serverAddr, ""));
properties.put(ENCODE, Objects.toString(this.encode, ""));
properties.put(NAMESPACE, Objects.toString(this.namespace, ""));
properties.put(ACCESS_KEY, Objects.toString(this.accessKey, ""));
properties.put(SECRET_KEY, Objects.toString(this.secretKey, ""));
properties.put(CONTEXT_PATH, Objects.toString(this.contextPath, ""));
properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
properties.put(ENDPOINT, Objects.toString(this.endpoint, ""));
try {
configService = NacosFactory.createConfigService(properties);
return configService;
}
if (StringUtils.isEmpty(this.getPrefix())) {
this.setPrefix(
env.resolvePlaceholders("${spring.cloud.nacos.config.prefix:}"));
catch (Exception e) {
LOGGER.error("create config service error!properties={},e=,", this, e);
return null;
}
}
}

@ -83,7 +83,6 @@ public class NacosPropertySourceBuilder {
String data = null;
try {
data = configService.getConfig(dataId, group, timeout);
// todo add file extension yaml support
if (!StringUtils.isEmpty(data)) {
logger.info(String.format("Loading nacos data, dataId: '%s', group: '%s'",
dataId, group));

@ -16,12 +16,9 @@
package org.springframework.cloud.alibaba.nacos.client;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
@ -30,11 +27,7 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import static com.alibaba.nacos.api.PropertyKeyConst.*;
/**
* @author xiaojing
@ -48,47 +41,15 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
private static final String SEP1 = "-";
private static final String DOT = ".";
@Autowired
private ConfigurableListableBeanFactory beanFactory;
@Autowired
private NacosConfigProperties nacosConfigProperties;
private ConfigService configService;
private NacosPropertySourceBuilder nacosPropertySourceBuilder;
private Properties getPropertiesFromEnv(Environment env) {
nacosConfigProperties.overrideFromEnv(env);
Properties properties = new Properties();
properties.put(SERVER_ADDR, nacosConfigProperties.getServerAddr());
properties.put(ENCODE, nacosConfigProperties.getEncode());
properties.put(NAMESPACE, nacosConfigProperties.getNamespace());
properties.put(ACCESS_KEY, nacosConfigProperties.getAccessKey());
properties.put(SECRET_KEY, nacosConfigProperties.getSecretKey());
properties.put(CONTEXT_PATH, nacosConfigProperties.getContextPath());
properties.put(CLUSTER_NAME, nacosConfigProperties.getClusterName());
properties.put(ENDPOINT, nacosConfigProperties.getEndpoint());
return properties;
}
@Override
public PropertySource<?> locate(Environment env) {
Properties properties = getPropertiesFromEnv(env);
try {
configService = NacosFactory.createConfigService(properties);
}
catch (NacosException e) {
logger.error("create config service error, nacosConfigProperties:{}, ",
properties, e);
return null;
}
beanFactory.registerSingleton("configService", configService);
ConfigService configService = nacosConfigProperties.configServiceInstance();
if (null == configService) {
logger.warn(
@ -99,13 +60,12 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
timeout);
String applicationName = env.getProperty("spring.application.name");
logger.info("Initialize spring.application.name '" + applicationName + "'.");
String name = nacosConfigProperties.getName();
String nacosGroup = nacosConfigProperties.getGroup();
String dataIdPrefix = nacosConfigProperties.getPrefix();
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = applicationName;
dataIdPrefix = name;
}
String fileExtension = nacosConfigProperties.getFileExtension();
@ -113,23 +73,21 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME);
loadApplicationConfiguration(composite, env, nacosGroup, dataIdPrefix,
fileExtension);
loadApplicationConfiguration(composite, nacosGroup, dataIdPrefix, fileExtension);
return composite;
}
private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, Environment environment,
String nacosGroup, String dataIdPrefix, String fileExtension) {
CompositePropertySource compositePropertySource, String nacosGroup,
String dataIdPrefix, String fileExtension) {
loadNacosDataIfPresent(compositePropertySource,
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension);
for (String profile : environment.getActiveProfiles()) {
for (String profile : nacosConfigProperties.getActiveProfiles()) {
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension);
}
// todo multi profile active order and priority
}
private void loadNacosDataIfPresent(final CompositePropertySource composite,

@ -44,15 +44,6 @@ public class NacosConfigEndpointAutoConfiguration {
@Autowired
private NacosPropertySourceRepository nacosPropertySourceRepository;
@Autowired
private ConfigService configService;
@Bean
@ConditionalOnBean
public NacosConfigProperties nacosConfigProperties() {
return new NacosConfigProperties();
}
@ConditionalOnMissingBean
@Bean
public NacosConfigEndpoint nacosConfigEndpoint() {
@ -64,6 +55,7 @@ public class NacosConfigEndpointAutoConfiguration {
public NacosConfigHealthIndicator nacosConfigHealthIndicator(
NacosPropertySourceRepository nacosPropertySourceRepository) {
return new NacosConfigHealthIndicator(nacosConfigProperties,
nacosPropertySourceRepository, configService);
nacosPropertySourceRepository,
nacosConfigProperties.configServiceInstance());
}
}

@ -38,66 +38,57 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class NacosConfigAutoConfigurationTests {
private ConfigurableApplicationContext context;
@Before
public void setUp() throws Exception {
this.context = new SpringApplicationBuilder(
NacosConfigBootstrapConfiguration.class,
NacosConfigAutoConfiguration.class,
TestConfiguration.class)
.web(false).run(
"--spring.cloud.config.enabled=true",
"--spring.cloud.nacos.config.server-addr=127.0.0.1:8080",
"--spring.cloud.nacos.config.prefix=myapp");
}
@After
public void tearDown() throws Exception {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testNacosConfigProperties() {
NacosPropertySourceLocator nacosPropertySourceLocator = this.context.getBean(NacosPropertySourceLocator.class);
Environment environment = this.context.getEnvironment();
try{
nacosPropertySourceLocator.locate(environment);
}catch (Exception e){
}
NacosConfigProperties nacosConfigProperties = this.context.getBean(NacosConfigProperties.class);
assertThat(nacosConfigProperties.getFileExtension()).isEqualTo("properties");
assertThat(nacosConfigProperties.getPrefix()).isEqualTo("myapp");
}
@Test
public void testNacosRefreshProperties() {
NacosRefreshProperties nacosRefreshProperties = this.context.getBean(NacosRefreshProperties.class);
assertThat(nacosRefreshProperties.isEnabled()).isEqualTo(true);
}
@Configuration
@AutoConfigureBefore(NacosConfigAutoConfiguration.class)
static class TestConfiguration{
@Autowired
ConfigurableApplicationContext context;
@Bean
ContextRefresher contextRefresher(){
return new ContextRefresher(context, new RefreshScope());
}
}
private ConfigurableApplicationContext context;
@Before
public void setUp() throws Exception {
this.context = new SpringApplicationBuilder(
NacosConfigBootstrapConfiguration.class,
NacosConfigAutoConfiguration.class, TestConfiguration.class).web(false)
.run("--spring.application.name=myapp",
"--spring.cloud.config.enabled=true",
"--spring.cloud.nacos.config.server-addr=127.0.0.1:8080",
"--spring.cloud.nacos.config.prefix=test");
}
@After
public void tearDown() throws Exception {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testNacosConfigProperties() {
NacosConfigProperties nacosConfigProperties = this.context.getParent()
.getBean(NacosConfigProperties.class);
assertThat(nacosConfigProperties.getFileExtension()).isEqualTo("properties");
assertThat(nacosConfigProperties.getPrefix()).isEqualTo("test");
assertThat(nacosConfigProperties.getName()).isEqualTo("myapp");
}
@Test
public void testNacosRefreshProperties() {
NacosRefreshProperties nacosRefreshProperties = this.context
.getBean(NacosRefreshProperties.class);
assertThat(nacosRefreshProperties.isEnabled()).isEqualTo(true);
}
@Configuration
@AutoConfigureBefore(NacosConfigAutoConfiguration.class)
static class TestConfiguration {
@Autowired
ConfigurableApplicationContext context;
@Bean
ContextRefresher contextRefresher() {
return new ContextRefresher(context, new RefreshScope());
}
}
}

@ -42,6 +42,7 @@ public class NacosConfigBootstrapConfigurationTests {
public void setUp() throws Exception {
this.context = new SpringApplicationBuilder(
NacosConfigBootstrapConfiguration.class).web(false).run(
"--spring.application.name=true",
"--spring.cloud.config.enabled=true",
"--spring.cloud.nacos.config.server-addr=127.0.0.1:8080",
"--spring.cloud.nacos.config.prefix=myapp");
@ -67,15 +68,14 @@ public class NacosConfigBootstrapConfigurationTests {
}
Field configServiceField = ReflectionUtils
.findField(NacosPropertySourceLocator.class, "configService");
configServiceField.setAccessible(true);
Field nacosConfigPropertiesField = ReflectionUtils
.findField(NacosPropertySourceLocator.class, "nacosConfigProperties");
nacosConfigPropertiesField.setAccessible(true);
ConfigService configService = (ConfigService) ReflectionUtils
.getField(configServiceField, locator);
NacosConfigProperties configService = (NacosConfigProperties) ReflectionUtils
.getField(nacosConfigPropertiesField, locator);
assertThat(configService).isNotNull();
}
}

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -22,12 +22,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.env.Environment;
import java.util.*;
import javax.annotation.PostConstruct;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
@ -44,22 +41,11 @@ public class NacosDiscoveryClient implements DiscoveryClient {
@Autowired
private NacosDiscoveryProperties discoveryProperties;
@Autowired
private Environment environment;
private NamingService namingService;
@Override
public String description() {
return DESCRIPTION;
}
@PostConstruct
public void init() {
discoveryProperties.overrideFromEnv(environment);
namingService = discoveryProperties.getNamingService();
}
@Override
public ServiceInstance getLocalServiceInstance() {
String serviceId = discoveryProperties.getService();
@ -73,7 +59,8 @@ public class NacosDiscoveryClient implements DiscoveryClient {
@Override
public List<ServiceInstance> getInstances(String serviceId) {
try {
List<Instance> instances = namingService.getAllInstances(serviceId);
List<Instance> instances = discoveryProperties.namingServiceInstance()
.getAllInstances(serviceId);
return hostToServiceInstanceList(instances, serviceId);
}
catch (Exception e) {
@ -113,8 +100,8 @@ public class NacosDiscoveryClient implements DiscoveryClient {
public List<String> getServices() {
try {
ListView<String> services = namingService.getServicesOfServer(1,
Integer.MAX_VALUE);
ListView<String> services = discoveryProperties.namingServiceInstance()
.getServicesOfServer(1, Integer.MAX_VALUE);
return services.getData();
}
catch (Exception e) {
@ -124,6 +111,6 @@ public class NacosDiscoveryClient implements DiscoveryClient {
}
public NamingService getNamingService() {
return namingService;
return discoveryProperties.namingServiceInstance();
}
}

@ -142,6 +142,11 @@ public class NacosDiscoveryProperties {
@Autowired
private InetUtils inetUtils;
@Autowired
private Environment environment;
private NamingService namingService;
@PostConstruct
public void init() throws SocketException {
@ -180,6 +185,8 @@ public class NacosDiscoveryProperties {
}
}
this.overrideFromEnv(environment);
}
public String getEndpoint() {
@ -350,7 +357,12 @@ public class NacosDiscoveryProperties {
}
}
public NamingService getNamingService() {
public NamingService namingServiceInstance() {
if (null != namingService) {
return namingService;
}
Properties properties = new Properties();
properties.put(SERVER_ADDR, serverAddr);
properties.put(NAMESPACE, namespace);
@ -360,7 +372,8 @@ public class NacosDiscoveryProperties {
properties.put(SECRET_KEY, secretKey);
properties.put(CLUSTER_NAME, clusterName);
try {
return NacosFactory.createNamingService(properties);
namingService = NacosFactory.createNamingService(properties);
return namingService;
}
catch (Exception e) {
LOGGER.error("create naming service error!properties={},e=,", this, e);

@ -28,7 +28,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryClient;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
/**
@ -43,9 +42,6 @@ public class NacosDiscoveryEndpoint extends AbstractEndpoint<Map<String, Object>
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired
private NacosDiscoveryClient discoveryClient;
public NacosDiscoveryEndpoint() {
super("nacos_discovery", false);
}
@ -58,7 +54,7 @@ public class NacosDiscoveryEndpoint extends AbstractEndpoint<Map<String, Object>
Map<String, Object> result = new HashMap<>();
result.put("NacosDiscoveryProperties", nacosDiscoveryProperties);
NamingService namingService = discoveryClient.getNamingService();
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
List<ServiceInfo> subscribe = Collections.emptyList();
try {

@ -48,15 +48,10 @@ public class NacosRegistration implements Registration, ServiceInstance {
@Autowired
private ApplicationContext context;
private NamingService nacosNamingService;
@PostConstruct
public void init() {
Environment env = context.getEnvironment();
nacosDiscoveryProperties.overrideFromEnv(context.getEnvironment());
nacosNamingService = nacosDiscoveryProperties.getNamingService();
Integer managementPort = ManagementServerPortUtils.getPort(context);
if (null != managementPort) {
Map<String, String> metadata = nacosDiscoveryProperties.getMetadata();
@ -123,11 +118,7 @@ public class NacosRegistration implements Registration, ServiceInstance {
}
public NamingService getNacosNamingService() {
return nacosNamingService;
}
public void setNacosNamingService(NamingService nacosNamingService) {
this.nacosNamingService = nacosNamingService;
return nacosDiscoveryProperties.namingServiceInstance();
}
public void setNacosDiscoveryProperties(
@ -138,7 +129,6 @@ public class NacosRegistration implements Registration, ServiceInstance {
@Override
public String toString() {
return "NacosRegistration{" + "nacosDiscoveryProperties="
+ nacosDiscoveryProperties + ", nacosNamingService=" + nacosNamingService
+ '}';
+ nacosDiscoveryProperties + '}';
}
}

@ -0,0 +1,69 @@
<?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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
<name>Spring Cloud Alibaba Sentinel DataSource</name>
<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-extension</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-zookeeper</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,152 @@
/*
* 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.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
/**
* {@link ReadableDataSource} Loader
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public class DataSourceLoader {
private static final Logger logger = LoggerFactory.getLogger(DataSourceLoader.class);
private final static String PROPERTIES_RESOURCE_LOCATION = "META-INF/sentinel-datasource.properties";
private final static String ALL_PROPERTIES_RESOURCES_LOCATION = CLASSPATH_ALL_URL_PREFIX
+ PROPERTIES_RESOURCE_LOCATION;
private final static ConcurrentMap<String, Class<? extends ReadableDataSource>> dataSourceClassesCache
= new ConcurrentHashMap<String, Class<? extends ReadableDataSource>>(
4);
static void loadAllDataSourceClassesCache() {
Map<String, Class<? extends ReadableDataSource>> dataSourceClassesMap = loadAllDataSourceClassesCache(
ALL_PROPERTIES_RESOURCES_LOCATION);
dataSourceClassesCache.putAll(dataSourceClassesMap);
}
static Map<String, Class<? extends ReadableDataSource>> loadAllDataSourceClassesCache(
String resourcesLocation) {
Map<String, Class<? extends ReadableDataSource>> dataSourcesMap
= new HashMap<String, Class<? extends ReadableDataSource>>(
4);
ClassLoader classLoader = DataSourceLoader.class.getClassLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources(resourcesLocation);
for (Resource resource : resources) {
if (resource.exists()) {
Properties properties = PropertiesLoaderUtils
.loadProperties(resource);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String type = (String)entry.getKey();
String className = (String)entry.getValue();
if (!ClassUtils.isPresent(className, classLoader)) {
if (logger.isDebugEnabled()) {
logger.debug(
"Sentinel DataSource implementation [ type : "
+ type + ": , class : " + className
+ " , url : " + resource.getURL()
+ "] was not present in current classpath , "
+ "thus loading will be ignored , please add dependency if required !");
}
continue;
}
Assert.isTrue(!dataSourcesMap.containsKey(type),
"The duplicated type[" + type
+ "] of SentinelDataSource were found in "
+ "resource [" + resource.getURL() + "]");
Class<?> dataSourceClass = ClassUtils.resolveClassName(className,
classLoader);
Assert.isAssignable(ReadableDataSource.class, dataSourceClass);
dataSourcesMap.put(type,
(Class<? extends ReadableDataSource>)dataSourceClass);
if (logger.isDebugEnabled()) {
logger.debug("Sentinel DataSource implementation [ type : "
+ type + ": , class : " + className
+ "] was loaded.");
}
}
}
}
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
}
return dataSourcesMap;
}
public static Class<? extends ReadableDataSource> loadClass(String type)
throws IllegalArgumentException {
Class<? extends ReadableDataSource> dataSourceClass = dataSourceClassesCache.get(type);
if (dataSourceClass == null) {
if (dataSourceClassesCache.isEmpty()) {
loadAllDataSourceClassesCache();
dataSourceClass = dataSourceClassesCache.get(type);
}
}
if (dataSourceClass == null) {
throw new IllegalArgumentException(
"Sentinel DataSource implementation [ type : " + type
+ " ] can't be found!");
}
return dataSourceClass;
}
}

@ -0,0 +1,33 @@
/*
* 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;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public interface SentinelDataSourceConstants {
String PROPERTY_PREFIX = "spring.cloud.sentinel";
String PROPERTY_ITEM_SEPARATOR = ".";
String PROPERTY_DATASOURCE_NAME = "datasource";
String PROPERTY_DATASOURCE_PREFIX = PROPERTY_PREFIX + PROPERTY_ITEM_SEPARATOR
+ PROPERTY_DATASOURCE_NAME;
}

@ -0,0 +1,278 @@
/*
* 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.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.property.SentinelProperty;
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.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cloud.alibaba.sentinel.datasource.annotation.SentinelDataSource;
import org.springframework.cloud.alibaba.sentinel.datasource.util.PropertySourcesUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
/**
* {@link SentinelDataSource @SentinelDataSource} Post Processor
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see ReadableDataSource
* @see SentinelDataSource
*/
public class SentinelDataSourcePostProcessor
extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor {
private static final Logger logger = LoggerFactory
.getLogger(SentinelDataSourcePostProcessor.class);
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ConfigurableEnvironment environment;
private final Map<String, List<SentinelDataSourceField>> dataSourceFieldCache = new ConcurrentHashMap<>(
64);
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, final String beanName) {
// find all fields using by @SentinelDataSource annotation
ReflectionUtils.doWithFields(beanType, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
SentinelDataSource annotation = getAnnotation(field,
SentinelDataSource.class);
if (annotation != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn(
"@SentinelDataSource annotation is not supported on static fields: "
+ field);
}
return;
}
if (dataSourceFieldCache.containsKey(beanName)) {
dataSourceFieldCache.get(beanName)
.add(new SentinelDataSourceField(annotation, field));
} else {
List<SentinelDataSourceField> list = new ArrayList<>();
list.add(new SentinelDataSourceField(annotation, field));
dataSourceFieldCache.put(beanName, list);
}
}
}
});
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeanCreationException {
if (dataSourceFieldCache.containsKey(beanName)) {
List<SentinelDataSourceField> sentinelDataSourceFields = dataSourceFieldCache
.get(beanName);
for (SentinelDataSourceField sentinelDataSourceField : sentinelDataSourceFields) {
try {
// construct DataSource field annotated by @SentinelDataSource
Field field = sentinelDataSourceField.getField();
ReflectionUtils.makeAccessible(field);
String dataSourceBeanName = constructDataSource(
sentinelDataSourceField.getSentinelDataSource());
field.set(bean, applicationContext.getBean(dataSourceBeanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return pvs;
}
private String constructDataSource(SentinelDataSource annotation) {
String prefix = annotation.value();
if (StringUtils.isEmpty(prefix)) {
prefix = SentinelDataSourceConstants.PROPERTY_DATASOURCE_PREFIX;
}
Map<String, Object> propertyMap = PropertySourcesUtils
.getSubProperties(environment.getPropertySources(), prefix);
String alias = propertyMap.get("type").toString();
Class dataSourceClass = DataSourceLoader.loadClass(alias);
String beanName = StringUtils.isEmpty(annotation.name())
? StringUtils.uncapitalize(dataSourceClass.getSimpleName()) + "_" + prefix
: annotation.name();
if (applicationContext.containsBean(beanName)) {
return beanName;
}
Class targetClass = null;
// if alias exists in SentinelDataSourceRegistry, wired properties into
// FactoryBean
if (SentinelDataSourceRegistry.checkFactoryBean(alias)) {
targetClass = SentinelDataSourceRegistry.getFactoryBean(alias);
} else {
// if alias not exists in SentinelDataSourceRegistry, wired properties into
// raw class
targetClass = dataSourceClass;
}
registerDataSource(beanName, targetClass, propertyMap);
return beanName;
}
private void registerDataSource(String beanName, Class targetClass,
Map<String, Object> propertyMap) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(targetClass);
for (String propertyName : propertyMap.keySet()) {
Field field = ReflectionUtils.findField(targetClass, propertyName);
if (field != null) {
if (field.getType().isAssignableFrom(Converter.class)) {
// Converter get from ApplicationContext
builder.addPropertyReference(propertyName,
propertyMap.get(propertyName).toString());
} else {
// wired properties
builder.addPropertyValue(propertyName, propertyMap.get(propertyName));
}
}
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)applicationContext
.getAutowireCapableBeanFactory();
beanFactory.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
@EventListener(classes = ApplicationReadyEvent.class)
public void appStartedListener(ApplicationReadyEvent event) throws Exception {
logger.info("[Sentinel Starter] Start to find ReadableDataSource");
Map<String, ReadableDataSource> dataSourceMap = event.getApplicationContext().getBeansOfType(
ReadableDataSource.class);
if (dataSourceMap.size() == 1) {
logger.info("[Sentinel Starter] There exists only one ReadableDataSource named {}, start to load rules",
dataSourceMap.keySet().iterator().next());
ReadableDataSource dataSource = dataSourceMap.values().iterator().next();
Object ruleConfig = dataSource.loadConfig();
SentinelProperty sentinelProperty = dataSource.getProperty();
Integer rulesNum;
if ((rulesNum = checkRuleType(ruleConfig, FlowRule.class)) > 0) {
FlowRuleManager.register2Property(sentinelProperty);
logger.info("[Sentinel Starter] load {} flow rules", rulesNum);
}
if ((rulesNum = checkRuleType(ruleConfig, DegradeRule.class)) > 0) {
DegradeRuleManager.register2Property(sentinelProperty);
logger.info("[Sentinel Starter] load {} degrade rules", rulesNum);
}
if ((rulesNum = checkRuleType(ruleConfig, SystemRule.class)) > 0) {
SystemRuleManager.register2Property(sentinelProperty);
logger.info("[Sentinel Starter] load {} system rules", rulesNum);
}
if ((rulesNum = checkRuleType(ruleConfig, AuthorityRule.class)) > 0) {
AuthorityRuleManager.register2Property(sentinelProperty);
logger.info("[Sentinel Starter] load {} authority rules", rulesNum);
}
} else if (dataSourceMap.size() > 1) {
logger.warn(
"[Sentinel Starter] There exists more than one ReadableDataSource, can not choose which one to load");
} else {
logger.warn(
"[Sentinel Starter] No ReadableDataSource exists");
}
}
private Integer checkRuleType(Object ruleConfig, Class type) {
if (ruleConfig.getClass() == type) {
return 1;
} else if (ruleConfig instanceof List) {
List ruleList = (List)ruleConfig;
List checkList = new ArrayList();
for (Object rule : ruleList) {
if (rule.getClass() == type) {
checkList.add(rule);
}
}
if (ruleList.size() == checkList.size()) {
return ruleList.size();
}
}
return -1;
}
class SentinelDataSourceField {
private SentinelDataSource sentinelDataSource;
private Field field;
public SentinelDataSourceField(SentinelDataSource sentinelDataSource,
Field field) {
this.sentinelDataSource = sentinelDataSource;
this.field = field;
}
public SentinelDataSource getSentinelDataSource() {
return sentinelDataSource;
}
public void setSentinelDataSource(SentinelDataSource sentinelDataSource) {
this.sentinelDataSource = sentinelDataSource;
}
public Field getField() {
return field;
}
public void setField(Field field) {
this.field = field;
}
}
}

@ -16,7 +16,7 @@
package org.springframework.cloud.alibaba.sentinel.datasource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
@ -29,7 +29,7 @@ import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.Zookeep
/**
* Registry to save DataSource FactoryBean
*
* @author fangjian
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see ReadableDataSource
* @see FileRefreshableDataSourceFactoryBean
* @see ZookeeperDataSourceFactoryBean
@ -38,7 +38,7 @@ import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.Zookeep
*/
public class SentinelDataSourceRegistry {
private static ConcurrentHashMap<String, Class<? extends FactoryBean>> cache = new ConcurrentHashMap<>(
private static HashMap<String, Class<? extends FactoryBean>> cache = new HashMap<>(
32);
static {
@ -54,7 +54,6 @@ public class SentinelDataSourceRegistry {
public static synchronized void registerFactoryBean(String alias,
Class<? extends FactoryBean> clazz) {
cache.putIfAbsent(alias, clazz);
cache.put(alias, clazz);
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.alibaba.sentinel.annotation;
package org.springframework.cloud.alibaba.sentinel.datasource.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -31,7 +31,7 @@ import org.springframework.core.annotation.AliasFor;
* into a Spring Bean. The Properties of DataSource bean get from config files with
* specific prefix.
*
* @author fangjian
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see ReadableDataSource
*/
@Target({ElementType.FIELD})

@ -1,12 +1,14 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import org.springframework.beans.factory.FactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* @author fangjian
* A {@link FactoryBean} for creating {@link ApolloDataSource} instance.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see ApolloDataSource
*/
public class ApolloDataSourceFactoryBean implements FactoryBean<ApolloDataSource> {
@ -19,7 +21,7 @@ public class ApolloDataSourceFactoryBean implements FactoryBean<ApolloDataSource
@Override
public ApolloDataSource getObject() throws Exception {
return new ApolloDataSource(namespaceName, flowRulesKey, defaultFlowRuleValue,
converter);
converter);
}
@Override

@ -3,13 +3,15 @@ package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.io.File;
import java.nio.charset.Charset;
import org.springframework.beans.factory.FactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* @author fangjian
* A {@link FactoryBean} for creating {@link FileRefreshableDataSource} instance.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see FileRefreshableDataSource
*/
public class FileRefreshableDataSourceFactoryBean implements FactoryBean<FileRefreshableDataSource> {
@ -23,7 +25,7 @@ public class FileRefreshableDataSourceFactoryBean implements FactoryBean<FileRef
@Override
public FileRefreshableDataSource getObject() throws Exception {
return new FileRefreshableDataSource(new File(file), converter,
recommendRefreshMs, bufSize, Charset.forName(charset));
recommendRefreshMs, bufSize, Charset.forName(charset));
}
@Override

@ -1,12 +1,14 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import org.springframework.beans.factory.FactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* @author fangjian
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see NacosDataSource
*/
public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {

@ -0,0 +1,86 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.FactoryBean;
/**
* A {@link FactoryBean} for creating {@link ZookeeperDataSource} instance.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see ZookeeperDataSource
*/
public class ZookeeperDataSourceFactoryBean implements FactoryBean<ZookeeperDataSource> {
private String serverAddr;
private String path;
private String groupId;
private String dataId;
private Converter converter;
@Override
public ZookeeperDataSource getObject() throws Exception {
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
// the path will be /{groupId}/{dataId}
return new ZookeeperDataSource(serverAddr, groupId, dataId, converter);
} else {
// using path directly
return new ZookeeperDataSource(serverAddr, path, converter);
}
}
@Override
public Class<?> getObjectType() {
return ZookeeperDataSource.class;
}
@Override
public boolean isSingleton() {
return true;
}
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
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;
}
}

@ -14,16 +14,16 @@
* limitations under the License.
*/
package org.springframework.cloud.alibaba.sentinel.util;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
package org.springframework.cloud.alibaba.sentinel.datasource.util;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
/**
* {@link PropertySources} Utilities
*
@ -47,7 +47,7 @@ public abstract class PropertySourcesUtils {
for (PropertySource<?> source : propertySources) {
if (source instanceof EnumerablePropertySource) {
for (String name : ((EnumerablePropertySource<?>) source).getPropertyNames()) {
for (String name : ((EnumerablePropertySource<?>)source).getPropertyNames()) {
if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
String subName = name.substring(normalizedPrefix.length());
if (!subProperties.containsKey(subName)) { // take first one

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -27,35 +27,17 @@
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-extension</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-zookeeper</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
<optional>true</optional>
<artifactId>sentinel-annotation-aspectj</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<artifactId>sentinel-dubbo-adapter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency>
<!--spring boot-->

@ -23,11 +23,4 @@ public interface SentinelConstants {
String PROPERTY_PREFIX = "spring.cloud.sentinel";
String PROPERTY_ITEM_SEPARATOR = ".";
String PROPERTY_DATASOURCE_NAME = "datasource";
String PROPERTY_DATASOURCE_PREFIX = PROPERTY_PREFIX + PROPERTY_ITEM_SEPARATOR
+ PROPERTY_DATASOURCE_NAME;
}

@ -1,152 +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 static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
/**
* {@link ReadableDataSource} Loader
*
* @author fangjian
*/
public class DataSourceLoader {
private static final Logger logger = LoggerFactory.getLogger(DataSourceLoader.class);
private final static String PROPERTIES_RESOURCE_LOCATION = "META-INF/sentinel-datasource.properties";
private final static String ALL_PROPERTIES_RESOURCES_LOCATION = CLASSPATH_ALL_URL_PREFIX
+ PROPERTIES_RESOURCE_LOCATION;
private final static ConcurrentMap<String, Class<? extends ReadableDataSource>> dataSourceClassesCache = new ConcurrentHashMap<String, Class<? extends ReadableDataSource>>(
4);
static void loadAllDataSourceClassesCache() {
Map<String, Class<? extends ReadableDataSource>> dataSourceClassesMap = loadAllDataSourceClassesCache(
ALL_PROPERTIES_RESOURCES_LOCATION);
dataSourceClassesCache.putAll(dataSourceClassesMap);
}
static Map<String, Class<? extends ReadableDataSource>> loadAllDataSourceClassesCache(
String resourcesLocation) {
Map<String, Class<? extends ReadableDataSource>> dataSourcesMap = new HashMap<String, Class<? extends ReadableDataSource>>(
4);
ClassLoader classLoader = DataSourceLoader.class.getClassLoader();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources(resourcesLocation);
for (Resource resource : resources) {
if (resource.exists()) {
Properties properties = PropertiesLoaderUtils
.loadProperties(resource);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String type = (String) entry.getKey();
String className = (String) entry.getValue();
if (!ClassUtils.isPresent(className, classLoader)) {
if (logger.isDebugEnabled()) {
logger.debug(
"Sentinel DataSource implementation [ type : "
+ type + ": , class : " + className
+ " , url : " + resource.getURL()
+ "] was not present in current classpath , "
+ "thus loading will be ignored , please add dependency if required !");
}
continue;
}
Assert.isTrue(!dataSourcesMap.containsKey(type),
"The duplicated type[" + type
+ "] of SentinelDataSource were found in "
+ "resource [" + resource.getURL() + "]");
Class<?> dataSourceClass = ClassUtils.resolveClassName(className,
classLoader);
Assert.isAssignable(ReadableDataSource.class, dataSourceClass);
dataSourcesMap.put(type,
(Class<? extends ReadableDataSource>) dataSourceClass);
if (logger.isDebugEnabled()) {
logger.debug("Sentinel DataSource implementation [ type : "
+ type + ": , class : " + className
+ "] was loaded.");
}
}
}
}
}
catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
}
return dataSourcesMap;
}
public static Class<? extends ReadableDataSource> loadClass(String type)
throws IllegalArgumentException {
Class<? extends ReadableDataSource> dataSourceClass = dataSourceClassesCache
.get(type);
if (dataSourceClass == null) {
if (dataSourceClassesCache.isEmpty()) {
loadAllDataSourceClassesCache();
dataSourceClass = dataSourceClassesCache.get(type);
}
}
if (dataSourceClass == null) {
throw new IllegalArgumentException(
"Sentinel DataSource implementation [ type : " + type
+ " ] can't be found!");
}
return dataSourceClass;
}
}

@ -1,217 +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 static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.cloud.alibaba.sentinel.SentinelConstants;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelDataSource;
import org.springframework.cloud.alibaba.sentinel.util.PropertySourcesUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
/**
* {@link SentinelDataSource @SentinelDataSource} Post Processor
*
* @author fangjian
* @see com.alibaba.csp.sentinel.datasource.ReadableDataSource
* @see SentinelDataSource
*/
public class SentinelDataSourcePostProcessor
extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor {
private static final Logger logger = LoggerFactory
.getLogger(SentinelDataSourcePostProcessor.class);
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ConfigurableEnvironment environment;
private final Map<String, List<SentinelDataSourceField>> dataSourceFieldCache = new ConcurrentHashMap<>(
64);
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, final String beanName) {
// find all fields using by @SentinelDataSource annotation
ReflectionUtils.doWithFields(beanType, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
SentinelDataSource annotation = getAnnotation(field,
SentinelDataSource.class);
if (annotation != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn(
"@SentinelDataSource annotation is not supported on static fields: "
+ field);
}
return;
}
if (dataSourceFieldCache.containsKey(beanName)) {
dataSourceFieldCache.get(beanName)
.add(new SentinelDataSourceField(annotation, field));
}
else {
List<SentinelDataSourceField> list = new ArrayList<>();
list.add(new SentinelDataSourceField(annotation, field));
dataSourceFieldCache.put(beanName, list);
}
}
}
});
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeanCreationException {
if (dataSourceFieldCache.containsKey(beanName)) {
List<SentinelDataSourceField> sentinelDataSourceFields = dataSourceFieldCache
.get(beanName);
for (SentinelDataSourceField sentinelDataSourceField : sentinelDataSourceFields) {
try {
// construct DataSource field annotated by @SentinelDataSource
Field field = sentinelDataSourceField.getField();
ReflectionUtils.makeAccessible(field);
String dataSourceBeanName = constructDataSource(
sentinelDataSourceField.getSentinelDataSource());
field.set(bean, applicationContext.getBean(dataSourceBeanName));
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
return pvs;
}
private String constructDataSource(SentinelDataSource annotation) {
String prefix = annotation.value();
if (StringUtils.isEmpty(prefix)) {
prefix = SentinelConstants.PROPERTY_DATASOURCE_PREFIX;
}
Map<String, Object> propertyMap = PropertySourcesUtils
.getSubProperties(environment.getPropertySources(), prefix);
String alias = propertyMap.get("type").toString();
Class dataSourceClass = DataSourceLoader.loadClass(alias);
String beanName = StringUtils.isEmpty(annotation.name())
? StringUtils.uncapitalize(dataSourceClass.getSimpleName()) + "_" + prefix
: annotation.name();
if (applicationContext.containsBean(beanName)) {
return beanName;
}
Class targetClass = null;
// if alias exists in SentinelDataSourceRegistry, wired properties into
// FactoryBean
if (SentinelDataSourceRegistry.checkFactoryBean(alias)) {
targetClass = SentinelDataSourceRegistry.getFactoryBean(alias);
}
else {
// if alias not exists in SentinelDataSourceRegistry, wired properties into
// raw class
targetClass = dataSourceClass;
}
registerDataSource(beanName, targetClass, propertyMap);
return beanName;
}
private void registerDataSource(String beanName, Class targetClass,
Map<String, Object> propertyMap) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(targetClass);
for (String propertyName : propertyMap.keySet()) {
Field field = ReflectionUtils.findField(targetClass, propertyName);
if (field != null) {
if (field.getType().isAssignableFrom(Converter.class)) {
// Converter get from ApplicationContext
builder.addPropertyReference(propertyName,
propertyMap.get(propertyName).toString());
}
else {
// wired properties
builder.addPropertyValue(propertyName, propertyMap.get(propertyName));
}
}
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
.getAutowireCapableBeanFactory();
beanFactory.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
class SentinelDataSourceField {
private SentinelDataSource sentinelDataSource;
private Field field;
public SentinelDataSourceField(SentinelDataSource sentinelDataSource,
Field field) {
this.sentinelDataSource = sentinelDataSource;
this.field = field;
}
public SentinelDataSource getSentinelDataSource() {
return sentinelDataSource;
}
public void setSentinelDataSource(SentinelDataSource sentinelDataSource) {
this.sentinelDataSource = sentinelDataSource;
}
public Field getField() {
return field;
}
public void setField(Field field) {
this.field = field;
}
}
}

@ -1,85 +0,0 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.FactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
/**
* @author fangjian
* @see ZookeeperDataSource
*/
public class ZookeeperDataSourceFactoryBean implements FactoryBean<ZookeeperDataSource> {
private String serverAddr;
private String path;
private String groupId;
private String dataId;
private Converter converter;
@Override
public ZookeeperDataSource getObject() throws Exception {
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
// the path will be /{groupId}/{dataId}
return new ZookeeperDataSource(serverAddr, groupId, dataId, converter);
}
else {
// using path directly
return new ZookeeperDataSource(serverAddr, path, converter);
}
}
@Override
public Class<?> getObjectType() {
return ZookeeperDataSource.class;
}
@Override
public boolean isSingleton() {
return true;
}
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
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;
}
}

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-test</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-test</artifactId>
<version>0.1.0</version>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

@ -0,0 +1,71 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-alicloud-acm</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-context</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-edas</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.edas.acm</groupId>
<artifactId>acm-sdk</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,75 @@
/*
* 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.acm;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.alicloud.acm.endpoint.AcmHealthIndicator;
import org.springframework.cloud.alicloud.acm.refresh.AcmContextRefresher;
import org.springframework.cloud.alicloud.acm.refresh.AcmRefreshHistory;
import org.springframework.cloud.alicloud.context.acm.AcmIntegrationProperties;
import org.springframework.cloud.alicloud.context.acm.AcmProperties;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.taobao.diamond.client.Diamond;
/**
* Created on 01/10/2017.
*
* @author juven.xuxb
*/
@Configuration
@ConditionalOnClass({ Diamond.class })
public class AcmAutoConfiguration implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Bean
public AcmPropertySourceRepository acmPropertySourceRepository() {
return new AcmPropertySourceRepository(applicationContext);
}
@Bean
public AcmHealthIndicator acmHealthIndicator(AcmProperties acmProperties,
AcmPropertySourceRepository acmPropertySourceRepository) {
return new AcmHealthIndicator(acmProperties, acmPropertySourceRepository);
}
@Bean
public AcmRefreshHistory acmRefreshHistory() {
return new AcmRefreshHistory();
}
@Bean
public AcmContextRefresher acmContextRefresher(
AcmIntegrationProperties acmIntegrationProperties,
ContextRefresher contextRefresher, AcmRefreshHistory refreshHistory,
AcmPropertySourceRepository propertySourceRepository) {
return new AcmContextRefresher(contextRefresher, acmIntegrationProperties,
refreshHistory, propertySourceRepository);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}

@ -0,0 +1,68 @@
/*
* 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.acm;
import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import java.util.ArrayList;
import java.util.List;
/**
* @author juven.xuxb, 5/17/16.
*/
public class AcmPropertySourceRepository {
private final ApplicationContext applicationContext;
public AcmPropertySourceRepository(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* get all acm properties from application context
* @return
*/
public List<AcmPropertySource> getAll() {
List<AcmPropertySource> result = new ArrayList<>();
ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) applicationContext;
for (PropertySource p : ctx.getEnvironment().getPropertySources()) {
if (p instanceof AcmPropertySource) {
result.add((AcmPropertySource) p);
}
else if (p instanceof CompositePropertySource) {
collectAcmPropertySources((CompositePropertySource) p, result);
}
}
return result;
}
private void collectAcmPropertySources(CompositePropertySource composite,
List<AcmPropertySource> result) {
for (PropertySource p : composite.getPropertySources()) {
if (p instanceof AcmPropertySource) {
result.add((AcmPropertySource) p);
}
else if (p instanceof CompositePropertySource) {
collectAcmPropertySources((CompositePropertySource) p, result);
}
}
}
}

@ -0,0 +1,55 @@
/*
* 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.acm.bootstrap;
import org.springframework.core.env.MapPropertySource;
import java.util.Date;
import java.util.Map;
/**
* @author juven.xuxb
* @author xiaolongzuo
*/
public class AcmPropertySource extends MapPropertySource {
private final String dataId;
private final Date timestamp;
private final boolean groupLevel;
AcmPropertySource(String dataId, Map<String, Object> source, Date timestamp,
boolean groupLevel) {
super(dataId, source);
this.dataId = dataId;
this.timestamp = timestamp;
this.groupLevel = groupLevel;
}
public String getDataId() {
return dataId;
}
public Date getTimestamp() {
return timestamp;
}
public boolean isGroupLevel() {
return groupLevel;
}
}

@ -0,0 +1,96 @@
/*
* 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.acm.bootstrap;
import com.alibaba.edas.acm.ConfigService;
import com.alibaba.edas.acm.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.util.StringUtils;
import java.io.StringReader;
import java.util.*;
/**
* @author juven.xuxb
* @author xiaolongzuo
*/
class AcmPropertySourceBuilder {
private Logger logger = LoggerFactory.getLogger(AcmPropertySourceBuilder.class);
/**
* ACM DataId groupID AcmProperty
*
* @param dataId
* @param diamondGroup
* @param groupLevel
* @return
*/
AcmPropertySource build(String dataId, String diamondGroup, boolean groupLevel) {
Properties properties = loadDiamondData(dataId, diamondGroup);
if (properties == null) {
return null;
}
return new AcmPropertySource(dataId, toMap(properties), new Date(), groupLevel);
}
private Properties loadDiamondData(String dataId, String diamondGroup) {
try {
String data = ConfigService.getConfig(dataId, diamondGroup, 3000L);
if (StringUtils.isEmpty(data)) {
return null;
}
if (dataId.endsWith(".properties")) {
Properties properties = new Properties();
logger.info(String.format("Loading acm data, dataId: '%s', group: '%s'",
dataId, diamondGroup));
properties.load(new StringReader(data));
return properties;
} else if (dataId.endsWith(".yaml") || dataId.endsWith(".yml")) {
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
yamlFactory.setResources(new ByteArrayResource(data.getBytes()));
return yamlFactory.getObject();
}
} catch (Exception e) {
if (e instanceof ConfigException) {
logger.error("DIAMOND-100500:" + dataId + ", " + e.toString(), e);
} else {
logger.error("DIAMOND-100500:" + dataId, e);
}
}
return null;
}
@SuppressWarnings("unchecked")
private Map<String, Object> toMap(Properties properties) {
Map<String, Object> result = new HashMap<>();
Enumeration<String> keys = (Enumeration<String>)properties.propertyNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
Object value = properties.getProperty(key);
if (value != null) {
result.put(key, ((String)value).trim());
} else {
result.put(key, null);
}
}
return result;
}
}

@ -0,0 +1,69 @@
/*
* 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.acm.bootstrap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alicloud.context.acm.AcmIntegrationProperties;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
/**
* @author juven.xuxb
* @author xiaolongzuo
*/
public class AcmPropertySourceLocator implements PropertySourceLocator {
private static final String DIAMOND_PROPERTY_SOURCE_NAME = "diamond";
private static String defaultDiamondGroup = "DEFAULT_GROUP";
private AcmPropertySourceBuilder acmPropertySourceBuilder = new AcmPropertySourceBuilder();
@Autowired
private AcmIntegrationProperties acmIntegrationProperties;
@Override
public PropertySource<?> locate(Environment environment) {
CompositePropertySource compositePropertySource = new CompositePropertySource(
DIAMOND_PROPERTY_SOURCE_NAME);
for (String dataId : acmIntegrationProperties.getGroupConfigurationDataIds()) {
loadDiamondDataIfPresent(compositePropertySource, dataId, defaultDiamondGroup,
true);
}
for (String dataId : acmIntegrationProperties
.getApplicationConfigurationDataIds()) {
loadDiamondDataIfPresent(compositePropertySource, dataId, defaultDiamondGroup,
false);
}
return compositePropertySource;
}
private void loadDiamondDataIfPresent(final CompositePropertySource composite,
final String dataId, final String diamondGroup, final boolean groupLevel) {
AcmPropertySource ps = acmPropertySourceBuilder.build(dataId, diamondGroup,
groupLevel);
if (ps != null) {
composite.addFirstPropertySource(ps);
}
}
}

@ -0,0 +1,40 @@
/*
* 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.acm.diagnostics.analyzer;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
/**
* A {@code FailureAnalyzer} that performs analysis of failures caused by a
* {@code DiamondConnectionFailureException}.
*
* @author juven.xuxb, 07/11/2016.
*/
public class DiamondConnectionFailureAnalyzer
extends AbstractFailureAnalyzer<DiamondConnectionFailureException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure,
DiamondConnectionFailureException cause) {
return new FailureAnalysis(
"Application failed to connect to Diamond, unable to access http://"
+ cause.getDomain() + ":" + cause.getPort()
+ "/diamond-server/diamond",
"config the right endpoint", cause);
}
}

@ -0,0 +1,52 @@
/*
* 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.acm.diagnostics.analyzer;
/**
* A {@code DiamondConnectionFailureException} is thrown when the application fails to
* connect to Diamond Server.
*
* @author juven.xuxb, 07/11/2016.
*/
public class DiamondConnectionFailureException extends RuntimeException {
private final String domain;
private final String port;
public DiamondConnectionFailureException(String domain, String port, String message) {
super(message);
this.domain = domain;
this.port = port;
}
public DiamondConnectionFailureException(String domain, String port, String message,
Throwable cause) {
super(message, cause);
this.domain = domain;
this.port = port;
}
String getDomain() {
return domain;
}
String getPort() {
return port;
}
}

@ -0,0 +1,76 @@
/*
* 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.acm.endpoint;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository;
import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource;
import org.springframework.cloud.alicloud.acm.refresh.AcmRefreshHistory;
import org.springframework.cloud.alicloud.context.acm.AcmProperties;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created on 01/10/2017.
*
* @author juven.xuxb
*/
public class AcmEndpoint extends AbstractEndpoint<Map<String, Object>> {
private final AcmProperties properties;
private final AcmRefreshHistory refreshHistory;
private final AcmPropertySourceRepository propertySourceRepository;
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public AcmEndpoint(AcmProperties properties, AcmRefreshHistory refreshHistory,
AcmPropertySourceRepository propertySourceRepository) {
super("acm", false);
this.properties = properties;
this.refreshHistory = refreshHistory;
this.propertySourceRepository = propertySourceRepository;
}
@Override
public Map<String, Object> invoke() {
Map<String, Object> result = new HashMap<>();
result.put("config", properties);
Map<String, Object> runtime = new HashMap<>();
List<AcmPropertySource> all = propertySourceRepository.getAll();
List<Map<String, Object>> sources = new ArrayList<>();
for (AcmPropertySource ps : all) {
Map<String, Object> source = new HashMap<>();
source.put("dataId", ps.getDataId());
source.put("lastSynced", dateFormat.format(ps.getTimestamp()));
sources.add(source);
}
runtime.put("sources", sources);
runtime.put("refreshHistory", refreshHistory.getRecords());
result.put("runtime", runtime);
return result;
}
}

@ -0,0 +1,50 @@
/*
* 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.acm.endpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository;
import org.springframework.cloud.alicloud.acm.refresh.AcmRefreshHistory;
import org.springframework.cloud.alicloud.context.acm.AcmProperties;
import org.springframework.context.annotation.Bean;
/**
* @author xiaojing
*/
@ConditionalOnWebApplication
@ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.AbstractEndpoint")
public class AcmEndpointAutoConfiguration {
@Autowired
private AcmProperties acmProperties;
@Autowired
private AcmRefreshHistory acmRefreshHistory;
@Autowired
private AcmPropertySourceRepository acmPropertySourceRepository;
@ConditionalOnMissingBean
@Bean
public AcmEndpoint acmEndpoint() {
return new AcmEndpoint(acmProperties, acmRefreshHistory,
acmPropertySourceRepository);
}
}

@ -0,0 +1,71 @@
/*
* 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.acm.endpoint;
import com.alibaba.edas.acm.ConfigService;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository;
import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource;
import org.springframework.cloud.alicloud.context.acm.AcmProperties;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @author leijuan
* @author juven
*/
public class AcmHealthIndicator extends AbstractHealthIndicator {
private final AcmProperties acmProperties;
private final AcmPropertySourceRepository acmPropertySourceRepository;
private final List<String> dataIds;
public AcmHealthIndicator(AcmProperties acmProperties,
AcmPropertySourceRepository acmPropertySourceRepository) {
this.acmProperties = acmProperties;
this.acmPropertySourceRepository = acmPropertySourceRepository;
this.dataIds = new ArrayList<>();
for (AcmPropertySource acmPropertySource : this.acmPropertySourceRepository
.getAll()) {
this.dataIds.add(acmPropertySource.getDataId());
}
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
for (String dataId : dataIds) {
try {
String config = ConfigService.getConfig(dataId, acmProperties.getGroup(),
acmProperties.getTimeout());
if (StringUtils.isEmpty(config)) {
builder.down().withDetail(String.format("dataId: '%s', group: '%s'",
dataId, acmProperties.getGroup()), "config is empty");
}
} catch (Exception e) {
builder.down().withDetail(String.format("dataId: '%s', group: '%s'",
dataId, acmProperties.getGroup()), e.getMessage());
}
}
builder.up().withDetail("dataIds", dataIds);
}
}

@ -0,0 +1,123 @@
/*
* 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.acm.refresh;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository;
import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySource;
import org.springframework.cloud.alicloud.context.acm.AcmIntegrationProperties;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.ApplicationListener;
import org.springframework.util.StringUtils;
import com.alibaba.edas.acm.ConfigService;
import com.alibaba.edas.acm.listener.ConfigChangeListener;
/**
* On application start up, AcmContextRefresher add diamond listeners to all application
* level dataIds, when there is a change in the data, listeners will refresh
* configurations.
*
* @author juven.xuxb, 5/13/16.
*/
public class AcmContextRefresher implements ApplicationListener<ApplicationReadyEvent> {
private Logger logger = LoggerFactory.getLogger(AcmContextRefresher.class);
private final ContextRefresher contextRefresher;
private final AcmIntegrationProperties acmIntegrationProperties;
private final AcmRefreshHistory refreshHistory;
private final AcmPropertySourceRepository acmPropertySourceRepository;
private Map<String, ConfigChangeListener> listenerMap = new ConcurrentHashMap<>(16);
public AcmContextRefresher(ContextRefresher contextRefresher,
AcmIntegrationProperties acmIntegrationProperties,
AcmRefreshHistory refreshHistory,
AcmPropertySourceRepository acmPropertySourceRepository) {
this.contextRefresher = contextRefresher;
this.acmIntegrationProperties = acmIntegrationProperties;
this.refreshHistory = refreshHistory;
this.acmPropertySourceRepository = acmPropertySourceRepository;
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
this.registerDiamondListenersForApplications();
}
private void registerDiamondListenersForApplications() {
if (acmIntegrationProperties.getAcmProperties().isRefreshEnabled()) {
for (AcmPropertySource acmPropertySource : acmPropertySourceRepository
.getAll()) {
if (acmPropertySource.isGroupLevel()) {
continue;
}
String dataId = acmPropertySource.getDataId();
registerDiamondListener(dataId);
}
if (acmPropertySourceRepository.getAll().isEmpty()) {
registerDiamondListener(acmIntegrationProperties
.getApplicationConfigurationDataIdWithoutGroup());
}
}
}
private void registerDiamondListener(final String dataId) {
ConfigChangeListener listener = listenerMap.get(dataId);
if (listener == null) {
listener = new ConfigChangeListener() {
@Override
public void receiveConfigInfo(String configInfo) {
String md5 = "";
if (!StringUtils.isEmpty(configInfo)) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md5 = new BigInteger(1,
md.digest(configInfo.getBytes("UTF-8"))).toString(16);
}
catch (NoSuchAlgorithmException
| UnsupportedEncodingException e) {
logger.warn("unable to get md5 for dataId: " + dataId, e);
}
}
refreshHistory.add(dataId, md5);
contextRefresher.refresh();
}
};
listenerMap.put(dataId, listener);
}
ConfigService.addListener(dataId,
acmIntegrationProperties.getAcmProperties().getGroup(), listener);
}
}

@ -0,0 +1,72 @@
/*
* 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.acm.refresh;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
/**
* @author juven.xuxb, 5/16/16.
*/
public class AcmRefreshHistory {
private static final int MAX_SIZE = 20;
private LinkedList<Record> records = new LinkedList<>();
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void add(String dataId, String md5) {
records.addFirst(new Record(dateFormat.format(new Date()), dataId, md5));
if (records.size() > MAX_SIZE) {
records.removeLast();
}
}
public LinkedList<Record> getRecords() {
return records;
}
}
class Record {
private final String timestamp;
private final String dataId;
private final String md5;
public Record(String timestamp, String dataId, String md5) {
this.timestamp = timestamp;
this.dataId = dataId;
this.md5 = md5;
}
public String getTimestamp() {
return timestamp;
}
public String getDataId() {
return dataId;
}
public String getMd5() {
return md5;
}
}

@ -0,0 +1,9 @@
{
"properties": [
{
"name": "spring.application.group",
"type": "java.lang.String",
"description": "spring application group."
}
]
}

@ -0,0 +1,9 @@
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySourceLocator
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alicloud.acm.AcmAutoConfiguration,\
org.springframework.cloud.alicloud.acm.endpoint.AcmEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.alicloud.acm.diagnostics.analyzer.DiamondConnectionFailureAnalyzer

@ -0,0 +1,87 @@
<?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>spring-cloud-alibaba</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.1.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-ans</artifactId>
<name>Spring Cloud Alibaba Cloud ANS</name>
<dependencies>
<dependency>
<groupId>com.alibaba.ans</groupId>
<artifactId>ans-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-edas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,66 @@
/*
* 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.ans;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alicloud.ans.registry.AnsAutoServiceRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaolongzuo
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(name = "org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent")
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@ConditionalOnAnsEnabled
@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class,
AnsDiscoveryClientAutoConfiguration.class })
public class AnsAutoConfiguration {
@Bean
public AnsServiceRegistry ansServiceRegistry() {
return new AnsServiceRegistry();
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public AnsRegistration ansRegistration() {
return new AnsRegistration();
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public AnsAutoServiceRegistration ansAutoServiceRegistration(
AnsServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
AnsRegistration registration) {
return new AnsAutoServiceRegistration(registry, autoServiceRegistrationProperties,
registration);
}
}

@ -0,0 +1,103 @@
/*
* 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.ans;
import java.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import com.alibaba.ans.core.NamingService;
import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
/**
* @author xiaolongzuo
*/
public class AnsDiscoveryClient implements DiscoveryClient {
public static final String DESCRIPTION = "Spring Cloud ANS Discovery Client";
@Autowired
private AnsProperties ansProperties;
@Override
public String description() {
return DESCRIPTION;
}
@Override
public ServiceInstance getLocalServiceInstance() {
String serviceId = ansProperties.getClientDomains();
String host = ansProperties.getClientIp();
int port = ansProperties.getClientPort();
boolean secure = ansProperties.isSecure();
Map<String, String> metadata = ansProperties.getClientMetadata();
return new DefaultServiceInstance(serviceId, host, port, secure, metadata);
}
@Override
public List<ServiceInstance> getInstances(String serviceId) {
try {
List<Host> hosts = NamingService.getHosts(serviceId);
return hostToServiceInstanceList(hosts, serviceId);
}
catch (Exception e) {
throw new RuntimeException(
"Can not get hosts from ans server. serviceId: " + serviceId, e);
}
}
private static ServiceInstance hostToServiceInstance(Host host, String serviceId) {
AnsServiceInstance ansServiceInstance = new AnsServiceInstance();
ansServiceInstance.setHost(host.getIp());
ansServiceInstance.setPort(host.getPort());
ansServiceInstance.setServiceId(serviceId);
Map<String, String> metadata = new HashMap<String, String>(5);
metadata.put("appUseType", host.getAppUseType());
metadata.put("site", host.getSite());
metadata.put("unit", host.getUnit());
metadata.put("doubleWeight", "" + host.getDoubleWeight());
metadata.put("weight", "" + host.getWeight());
ansServiceInstance.setMetadata(metadata);
return ansServiceInstance;
}
private static List<ServiceInstance> hostToServiceInstanceList(List<Host> hosts,
String serviceId) {
List<ServiceInstance> result = new ArrayList<ServiceInstance>(hosts.size());
for (Host host : hosts) {
result.add(hostToServiceInstance(host, serviceId));
}
return result;
}
@Override
public List<String> getServices() {
Set<String> doms = NamingService.getDomsSubscribed();
List<String> result = new LinkedList<>();
for (String service : doms) {
result.add(service);
}
return result;
}
}

@ -0,0 +1,41 @@
/*
* 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.ans;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaolongzuo
*/
@Configuration
@ConditionalOnMissingBean(DiscoveryClient.class)
@EnableConfigurationProperties
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)
public class AnsDiscoveryClientAutoConfiguration {
@Bean
public DiscoveryClient ansDiscoveryClient() {
return new AnsDiscoveryClient();
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save