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

Merge pull request #5 from spring-cloud-incubator/master

Merge
This commit is contained in:
Neptune
2018-11-03 18:27:14 +08:00
committed by GitHub
162 changed files with 6009 additions and 1515 deletions

40
.circleci/config.yml Normal file
View File

@@ -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
View File

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

View File

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

View File

@@ -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.

90
pom.xml
View File

@@ -8,13 +8,13 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.0.0.RELEASE</version>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.2.0</version>
<version>0.2.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,9 +59,9 @@
<properties>
<!-- Dependency Versions -->
<spring-cloud-commons.version>2.0.0.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.0.0.RELEASE</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>2.0.0.RELEASE</spring-cloud-openfeign.version>
<spring-cloud-commons.version>2.0.2.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.0.2.RELEASE</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>2.0.2.RELEASE</spring-cloud-openfeign.version>
<junit.version>4.12</junit.version>
<javax-servlet-api>3.0</javax-servlet-api>
@@ -74,7 +78,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>
@@ -82,6 +86,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>
@@ -154,4 +161,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>

View File

@@ -6,24 +6,60 @@
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>2.0.0.RELEASE</version>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.0</version>
<version>0.2.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>
@@ -95,6 +131,11 @@
<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>
@@ -110,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>
@@ -135,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 -->

View File

@@ -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.2.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>

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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.2.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-openfeign</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>

View File

@@ -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.openfeign.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);
}
}

View File

@@ -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.openfeign.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);
}

View File

@@ -0,0 +1,46 @@
/*
* 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;
}
}

View File

@@ -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

View File

@@ -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.2.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>

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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.2.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>

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

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

View File

@@ -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 直接启动和编译打包后启动。
@@ -118,9 +119,9 @@ Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 `Config
* `spring.active.profile` 即为当前环境对应的 profile详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
**注意,当 activeprofile 为空时,对应的连接符 `-` 也将不存在dataId 的拼接格式变成 `${prefix}`.`${context.type}`**
**注意,当 activeprofile 为空时,对应的连接符 `-` 也将不存在dataId 的拼接格式变成 `${prefix}`.`${file-extension}`**
* `file-extension` 为配置内容的数据格式,可以通过配置项 `spring.cloud.nacos.config.content-type`来配置。
* `file-extension` 为配置内容的数据格式,可以通过配置项 `spring.cloud.nacos.config.file-extension`来配置。
目前只支持 `properties` 类型。
#### group
@@ -168,7 +169,7 @@ Spring Boot 2.x 可以通过访问 http://127.0.0.1:18084/actuator/nacos-config
服务端地址|spring.cloud.nacos.config.server-addr||
DataId前缀|spring.cloud.nacos.config.prefix||spring.application.name
Group|spring.cloud.nacos.config.group|DEFAULT_GROUP|
dataID后缀及数据格式|spring.cloud.nacos.config.file-extension|properties|目前只支持 properties
dataID后缀及内容文件格式|spring.cloud.nacos.config.file-extension|properties|dataId的后缀同时也是配置内容的文件格式目前只支持 properties
配置内容的编码方式|spring.cloud.nacos.config.encode|UTF-8|配置的编码
获取配置的超时时间|spring.cloud.nacos.config.timeout|3000|单位为 ms
配置的命名空间|spring.cloud.nacos.config.namespace||常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源隔离等。

View File

@@ -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.
@@ -119,9 +120,9 @@ In Nacos Config Starter, the splicing format of dataId is as follows
* `spring.active.profile` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
**Note: when the activeprofile is empty, the corresponding connector `-` will also not exist, and the splicing format of the dataId becomes `${prefix}`.`${context.type}`**
**Note: when the activeprofile is empty, the corresponding connector `-` will also not exist, and the splicing format of the dataId becomes `${prefix}`.`${file-extension}`**
* `file-extension` is the data format of the configuration content, which can be configured by the configuration item `spring.cloud.nacos.config.content-type`.
* `file-extension` is the data format of the configuration content, which can be configured by the configuration item `spring.cloud.nacos.config.file-extension`.
Currently only the `properties` type is supported.
#### group

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -197,7 +197,7 @@ AccessKey|spring.cloud.nacos.discovery.access-key||
SecretKey|spring.cloud.nacos.discovery.secret-key||
Metadata|spring.cloud.nacos.discovery.metadata||使用Map格式配置
日志文件名|spring.cloud.nacos.discovery.log-name||
接入点|spring.cloud.nacos.discovery.enpoint|UTF-8|地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
接入点|spring.cloud.nacos.discovery.endpoint|UTF-8|地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否集成Ribbon|ribbon.nacos.enabled|true|

View File

@@ -205,7 +205,7 @@ AccessKey|spring.cloud.nacos.discovery.access-key||
SecretKey|spring.cloud.nacos.discovery.secret-key||
Metadata|spring.cloud.nacos.discovery.metadata||Extended data, Configure using Map format
log name|spring.cloud.nacos.discovery.log-name||
endpoint|spring.cloud.nacos.discovery.enpoint||The domain name of a service, through which the server address can be dynamically obtained.
endpoint|spring.cloud.nacos.discovery.endpoint||The domain name of a service, through which the server address can be dynamically obtained.
Integration Ribbon|ribbon.nacos.enabled|true|

View File

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

View File

@@ -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);
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,49 @@
package org.springframework.cloud.alibaba.cloud.examples;
import com.aliyun.oss.OSS;
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 java.net.URISyntaxException;
/**
* 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);
}
}
}
}

View File

@@ -0,0 +1,65 @@
package org.springframework.cloud.alibaba.cloud.examples;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.model.OSSObject;
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 java.nio.charset.Charset;
/**
* 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();
}
}
}

View File

@@ -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.endpoints.web.exposure.include=*
spring.cloud.alicloud.access-key=AK
spring.cloud.alicloud.secret-key=SK
spring.cloud.alicloud.oss.endpoint=***.aliyuncs.com
management.endpoints.web.exposure.include=*

View File

@@ -1,6 +1,3 @@
{
"name": "spring-cloud-alibaba",
"github": "https://github.com/spring-cloud-incubator/spring-cloud-alibaba",
"authors": ["Jim", "flystar32"],
"emails": ["fangjian0423@gmail.com", "flystar32@163.com"]
"name": "chenzhu-test"
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.2.0</version>
<version>0.2.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>

View File

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

View File

@@ -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

View File

@@ -193,7 +193,8 @@ 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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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 (null != configService) {
return configService;
}
if (StringUtils.isEmpty(this.getEncode())) {
this.setEncode(
env.resolvePlaceholders("${spring.cloud.nacos.config.encode:}"));
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.getNamespace())) {
this.setNamespace(
env.resolvePlaceholders("${spring.cloud.nacos.config.namespace:}"));
}
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:}"));
}
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;
}
}
}

View File

@@ -83,7 +83,6 @@ public class NacosPropertySourceBuilder {
String data = null;
try {
data = configService.getConfig(dataId, group, timeout);
// todo add content type yaml support
if (!StringUtils.isEmpty(data)) {
logger.info(String.format("Loading nacos data, dataId: '%s', group: '%s'",
dataId, group));
@@ -95,7 +94,7 @@ public class NacosPropertySourceBuilder {
return properties;
}
else if (fileExtension.equalsIgnoreCase("yaml")
|| fileExtension.equalsIgnoreCase("yml")) {
|| fileExtension.equalsIgnoreCase("yml")) {
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
yamlFactory.setResources(new ByteArrayResource(data.getBytes()));
return yamlFactory.getObject();

View File

@@ -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,

View File

@@ -16,8 +16,6 @@
package org.springframework.cloud.alibaba.nacos.endpoint;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
@@ -46,15 +44,6 @@ public class NacosConfigEndpointAutoConfiguration {
@Autowired
private NacosPropertySourceRepository nacosPropertySourceRepository;
@Autowired
private ConfigService configService;
@Bean
@ConditionalOnBean
public NacosConfigProperties nacosConfigProperties() {
return new NacosConfigProperties();
}
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@Bean
@@ -67,6 +56,7 @@ public class NacosConfigEndpointAutoConfiguration {
public NacosConfigHealthIndicator nacosConfigHealthIndicator(
NacosPropertySourceRepository nacosPropertySourceRepository) {
return new NacosConfigHealthIndicator(nacosConfigProperties,
nacosPropertySourceRepository, configService);
nacosPropertySourceRepository,
nacosConfigProperties.configServiceInstance());
}
}

View File

@@ -39,66 +39,59 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class NacosConfigAutoConfigurationTests {
private ConfigurableApplicationContext context;
private ConfigurableApplicationContext context;
@Before
public void setUp() throws Exception {
this.context = new SpringApplicationBuilder(
NacosConfigBootstrapConfiguration.class,
NacosConfigAutoConfiguration.class,
TestConfiguration.class)
.web(WebApplicationType.NONE).run(
"--spring.cloud.config.enabled=true",
"--spring.cloud.nacos.config.server-addr=127.0.0.1:8080",
"--spring.cloud.nacos.config.prefix=myapp");
}
@Before
public void setUp() throws Exception {
this.context = new SpringApplicationBuilder(
NacosConfigBootstrapConfiguration.class,
NacosConfigAutoConfiguration.class, TestConfiguration.class)
.web(WebApplicationType.NONE)
.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();
}
}
@After
public void tearDown() throws Exception {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testNacosConfigProperties() {
@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.getParent()
.getBean(NacosConfigProperties.class);
assertThat(nacosConfigProperties.getFileExtension()).isEqualTo("properties");
assertThat(nacosConfigProperties.getPrefix()).isEqualTo("test");
assertThat(nacosConfigProperties.getName()).isEqualTo("myapp");
}
}
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);
}
@Test
public void testNacosRefreshProperties() {
@Configuration
@AutoConfigureBefore(NacosConfigAutoConfiguration.class)
static class TestConfiguration {
NacosRefreshProperties nacosRefreshProperties = this.context.getBean(NacosRefreshProperties.class);
assertThat(nacosRefreshProperties.isEnabled()).isEqualTo(true);
@Autowired
ConfigurableApplicationContext context;
}
@Bean
ContextRefresher contextRefresher() {
return new ContextRefresher(context, new RefreshScope());
}
@Configuration
@AutoConfigureBefore(NacosConfigAutoConfiguration.class)
static class TestConfiguration{
@Autowired
ConfigurableApplicationContext context;
@Bean
ContextRefresher contextRefresher(){
return new ContextRefresher(context, new RefreshScope());
}
}
}
}

View File

@@ -43,9 +43,10 @@ public class NacosConfigBootstrapConfigurationTests {
public void setUp() throws Exception {
this.context = new SpringApplicationBuilder(
NacosConfigBootstrapConfiguration.class).web(WebApplicationType.NONE).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=myapp");
"--spring.cloud.nacos.config.prefix=test");
}
@After
@@ -68,15 +69,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();
}
}

View File

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

View File

@@ -19,15 +19,11 @@ package org.springframework.cloud.alibaba.nacos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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,17 +40,6 @@ public class NacosDiscoveryClient implements DiscoveryClient {
@Autowired
private NacosDiscoveryProperties discoveryProperties;
@Autowired
private Environment environment;
private NamingService namingService;
@PostConstruct
public void init() {
discoveryProperties.overrideFromEnv(environment);
namingService = discoveryProperties.getNamingService();
}
@Override
public String description() {
return DESCRIPTION;
@@ -63,7 +48,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) {
@@ -103,8 +89,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) {
@@ -114,6 +100,6 @@ public class NacosDiscoveryClient implements DiscoveryClient {
}
public NamingService getNamingService() {
return namingService;
return discoveryProperties.namingServiceInstance();
}
}

View File

@@ -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);

View File

@@ -29,7 +29,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryClient;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
/**
@@ -45,9 +44,6 @@ public class NacosDiscoveryEndpoint {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired
private NacosDiscoveryClient discoveryClient;
/**
* @return nacos discovery endpoint
*/
@@ -56,7 +52,7 @@ public class NacosDiscoveryEndpoint {
Map<String, Object> result = new HashMap<>();
result.put("NacosDiscoveryProperties", nacosDiscoveryProperties);
NamingService namingService = discoveryClient.getNamingService();
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
List<ServiceInfo> subscribe = Collections.emptyList();
try {

View File

@@ -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();
@@ -124,11 +119,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(
@@ -139,7 +130,6 @@ public class NacosRegistration implements Registration, ServiceInstance {
@Override
public String toString() {
return "NacosRegistration{" + "nacosDiscoveryProperties="
+ nacosDiscoveryProperties + ", nacosNamingService=" + nacosNamingService
+ '}';
+ nacosDiscoveryProperties + '}';
}
}

View File

@@ -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.2.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>

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -0,0 +1,272 @@
/*
* 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.ApplicationStartedEvent;
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, 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);
sentinelDataSourceFields.forEach(sentinelDataSourceField -> {
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 = ApplicationStartedEvent.class)
public void appStartedListener(ApplicationStartedEvent 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;
if (ruleList.stream().filter(rule -> rule.getClass() == type).toArray().length == ruleList.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;
}
}
}

View File

@@ -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);
}

View File

@@ -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
* <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see ReadableDataSource
*/
@Target({ElementType.FIELD})

View File

@@ -0,0 +1,63 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* 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> {
private String namespaceName;
private String flowRulesKey;
private String defaultFlowRuleValue;
private Converter converter;
@Override
public ApolloDataSource getObject() throws Exception {
return new ApolloDataSource(namespaceName, flowRulesKey, defaultFlowRuleValue,
converter);
}
@Override
public Class<?> getObjectType() {
return ApolloDataSource.class;
}
public String getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public String getFlowRulesKey() {
return flowRulesKey;
}
public void setFlowRulesKey(String flowRulesKey) {
this.flowRulesKey = flowRulesKey;
}
public String getDefaultFlowRuleValue() {
return defaultFlowRuleValue;
}
public void setDefaultFlowRuleValue(String defaultFlowRuleValue) {
this.defaultFlowRuleValue = defaultFlowRuleValue;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter Converter) {
this.converter = Converter;
}
}

View File

@@ -0,0 +1,76 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.io.File;
import java.nio.charset.Charset;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* 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> {
private String file;
private String charset;
private long recommendRefreshMs;
private int bufSize;
private Converter converter;
@Override
public FileRefreshableDataSource getObject() throws Exception {
return new FileRefreshableDataSource(new File(file), converter,
recommendRefreshMs, bufSize, Charset.forName(charset));
}
@Override
public Class<?> getObjectType() {
return FileRefreshableDataSource.class;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public long getRecommendRefreshMs() {
return recommendRefreshMs;
}
public void setRecommendRefreshMs(long recommendRefreshMs) {
this.recommendRefreshMs = recommendRefreshMs;
}
public int getBufSize() {
return bufSize;
}
public void setBufSize(int bufSize) {
this.bufSize = bufSize;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter Converter) {
this.converter = Converter;
}
}

View File

@@ -0,0 +1,62 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* 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> {
private String serverAddr;
private String groupId;
private String dataId;
private Converter converter;
@Override
public NacosDataSource getObject() throws Exception {
return new NacosDataSource(serverAddr, groupId, dataId, converter);
}
@Override
public Class<?> getObjectType() {
return NacosDataSource.class;
}
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter Converter) {
this.converter = Converter;
}
}

View File

@@ -0,0 +1,81 @@
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;
}
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;
}
}

View File

@@ -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

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.2.0</version>
<version>0.2.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -25,29 +25,6 @@
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
<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>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
@@ -58,6 +35,11 @@
<artifactId>sentinel-dubbo-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency>
<!--spring boot-->
<dependency>

View File

@@ -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;
}

View File

@@ -1,151 +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;
}
}

View File

@@ -1,264 +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.boot.context.event.ApplicationStartedEvent;
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.context.event.EventListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
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;
/**
* {@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, 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);
sentinelDataSourceFields.forEach(sentinelDataSourceField -> {
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());
}
@EventListener(classes = ApplicationStartedEvent.class)
public void appStartedListener(ApplicationStartedEvent event) throws Exception {
Map<String, ReadableDataSource> dataSourceMap = event.getApplicationContext().getBeansOfType(ReadableDataSource.class);
if(dataSourceMap.size() == 1) {
ReadableDataSource dataSource = dataSourceMap.values().iterator().next();
Object ruleConfig = dataSource.loadConfig();
SentinelProperty sentinelProperty = dataSource.getProperty();
if(checkRuleType(ruleConfig, FlowRule.class)) {
FlowRuleManager.register2Property(sentinelProperty);
}
if(checkRuleType(ruleConfig, DegradeRule.class)) {
DegradeRuleManager.register2Property(sentinelProperty);
}
if(checkRuleType(ruleConfig, SystemRule.class)) {
SystemRuleManager.register2Property(sentinelProperty);
}
if(checkRuleType(ruleConfig, AuthorityRule.class)) {
AuthorityRuleManager.register2Property(sentinelProperty);
}
}
}
private boolean checkRuleType(Object ruleConfig, Class type) {
if(ruleConfig.getClass() == type) {
return true;
} else if(ruleConfig instanceof List) {
List ruleList = (List)ruleConfig;
if(ruleList.stream().filter(rule -> rule.getClass() == type).toArray().length == ruleList.size()) {
return true;
}
}
return false;
}
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;
}
}
}

View File

@@ -1,61 +0,0 @@
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;
/**
* @author fangjian
* @see ApolloDataSource
*/
public class ApolloDataSourceFactoryBean implements FactoryBean<ApolloDataSource> {
private String namespaceName;
private String flowRulesKey;
private String defaultFlowRuleValue;
private Converter converter;
@Override
public ApolloDataSource getObject() throws Exception {
return new ApolloDataSource(namespaceName, flowRulesKey, defaultFlowRuleValue,
converter);
}
@Override
public Class<?> getObjectType() {
return ApolloDataSource.class;
}
public String getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public String getFlowRulesKey() {
return flowRulesKey;
}
public void setFlowRulesKey(String flowRulesKey) {
this.flowRulesKey = flowRulesKey;
}
public String getDefaultFlowRuleValue() {
return defaultFlowRuleValue;
}
public void setDefaultFlowRuleValue(String defaultFlowRuleValue) {
this.defaultFlowRuleValue = defaultFlowRuleValue;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter Converter) {
this.converter = Converter;
}
}

View File

@@ -1,74 +0,0 @@
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;
/**
* @author fangjian
* @see FileRefreshableDataSource
*/
public class FileRefreshableDataSourceFactoryBean
implements FactoryBean<FileRefreshableDataSource> {
private String file;
private String charset;
private long recommendRefreshMs;
private int bufSize;
private Converter converter;
@Override
public FileRefreshableDataSource getObject() throws Exception {
return new FileRefreshableDataSource(new File(file), converter,
recommendRefreshMs, bufSize, Charset.forName(charset));
}
@Override
public Class<?> getObjectType() {
return FileRefreshableDataSource.class;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public long getRecommendRefreshMs() {
return recommendRefreshMs;
}
public void setRecommendRefreshMs(long recommendRefreshMs) {
this.recommendRefreshMs = recommendRefreshMs;
}
public int getBufSize() {
return bufSize;
}
public void setBufSize(int bufSize) {
this.bufSize = bufSize;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter Converter) {
this.converter = Converter;
}
}

View File

@@ -1,60 +0,0 @@
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;
/**
* @author fangjian
* @see NacosDataSource
*/
public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {
private String serverAddr;
private String groupId;
private String dataId;
private Converter converter;
@Override
public NacosDataSource getObject() throws Exception {
return new NacosDataSource(serverAddr, groupId, dataId, converter);
}
@Override
public Class<?> getObjectType() {
return NacosDataSource.class;
}
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter Converter) {
this.converter = Converter;
}
}

View File

@@ -1,80 +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;
}
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;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,72 @@
<?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.2.1.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-alicloud-acm</artifactId>
<name>Spring Cloud Alibaba Cloud ACM</name>
<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>

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
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
*/
@Endpoint(id = "acm")
public class AcmEndpoint {
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) {
this.properties = properties;
this.refreshHistory = refreshHistory;
this.propertySourceRepository = propertySourceRepository;
}
@ReadOperation
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;
}
}

View File

@@ -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.endpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
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.autoconfigure.web.ManagementContextConfiguration")
public class AcmEndpointAutoConfiguration {
@Autowired
private AcmProperties acmProperties;
@Autowired
private AcmRefreshHistory acmRefreshHistory;
@Autowired
private AcmPropertySourceRepository acmPropertySourceRepository;
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@Bean
public AcmEndpoint acmEndpoint() {
return new AcmEndpoint(acmProperties, acmRefreshHistory,
acmPropertySourceRepository);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,120 @@
/*
* 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.computeIfAbsent(dataId,
i -> 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();
}
});
ConfigService.addListener(dataId,
acmIntegrationProperties.getAcmProperties().getGroup(), listener);
}
}

View File

@@ -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;
}
}

View File

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

View File

@@ -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

View File

@@ -0,0 +1,98 @@
<?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.2.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-actuator-autoconfigure</artifactId>
<scope>provided</scope>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

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