From ee2c696bdf1a3c5b36d6a69b7482d8d1053c71fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=97=E5=B0=91?= <314226532@qq.com> Date: Wed, 9 Jan 2019 18:38:08 +0800 Subject: [PATCH] ans starter suport eureka/consule registry and add sms module --- spring-cloud-alibaba-dependencies/pom.xml | 29 ++ .../sms-example/pom.xml | 74 +++ .../alibaba/cloud/example/SmsApplication.java | 31 ++ .../alibaba/cloud/example/SmsController.java | 128 ++++++ .../example/SmsReportMessageListener.java | 28 ++ .../cloud/example/SmsUpMessageListener.java | 19 + .../src/main/resources/application.properties | 9 + .../NacosConfigBootstrapConfiguration.java | 11 +- .../alibaba/nacos/NacosConfigProperties.java | 13 +- .../client/NacosPropertySourceBuilder.java | 20 +- .../client/NacosPropertySourceLocator.java | 32 +- .../nacos/refresh/NacosContextRefresher.java | 24 +- .../alicloud/ans/AnsAutoConfiguration.java | 11 +- .../alicloud/ans/AnsDiscoveryClient.java | 10 +- .../AnsDiscoveryClientAutoConfiguration.java | 3 + .../alicloud/ans/endpoint/AnsEndpoint.java | 23 +- .../alicloud/ans/migrate/MigrateEndpoint.java | 31 ++ .../MigrateEndpointAutoConfiguration.java | 18 + .../ans/migrate/MigrateOnCondition.java | 49 ++ .../ans/migrate/MigrateOnConditionClass.java | 22 + .../MigrateOnConditionMissingClass.java | 23 + .../ans/migrate/MigrateProxyManager.java | 94 ++++ .../migrate/MigrateRefreshEventListener.java | 75 +++ .../MigrateRibbonBeanPostProcessor.java | 53 +++ .../ans/migrate/MigrateServiceRegistry.java | 51 +++ .../migrate/MigrationAutoconfiguration.java | 25 + .../migrate/ServerListInvocationHandler.java | 143 ++++++ .../alicloud/ans/migrate/ServerWrapper.java | 35 ++ .../registry/AnsAutoServiceRegistration.java | 11 +- .../ans/registry/AnsRegistration.java | 23 +- .../ans/registry/AnsServiceRegistry.java | 42 +- .../ribbon/AnsRibbonClientConfiguration.java | 5 +- .../cloud/alicloud/ans/ribbon/AnsServer.java | 50 +- .../alicloud/ans/ribbon/AnsServerList.java | 6 +- .../ans/ribbon/MigrateRibbonCofiguration.java | 20 + .../ribbon/RibbonAnsAutoConfiguration.java | 3 +- .../main/resources/META-INF/spring.factories | 6 +- spring-cloud-alicloud-context/pom.xml | 6 + .../context/sms/SmsConfigProperties.java | 107 +++++ .../context/sms/SmsConfigRegistration.java | 26 ++ .../sms/SmsContextAutoConfiguration.java | 30 ++ .../main/resources/META-INF/spring.factories | 3 +- spring-cloud-alicloud-sms/pom.xml | 83 ++++ .../alicloud/sms/AbstractSmsService.java | 46 ++ .../cloud/alicloud/sms/ISmsService.java | 115 +++++ .../sms/SmsInitializerEventListener.java | 105 +++++ .../alicloud/sms/SmsMessageListener.java | 24 + .../sms/SmsReportMessageListener.java | 22 + .../cloud/alicloud/sms/SmsServiceImpl.java | 187 ++++++++ .../alicloud/sms/SmsUpMessageListener.java | 22 + .../sms/base/DefaultAlicomMessagePuller.java | 429 ++++++++++++++++++ .../alicloud/sms/base/MessageListener.java | 24 + .../base/QueryTokenForMnsQueueRequest.java | 82 ++++ .../base/QueryTokenForMnsQueueResponse.java | 117 +++++ ...yTokenForMnsQueueResponseUnmarshaller.java | 48 ++ .../alicloud/sms/base/TokenForAlicom.java | 96 ++++ .../sms/base/TokenGetterForAlicom.java | 142 ++++++ .../sms/config/SmsAutoConfiguration.java | 49 ++ .../sms/endpoint/EndpointManager.java | 106 +++++ .../sms/endpoint/ReceiveMessageEntity.java | 60 +++ .../alicloud/sms/endpoint/SmsEndpoint.java | 31 ++ .../SmsEndpointAutoConfiguration.java | 31 ++ .../main/resources/META-INF/spring.factories | 3 + spring-cloud-starter-alicloud/pom.xml | 1 + .../spring-cloud-starter-alicloud-sms/pom.xml | 20 + 65 files changed, 3149 insertions(+), 116 deletions(-) create mode 100644 spring-cloud-alibaba-examples/sms-example/pom.xml create mode 100644 spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsApplication.java create mode 100644 spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsController.java create mode 100644 spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsReportMessageListener.java create mode 100644 spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsUpMessageListener.java create mode 100644 spring-cloud-alibaba-examples/sms-example/src/main/resources/application.properties create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java create mode 100644 spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java create mode 100644 spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java create mode 100644 spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java create mode 100644 spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java create mode 100644 spring-cloud-alicloud-sms/pom.xml create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/ISmsService.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsMessageListener.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsReportMessageListener.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsUpMessageListener.java create mode 100755 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/DefaultAlicomMessagePuller.java create mode 100755 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/MessageListener.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueRequest.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponse.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponseUnmarshaller.java create mode 100755 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenForAlicom.java create mode 100755 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenGetterForAlicom.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/EndpointManager.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/ReceiveMessageEntity.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpoint.java create mode 100644 spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpointAutoConfiguration.java create mode 100644 spring-cloud-alicloud-sms/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-starter-alicloud/spring-cloud-starter-alicloud-sms/pom.xml diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index cc49e9ee0..e34b9f726 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -28,6 +28,10 @@ 2.16.0 4.3.1 2.1.6 + 1.1.0 + 1.1.8 + 1.1.0 + 1.1.1 @@ -71,6 +75,19 @@ ${schedulerX.client.version} + + + com.aliyun.mns + aliyun-sdk-mns + ${aliyun.sdk.mns} + + + + com.aliyun + aliyun-java-sdk-dysmsapi + ${aliyun.java.sdk.dysmsapi} + + com.alibaba.nacos @@ -213,6 +230,11 @@ spring-cloud-alicloud-schedulerx ${project.version} + + org.springframework.cloud + spring-cloud-alicloud-sms + ${project.version} + org.springframework.cloud spring-cloud-alicloud-context @@ -283,6 +305,13 @@ ${project.version} + + + org.springframework.cloud + spring-cloud-starter-alicloud-sms + ${project.version} + + diff --git a/spring-cloud-alibaba-examples/sms-example/pom.xml b/spring-cloud-alibaba-examples/sms-example/pom.xml new file mode 100644 index 000000000..77069083f --- /dev/null +++ b/spring-cloud-alibaba-examples/sms-example/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + alibaba.com + sms-example + 0.0.1-SNAPSHOT + jar + + sms-example + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.0.6.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.SR2 + 0.2.2.BUILD-SNAPSHOT + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + org.springframework.cloud + spring-cloud-alibaba-dependencies + ${spring-cloud-alibaba-alicloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-alicloud-sms + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsApplication.java b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsApplication.java new file mode 100644 index 000000000..a5e89a9a4 --- /dev/null +++ b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsApplication.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * + */ +@SpringBootApplication +public class SmsApplication { + + public static void main(String[] args) { + + SpringApplication.run(SmsApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsController.java b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsController.java new file mode 100644 index 000000000..496b97c0d --- /dev/null +++ b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsController.java @@ -0,0 +1,128 @@ +package org.springframework.cloud.alibaba.cloud.example; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alicloud.sms.ISmsService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.aliyun.mns.model.Message; +import com.aliyuncs.dysmsapi.model.v20170525.*; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.http.MethodType; + +@RestController +public class SmsController { + + @Autowired + private ISmsService smsService; + + @Autowired + private SmsReportMessageListener smsReportMessageListener; + + /** + * 短信发送 Example + * @param code + * @return + */ + @RequestMapping("/batch-sms-send.do") + public SendBatchSmsResponse batchsendCheckCode( + @RequestParam(name = "code") String code) { + // 组装请求对象 + SendBatchSmsRequest request = new SendBatchSmsRequest(); + // 使用post提交 + request.setMethod(MethodType.GET); + // 必填:待发送手机号。支持JSON格式的批量调用,批量上限为100个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式 + request.setPhoneNumberJson("[\"177********\",\"130********\"]"); + // 必填:短信签名-支持不同的号码发送不同的短信签名 + request.setSignNameJson("[\"*******\",\"*******\"]"); + // 必填:短信模板-可在短信控制台中找到 + request.setTemplateCode("******"); + // 必填:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 + // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败 + request.setTemplateParamJson( + "[{\"code\":\"" + code + "\"},{\"code\":\"" + code + "\"}]"); + // 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段) + // request.setSmsUpExtendCodeJson("[\"90997\",\"90998\"]"); + try { + SendBatchSmsResponse sendSmsResponse = smsService + .sendSmsBatchRequest(request); + return sendSmsResponse; + } + catch (ClientException e) { + e.printStackTrace(); + } + return new SendBatchSmsResponse(); + } + + /** + * 短信发送 Example + * @param code + * @return + */ + @RequestMapping("/sms-send.do") + public SendSmsResponse sendCheckCode(@RequestParam(name = "code") String code) { + // 组装请求对象-具体描述见控制台-文档部分内容 + SendSmsRequest request = new SendSmsRequest(); + // 必填:待发送手机号 + request.setPhoneNumbers("******"); + // 必填:短信签名-可在短信控制台中找到 + request.setSignName("******"); + // 必填:短信模板-可在短信控制台中找到 + request.setTemplateCode("******"); + // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 + request.setTemplateParam("{\"code\":\"" + code + "\"}"); + + // 选填-上行短信扩展码(无特殊需求用户请忽略此字段) + // request.setSmsUpExtendCode("90997"); + + // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 + request.setOutId("****TraceId"); + try { + SendSmsResponse sendSmsResponse = smsService.sendSmsRequest(request); + return sendSmsResponse; + } + catch (ClientException e) { + e.printStackTrace(); + } + return new SendSmsResponse(); + } + + /** + * + * 短信查询 Example + * @param telephone + * @return + */ + @RequestMapping("/query.do") + public QuerySendDetailsResponse querySendDetailsResponse( + @RequestParam(name = "tel") String telephone) { + // 组装请求对象 + QuerySendDetailsRequest request = new QuerySendDetailsRequest(); + // 必填-号码 + request.setPhoneNumber(telephone); + // 必填-短信发送的日期 支持30天内记录查询(可查其中一天的发送数据),格式yyyyMMdd + request.setSendDate("20190103"); + // 必填-页大小 + request.setPageSize(10L); + // 必填-当前页码从1开始计数 + request.setCurrentPage(1L); + try { + QuerySendDetailsResponse response = smsService.querySendDetails(request); + return response; + } + catch (ClientException e) { + e.printStackTrace(); + } + + return new QuerySendDetailsResponse(); + } + + @RequestMapping("/sms-report.do") + public List smsReport() { + + return smsReportMessageListener.getSmsReportMessageSet(); + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsReportMessageListener.java b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsReportMessageListener.java new file mode 100644 index 000000000..aa092789f --- /dev/null +++ b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsReportMessageListener.java @@ -0,0 +1,28 @@ +package org.springframework.cloud.alibaba.cloud.example; + +import com.aliyun.mns.model.Message; +import org.springframework.stereotype.Component; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author 如果需要监听短信是否被对方成功接收,只需实现这个接口并初始化一个 Spring Bean 即可。 + */ +@Component +public class SmsReportMessageListener + implements org.springframework.cloud.alicloud.sms.SmsReportMessageListener { + private List smsReportMessageSet = new LinkedList<>(); + + @Override + public boolean dealMessage(Message message) { + smsReportMessageSet.add(message); + System.err.println(this.getClass().getName() + "; " + message.toString()); + return true; + } + + public List getSmsReportMessageSet() { + + return smsReportMessageSet; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsUpMessageListener.java b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsUpMessageListener.java new file mode 100644 index 000000000..22f4efec1 --- /dev/null +++ b/spring-cloud-alibaba-examples/sms-example/src/main/java/org/springframework/cloud/alibaba/cloud/example/SmsUpMessageListener.java @@ -0,0 +1,19 @@ +package org.springframework.cloud.alibaba.cloud.example; + +import org.springframework.stereotype.Component; + +import com.aliyun.mns.model.Message; + +/** + * @author 如果发送的短信需要接收对方回复的状态消息,只需实现该接口并初始化一个 Spring Bean 即可。 + */ +@Component +public class SmsUpMessageListener + implements org.springframework.cloud.alicloud.sms.SmsUpMessageListener { + + @Override + public boolean dealMessage(Message message) { + System.err.println(this.getClass().getName() + "; " + message.toString()); + return true; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/sms-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sms-example/src/main/resources/application.properties new file mode 100644 index 000000000..ae65c56b9 --- /dev/null +++ b/spring-cloud-alibaba-examples/sms-example/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.application.name=sca-sms-example +server.port=9051 +# config management +management.endpoints.web.exposure.include=* +#config sms +spring.cloud.alicloud.access-key=****** +spring.cloud.alicloud.secret-key=****** +spring.cloud.alicloud.sms.report-queue-name=***** +spring.cloud.alicloud.sms.up-queue-name=****** \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java index 076d884f0..7fedcc169 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java @@ -27,15 +27,16 @@ import org.springframework.context.annotation.Configuration; @Configuration public class NacosConfigBootstrapConfiguration { - @Bean - public NacosPropertySourceLocator nacosPropertySourceLocator() { - return new NacosPropertySourceLocator(); - } - @Bean @ConditionalOnMissingBean public NacosConfigProperties nacosConfigProperties() { return new NacosConfigProperties(); } + @Bean + public NacosPropertySourceLocator nacosPropertySourceLocator( + NacosConfigProperties nacosConfigProperties) { + return new NacosPropertySourceLocator(nacosConfigProperties); + } + } diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java index 941672204..8a7be5057 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java @@ -18,8 +18,8 @@ package org.springframework.cloud.alibaba.nacos; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.config.ConfigService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.env.Environment; @@ -42,10 +42,9 @@ import static com.alibaba.nacos.api.PropertyKeyConst.*; @ConfigurationProperties(NacosConfigProperties.PREFIX) public class NacosConfigProperties { - public static final String PREFIX = "spring.cloud.nacos.config"; + static final String PREFIX = "spring.cloud.nacos.config"; - private static final Logger LOGGER = LoggerFactory - .getLogger(NacosConfigProperties.class); + private static final Log log = LogFactory.getLog(NacosConfigProperties.class); /** * nacos config server address @@ -348,7 +347,9 @@ public class NacosConfigProperties { return configService; } catch (Exception e) { - LOGGER.error("create config service error!properties={},e=,", this, e); + log.error( + "create config service error!properties=" + this.toString() + ",e=,", + e); return null; } } diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java index b900a674c..1b853704a 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java @@ -18,8 +18,8 @@ package org.springframework.cloud.alibaba.nacos.client; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; import org.springframework.core.io.ByteArrayResource; @@ -33,8 +33,7 @@ import java.util.*; * @author pbting */ public class NacosPropertySourceBuilder { - private static final Logger LOGGER = LoggerFactory - .getLogger(NacosPropertySourceBuilder.class); + private static final Log log = LogFactory.getLog(NacosPropertySourceBuilder.class); private static final Properties EMPTY_PROPERTIES = new Properties(); private ConfigService configService; @@ -68,9 +67,6 @@ public class NacosPropertySourceBuilder { NacosPropertySource build(String dataId, String group, String fileExtension, boolean isRefreshable) { Properties p = loadNacosData(dataId, group, fileExtension); - if (p == null) { - p = EMPTY_PROPERTIES; - } NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId, propertiesToMap(p), new Date(), isRefreshable); NacosPropertySourceRepository.collectNacosPropertySources(nacosPropertySource); @@ -82,7 +78,7 @@ public class NacosPropertySourceBuilder { try { data = configService.getConfig(dataId, group, timeout); if (!StringUtils.isEmpty(data)) { - LOGGER.info(String.format("Loading nacos data, dataId: '%s', group: '%s'", + log.info(String.format("Loading nacos data, dataId: '%s', group: '%s'", dataId, group)); if (fileExtension.equalsIgnoreCase("properties")) { @@ -101,13 +97,13 @@ public class NacosPropertySourceBuilder { } } catch (NacosException e) { - LOGGER.error("get data from Nacos error,dataId:{}, ", dataId, e); + log.error("get data from Nacos error,dataId:" + dataId + ", ", e); } catch (Exception e) { - LOGGER.error("parse data from Nacos error,dataId:{},data:{},", dataId, data, - e); + log.error("parse data from Nacos error,dataId:" + dataId + ",data:" + data + + ",", e); } - return null; + return EMPTY_PROPERTIES; } @SuppressWarnings("unchecked") diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java index e0cabb383..72cdb6088 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java @@ -16,10 +16,11 @@ package org.springframework.cloud.alibaba.nacos.client; -import com.alibaba.nacos.api.config.ConfigService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; import org.springframework.cloud.alibaba.nacos.refresh.NacosContextRefresher; @@ -30,8 +31,7 @@ import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; import org.springframework.util.StringUtils; -import java.util.Arrays; -import java.util.List; +import com.alibaba.nacos.api.config.ConfigService; /** * @author xiaojing @@ -40,8 +40,7 @@ import java.util.List; @Order(0) public class NacosPropertySourceLocator implements PropertySourceLocator { - private static final Logger LOGGER = LoggerFactory - .getLogger(NacosPropertySourceLocator.class); + private static final Log log = LogFactory.getLog(NacosPropertySourceLocator.class); private static final String NACOS_PROPERTY_SOURCE_NAME = "NACOS"; private static final String SEP1 = "-"; private static final String DOT = "."; @@ -49,22 +48,21 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { private static final List SUPPORT_FILE_EXTENSION = Arrays.asList("properties", "yaml", "yml"); - @Autowired + private NacosPropertySourceBuilder nacosPropertySourceBuilder; + private NacosConfigProperties nacosConfigProperties; - public NacosPropertySourceLocator() { + public NacosPropertySourceLocator(NacosConfigProperties nacosConfigProperties) { + this.nacosConfigProperties = nacosConfigProperties; } - private NacosPropertySourceBuilder nacosPropertySourceBuilder; - @Override public PropertySource locate(Environment env) { ConfigService configService = nacosConfigProperties.configServiceInstance(); if (null == configService) { - LOGGER.warn( - "no instance of config service found, can't load config from nacos"); + log.warn("no instance of config service found, can't load config from nacos"); return null; } long timeout = nacosConfigProperties.getTimeout(); @@ -167,7 +165,7 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { private void loadNacosDataIfPresent(final CompositePropertySource composite, final String dataId, final String group, String fileExtension, boolean isRefreshable) { - if (NacosContextRefresher.loadCount.get() != 0) { + if (NacosContextRefresher.getRefreshCount() != 0) { NacosPropertySource ps; if (!isRefreshable) { ps = NacosPropertySourceRepository.getNacosPropertySource(dataId); @@ -187,10 +185,10 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { private static void checkDataIdFileExtension(String[] sharedDataIdArry) { StringBuilder stringBuilder = new StringBuilder(); - outline: for (int i = 0; i < sharedDataIdArry.length; i++) { + for (int i = 0; i < sharedDataIdArry.length; i++) { for (String fileExtension : SUPPORT_FILE_EXTENSION) { if (sharedDataIdArry[i].indexOf(fileExtension) > 0) { - continue outline; + break; } } stringBuilder.append(sharedDataIdArry[i] + ","); diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java index c726f9489..fcc6d9df1 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java @@ -19,8 +19,8 @@ package org.springframework.cloud.alibaba.nacos.refresh; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; @@ -51,10 +51,9 @@ import java.util.concurrent.atomic.AtomicLong; public class NacosContextRefresher implements ApplicationListener, ApplicationContextAware { - private final static Logger LOGGER = LoggerFactory - .getLogger(NacosContextRefresher.class); + private final static Log log = LogFactory.getLog(NacosContextRefresher.class); - public static final AtomicLong loadCount = new AtomicLong(0); + private static final AtomicLong REFRESH_COUNT = new AtomicLong(0); private final NacosRefreshProperties refreshProperties; @@ -108,7 +107,7 @@ public class NacosContextRefresher Listener listener = listenerMap.computeIfAbsent(dataId, i -> new Listener() { @Override public void receiveConfigInfo(String configInfo) { - loadCount.incrementAndGet(); + refreshCountIncrement(); String md5 = ""; if (!StringUtils.isEmpty(configInfo)) { try { @@ -117,14 +116,14 @@ public class NacosContextRefresher .toString(16); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { - LOGGER.warn("[Nacos] unable to get md5 for dataId: " + dataId, e); + log.warn("[Nacos] unable to get md5 for dataId: " + dataId, e); } } refreshHistory.add(dataId, md5); applicationContext.publishEvent( new RefreshEvent(this, null, "Refresh Nacos config")); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Refresh Nacos config group{},dataId{}", group, dataId); + if (log.isDebugEnabled()) { + log.debug("Refresh Nacos config group " + group + ",dataId" + dataId); } } @@ -142,4 +141,11 @@ public class NacosContextRefresher } } + public static long getRefreshCount() { + return REFRESH_COUNT.get(); + } + + public static void refreshCountIncrement() { + REFRESH_COUNT.incrementAndGet(); + } } diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java index a14c6e12a..d563632ea 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java @@ -21,12 +21,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass; import org.springframework.cloud.alicloud.ans.registry.AnsAutoServiceRegistration; import org.springframework.cloud.alicloud.ans.registry.AnsRegistration; import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; /** @@ -34,6 +38,7 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @EnableConfigurationProperties +@Conditional(MigrateOnConditionMissingClass.class) @ConditionalOnClass(name = "org.springframework.boot.web.context.WebServerInitializedEvent") @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @ConditionalOnAnsEnabled @@ -49,8 +54,9 @@ public class AnsAutoConfiguration { @Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) - public AnsRegistration ansRegistration() { - return new AnsRegistration(); + public AnsRegistration ansRegistration(AnsProperties ansProperties, + ApplicationContext applicationContext) { + return new AnsRegistration(ansProperties, applicationContext); } @Bean @@ -63,4 +69,5 @@ public class AnsAutoConfiguration { return new AnsAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); } + } diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java index c95757b22..46e1a1bbf 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClient.java @@ -16,13 +16,12 @@ package org.springframework.cloud.alicloud.ans; -import java.util.*; - +import com.alibaba.ans.core.NamingService; +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; -import com.alibaba.ans.core.NamingService; -import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; +import java.util.*; /** * @author xiaolongzuo @@ -75,8 +74,9 @@ public class AnsDiscoveryClient implements DiscoveryClient { @Override public List getServices() { - + Set publishers = NamingService.getPublishes(); Set doms = NamingService.getDomsSubscribed(); + doms.addAll(publishers); List result = new LinkedList<>(); for (String service : doms) { result.add(service); diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java index 7d2869763..c19296f4d 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientAutoConfiguration.java @@ -19,15 +19,18 @@ package org.springframework.cloud.alicloud.ans; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; /** * @author xiaolongzuo */ @Configuration +@Conditional(MigrateOnConditionMissingClass.class) @ConditionalOnMissingBean(DiscoveryClient.class) @EnableConfigurationProperties @AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class) diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java index a8bc64c7c..87cdcd591 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/endpoint/AnsEndpoint.java @@ -16,19 +16,18 @@ package org.springframework.cloud.alicloud.ans.endpoint; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.alibaba.ans.core.NamingService; +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.cloud.alicloud.context.ans.AnsProperties; -import com.alibaba.ans.core.NamingService; -import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author xiaolongzuo @@ -36,7 +35,7 @@ import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; @Endpoint(id = "ans") public class AnsEndpoint { - private static final Logger LOGGER = LoggerFactory.getLogger(AnsEndpoint.class); + private static final Log log = LogFactory.getLog(AnsEndpoint.class); private AnsProperties ansProperties; @@ -50,7 +49,7 @@ public class AnsEndpoint { @ReadOperation public Map invoke() { Map ansEndpoint = new HashMap<>(); - LOGGER.info("ANS endpoint invoke, ansProperties is {}", ansProperties); + log.info("ANS endpoint invoke, ansProperties is " + ansProperties); ansEndpoint.put("ansProperties", ansProperties); Map subscribes = new HashMap<>(); @@ -65,7 +64,7 @@ public class AnsEndpoint { } } ansEndpoint.put("subscribes", subscribes); - LOGGER.info("ANS endpoint invoke, subscribes is {}", subscribes); + log.info("ANS endpoint invoke, subscribes is " + subscribes); return ansEndpoint; } diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java new file mode 100644 index 000000000..16b99d7b8 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpoint.java @@ -0,0 +1,31 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; + +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +@Endpoint(id = "migrate") +public class MigrateEndpoint { + + private static final Log log = LogFactory.getLog(MigrateEndpoint.class); + + public MigrateEndpoint() { + } + + /** + * @return ans endpoint + */ + @ReadOperation + public Map> invoke() { + + Map> result = ServerListInvocationHandler + .getServerRegistry(); + + log.info("migrate server list :" + result); + return result; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java new file mode 100644 index 000000000..bc80cfc23 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateEndpointAutoConfiguration.java @@ -0,0 +1,18 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; + +@ConditionalOnWebApplication + +@ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.annotation.Endpoint") +@Conditional(MigrateOnConditionClass.class) +public class MigrateEndpointAutoConfiguration { + + @Bean + public MigrateEndpoint ansEndpoint() { + return new MigrateEndpoint(); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java new file mode 100644 index 000000000..96050181e --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnCondition.java @@ -0,0 +1,49 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.ClassUtils; + +/** + * @author pbting + */ +public abstract class MigrateOnCondition implements Condition, BeanClassLoaderAware { + + final String[] conditionOnClass = new String[] { + "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistration", + "org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration" }; + + ClassLoader classLoader; + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public abstract boolean matches(ConditionContext context, + AnnotatedTypeMetadata metadata); + + boolean isPresent(String className, ClassLoader classLoader) { + if (classLoader == null) { + classLoader = ClassUtils.getDefaultClassLoader(); + } + + try { + forName(className, classLoader); + return true; + } + catch (Throwable var3) { + return false; + } + } + + Class forName(String className, ClassLoader classLoader) + throws ClassNotFoundException { + return classLoader != null ? classLoader.loadClass(className) + : Class.forName(className); + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java new file mode 100644 index 000000000..cf5ee82ad --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionClass.java @@ -0,0 +1,22 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * @author pbting + */ +public class MigrateOnConditionClass extends MigrateOnCondition { + + protected static final Log log = LogFactory.getLog(MigrateOnConditionClass.class); + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + boolean result = isPresent(conditionOnClass[0], classLoader) + || isPresent(conditionOnClass[1], classLoader); + log.info("the result of MigrateOnConditionClass is :" + result); + return result; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java new file mode 100644 index 000000000..e5651c6f9 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateOnConditionMissingClass.java @@ -0,0 +1,23 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * @author pbting + */ +public class MigrateOnConditionMissingClass extends MigrateOnConditionClass { + + protected static final Log log = LogFactory + .getLog(MigrateOnConditionMissingClass.class); + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + boolean result = !super.matches(context, metadata); + log.info("the result of MigrateOnConditionMissingClass is :" + result); + return result; + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java new file mode 100644 index 000000000..df2800829 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateProxyManager.java @@ -0,0 +1,94 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.aopalliance.aop.Advice; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.aop.AfterReturningAdvice; +import org.springframework.aop.framework.ProxyFactory; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ServerList; + +/** + * @author pbting + */ +final class MigrateProxyManager { + + private final static Log log = LogFactory.getLog(MigrateProxyManager.class); + private final static AtomicBoolean IS_PROXY = new AtomicBoolean(true); + + private final static Set SERVICES_ID = new ConcurrentSkipListSet<>(); + + private static Object springProxyFactory(Object target, ClassLoader classLoader, + List adviceList, Class... interfaces) { + final ProxyFactory proxyFactory = new ProxyFactory(interfaces); + proxyFactory.setTarget(target); + adviceList.forEach(advice -> proxyFactory.addAdvice(advice)); + return proxyFactory.getProxy(classLoader); + } + + static Object newServerListProxy(Object bean, ClassLoader classLoader, + IClientConfig clientConfig) { + bean = springProxyFactory(bean, classLoader, + Arrays.asList(new ServerListInvocationHandler(clientConfig)), + new Class[] { ServerList.class }); + log.info("[service id]" + clientConfig.getClientName() + + " new a ServerList proxy instance for spring cloud netflix to spring cloud alibaba "); + collectServiceId(clientConfig.getClientName()); + return bean; + } + + static Object newLoadBalancerProxy(Object bean, ClassLoader classLoader, + IClientConfig clientConfig) { + + bean = springProxyFactory(bean, classLoader, + Arrays.asList(new AfterReturningAdvice() { + @Override + public void afterReturning(Object returnValue, Method method, + Object[] args, Object target) { + String methodName = method.getName(); + if ("chooseServer".equals(methodName)) { + String serviceId = clientConfig.getClientName(); + Server server = (Server) returnValue; + ServerListInvocationHandler.incrementCallService(serviceId, + server); + } + } + }), new Class[] { ILoadBalancer.class }); + log.info("[service id]" + clientConfig.getClientName() + + " new a ILoadBalancer proxy instance for spring cloud netflix to spring cloud alibaba "); + return bean; + } + + static void migrateProxyClose() { + IS_PROXY.set(false); + } + + static void migrateProxyUp() { + IS_PROXY.set(true); + } + + static boolean isMigrateProxy() { + + return IS_PROXY.get(); + } + + static void collectServiceId(String serviceId) { + SERVICES_ID.add(serviceId); + } + + static Set getServicesId() { + + return Collections.unmodifiableSet(SERVICES_ID); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java new file mode 100644 index 000000000..620776d9a --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRefreshEventListener.java @@ -0,0 +1,75 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import com.netflix.loadbalancer.ILoadBalancer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.context.named.NamedContextFactory; +import org.springframework.cloud.endpoint.event.RefreshEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * @author pbting + */ +@Component +public class MigrateRefreshEventListener implements ApplicationListener { + + private final static String MIGRATE_SWITCH = "sca.migrate.ans.switch"; + + private volatile String lastScaMigrateAnsSwitchValue = "true"; + + @Autowired + private Environment environment; + + @Autowired + private NamedContextFactory namedContextFactory; + + public MigrateRefreshEventListener() { + } + + @PostConstruct + public void initTimerCheck() { + Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay( + () -> onApplicationEvent(null), 1, 1, TimeUnit.SECONDS); + } + + @Override + public void onApplicationEvent(RefreshEvent event) { + String value = environment.getProperty(MIGRATE_SWITCH, "true"); + // check 1: check the value + if (value.equals(lastScaMigrateAnsSwitchValue)) { + return; + } + + updateLastScaMigrateAnsResetValue(value); + + // step 1: migrate up + if ("true".equals(value)) { + MigrateProxyManager.migrateProxyUp(); + serviceIdContextInit(); + return; + } + + // step 2: migrate close + if ("false".equals(value)) { + MigrateProxyManager.migrateProxyClose(); + serviceIdContextInit(); + return; + } + } + + private void serviceIdContextInit() { + namedContextFactory.destroy(); + // initializer each spring context for service id + MigrateProxyManager.getServicesId().forEach(serviceId -> namedContextFactory + .getInstance(serviceId, ILoadBalancer.class)); + } + + private synchronized void updateLastScaMigrateAnsResetValue(String value) { + this.lastScaMigrateAnsSwitchValue = value; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java new file mode 100644 index 000000000..c863399b0 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateRibbonBeanPostProcessor.java @@ -0,0 +1,53 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.config.BeanPostProcessor; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.ServerList; + +public class MigrateRibbonBeanPostProcessor + implements BeanPostProcessor, BeanClassLoaderAware { + + protected static final Log log = LogFactory.getLog(MigrateOnCondition.class); + + private ClassLoader classLoader; + private IClientConfig clientConfig; + + public MigrateRibbonBeanPostProcessor(IClientConfig clientConfig) { + this.clientConfig = clientConfig; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + + // step 1 : check the bean whether proxy or not + if (!MigrateProxyManager.isMigrateProxy()) { + log.info("Migrate proxy is Close."); + return bean; + } + + // step 2 : proxy the designated bean + if (bean instanceof ServerList) { + bean = MigrateProxyManager.newServerListProxy(bean, classLoader, + clientConfig); + } + + if (bean instanceof ILoadBalancer) { + bean = MigrateProxyManager.newLoadBalancerProxy(bean, classLoader, + clientConfig); + } + return bean; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java new file mode 100644 index 000000000..5491e98df --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrateServiceRegistry.java @@ -0,0 +1,51 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.boot.web.context.WebServerInitializedEvent; +import org.springframework.cloud.alicloud.ans.registry.AnsRegistration; +import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationContext; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author pbting + */ +@Component +public class MigrateServiceRegistry { + + private static final Log log = LogFactory.getLog(MigrateServiceRegistry.class); + + private AtomicBoolean running = new AtomicBoolean(false); + + private ServiceRegistry serviceRegistry; + private AnsRegistration ansRegistration; + + public MigrateServiceRegistry(AnsProperties ansProperties, + ApplicationContext context) { + this.ansRegistration = new AnsRegistration(ansProperties, context); + this.ansRegistration.init(); + this.serviceRegistry = new AnsServiceRegistry(); + } + + @EventListener(WebServerInitializedEvent.class) + public void onApplicationEvent(WebServerInitializedEvent event) { + int serverPort = event.getWebServer().getPort(); + this.ansRegistration.setPort(serverPort); + log.info("[ Migrate ] change the port to " + serverPort); + if (!this.running.get()) { + long s = System.currentTimeMillis(); + log.info("[Migrate] start to registry server to ANS"); + this.serviceRegistry.register(this.ansRegistration); + log.info("[migrate] end to registry server to ANS cost time with " + + (System.currentTimeMillis() - s) + " ms."); + this.running.set(true); + } + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java new file mode 100644 index 000000000..45ae571f4 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/MigrationAutoconfiguration.java @@ -0,0 +1,25 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alicloud.ans.ConditionalOnAnsEnabled; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties +@Conditional(MigrateOnConditionClass.class) +@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) +@ConditionalOnAnsEnabled +public class MigrationAutoconfiguration { + + @Bean + public MigrateServiceRegistry migrationManger(AnsProperties ansProperties, + ApplicationContext applicationContext) { + + return new MigrateServiceRegistry(ansProperties, applicationContext); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java new file mode 100644 index 000000000..2a8f1b4f2 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerListInvocationHandler.java @@ -0,0 +1,143 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.Server; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.cloud.alicloud.ans.ribbon.AnsServer; +import org.springframework.cloud.alicloud.ans.ribbon.AnsServerList; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +/** + * + */ +class ServerListInvocationHandler implements MethodInterceptor { + + private final static Log log = LogFactory.getLog(ServerListInvocationHandler.class); + + private final static ConcurrentMap> CALL_SERVICE_COUNT = new ConcurrentHashMap<>(); + private final static Set INTERCEPTOR_METHOD_NAME = new ConcurrentSkipListSet(); + + private IClientConfig clientConfig; + private AnsServerList ansServerList; + private AtomicBoolean isFirst = new AtomicBoolean(false); + + static { + INTERCEPTOR_METHOD_NAME.add("getInitialListOfServers"); + INTERCEPTOR_METHOD_NAME.add("getUpdatedListOfServers"); + } + + ServerListInvocationHandler(IClientConfig clientConfig) { + this.clientConfig = clientConfig; + this.ansServerList = new AnsServerList(clientConfig.getClientName()); + } + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + String methodName = invocation.getMethod().getName(); + // step 1: check the method is not interceptor + if (!INTERCEPTOR_METHOD_NAME.contains(methodName)) { + return invocation.proceed(); + } + + // step 2: interceptor the method + List serverList = (List) invocation.proceed(); + long s = System.currentTimeMillis(); + log.info("[ START ] merage server list for " + clientConfig.getClientName()); + serverList = mergeAnsServerList(serverList); + log.info("[ END ] merage server list for " + clientConfig.getClientName() + + ", cost time " + (System.currentTimeMillis() - s) + " ms ."); + return serverList; + } + + /** + * 后台线程 和 Eureka 两个注册中心进行 Merage 的时候,List 表中始终保持是有效的 Server. 即不考虑 ANS 客户端本地容灾的情况 + */ + private List mergeAnsServerList(final List source) { + if (isFirst.compareAndSet(false, true)) { + return source; + } + + // step 1: get all of server list and filter the alive + List ansServerList = filterAliveAnsServer( + this.ansServerList.getInitialListOfServers()); + + if (ansServerList.isEmpty()) { + return source; + } + + log.info("[" + this.clientConfig.getClientName() + "] Get Server List from ANS:" + + ansServerList + "; loadbalancer server list override before:" + source); + + // step 2:remove servers of that have in load balancer list + final Iterator serverIterator = source.iterator(); + while (serverIterator.hasNext()) { + final Server server = serverIterator.next(); + ansServerList.forEach(ansServer -> { + if (server.getHostPort() + .equals(ansServer.getHealthService().toInetAddr())) { + // fix bug: mast be set the zone, update server list,will filter + // by: ZoneAffinityPredicate + ansServer.setZone(server.getZone()); + ansServer.setSchemea(server.getScheme()); + ansServer.setId(server.getId()); + ansServer.setReadyToServe(true); + serverIterator.remove(); + log.info("Source Server is remove " + server.getHostPort() + + ", and from ANS Server is override:" + + ansServer.toString()); + } + }); + } + + ansServerList.forEach(ansServer -> source.add(ansServer)); + log.info("[" + this.clientConfig.getClientName() + "] " + + "; loadbalancer server list override after:" + source); + // override + return source; + } + + private List filterAliveAnsServer(List sourceServerList) { + final List resultServerList = new LinkedList<>(); + sourceServerList.forEach(ansServer -> { + boolean isAlive = ansServer.isAlive(3); + if (isAlive) { + resultServerList.add(ansServer); + } + log.warn(ansServer.toString() + " isAlive :" + isAlive); + }); + return resultServerList; + } + + static Map> getServerRegistry() { + + return Collections.unmodifiableMap(CALL_SERVICE_COUNT); + } + + static void incrementCallService(String serviceId, Server server) { + ConcurrentMap concurrentHashMap = CALL_SERVICE_COUNT + .putIfAbsent(serviceId, new ConcurrentHashMap<>()); + + if (concurrentHashMap == null) { + concurrentHashMap = CALL_SERVICE_COUNT.get(serviceId); + } + + String ipPort = server.getHostPort(); + ServerWrapper serverWraper = concurrentHashMap.putIfAbsent(ipPort, + new ServerWrapper(server, new AtomicLong())); + + if (serverWraper == null) { + serverWraper = concurrentHashMap.get(ipPort); + } + serverWraper.setServer(server); + serverWraper.getCallCount().incrementAndGet(); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java new file mode 100644 index 000000000..aeaa5a60e --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/migrate/ServerWrapper.java @@ -0,0 +1,35 @@ +package org.springframework.cloud.alicloud.ans.migrate; + +import com.netflix.loadbalancer.Server; + +import java.util.concurrent.atomic.AtomicLong; + +public class ServerWrapper { + + private Server server; + private AtomicLong callCount; + + public ServerWrapper() { + } + + public ServerWrapper(Server server, AtomicLong callCount) { + this.server = server; + this.callCount = callCount; + } + + public Server getServer() { + return server; + } + + public void setServer(Server server) { + this.server = server; + } + + public AtomicLong getCallCount() { + return callCount; + } + + public void setCallCount(AtomicLong callCount) { + this.callCount = callCount; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java index 0774f1856..b48c94b2d 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistration.java @@ -16,8 +16,8 @@ package org.springframework.cloud.alicloud.ans.registry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; @@ -30,8 +30,7 @@ import org.springframework.util.StringUtils; */ public class AnsAutoServiceRegistration extends AbstractAutoServiceRegistration { - private static final Logger LOGGER = LoggerFactory - .getLogger(AnsAutoServiceRegistration.class); + private static final Log log = LogFactory.getLog(AnsAutoServiceRegistration.class); @Autowired private AnsRegistration registration; @@ -59,13 +58,13 @@ public class AnsAutoServiceRegistration @Override protected AnsRegistration getManagementRegistration() { - return null; + return registration; } @Override protected void register() { if (!this.registration.getAnsProperties().isRegisterEnabled()) { - LOGGER.debug("Registration disabled."); + log.debug("Registration disabled."); return; } if (this.registration.getPort() < 0) { diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java index 1fcb292f3..e28bf4779 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java @@ -16,12 +16,6 @@ package org.springframework.cloud.alicloud.ans.registry; -import java.net.URI; -import java.util.Map; - -import javax.annotation.PostConstruct; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.alicloud.context.ans.AnsProperties; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance; @@ -31,6 +25,10 @@ import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; +import javax.annotation.PostConstruct; +import java.net.URI; +import java.util.Map; + /** * @author xiaolongzuo */ @@ -40,12 +38,14 @@ public class AnsRegistration implements Registration, ServiceInstance { private static final String MANAGEMENT_CONTEXT_PATH = "management.context-path"; private static final String MANAGEMENT_ADDRESS = "management.address"; - @Autowired private AnsProperties ansProperties; - - @Autowired private ApplicationContext context; + public AnsRegistration(AnsProperties ansProperties, ApplicationContext context) { + this.ansProperties = ansProperties; + this.context = context; + } + @PostConstruct public void init() { @@ -64,6 +64,11 @@ public class AnsRegistration implements Registration, ServiceInstance { metadata.put(MANAGEMENT_ADDRESS, address); } } + + String serverPort = env.getProperty("server.port"); + if (null != serverPort) { + this.setPort(Integer.valueOf(serverPort)); + } } @Override diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java index ebe65ee39..1ff187a35 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsServiceRegistry.java @@ -16,24 +16,23 @@ package org.springframework.cloud.alicloud.ans.registry; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - +import com.alibaba.ans.core.NamingService; +import com.alibaba.ans.shaded.com.taobao.vipserver.client.ipms.NodeReactor; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import com.alibaba.ans.core.NamingService; -import com.alibaba.ans.shaded.com.taobao.vipserver.client.ipms.NodeReactor; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * @author xiaolongzuo */ public class AnsServiceRegistry implements ServiceRegistry { - private static Logger logger = LoggerFactory.getLogger(AnsServiceRegistry.class); + private static Log log = LogFactory.getLog(AnsServiceRegistry.class); private static final String SEPARATOR = ","; @@ -41,11 +40,11 @@ public class AnsServiceRegistry implements ServiceRegistry { public void register(AnsRegistration registration) { if (!registration.isRegisterEnabled()) { - logger.info("Registration is disabled..."); + log.info("Registration is disabled..."); return; } if (StringUtils.isEmpty(registration.getServiceId())) { - logger.info("No service to register for client..."); + log.info("No service to register for client..."); return; } @@ -63,13 +62,14 @@ public class AnsServiceRegistry implements ServiceRegistry { NamingService.regDom(dom, registration.getHost(), registration.getPort(), registration.getRegisterWeight(dom), registration.getCluster(), tags); - logger.info("INFO_ANS_REGISTER, {} {}:{} register finished", dom, - registration.getAnsProperties().getClientIp(), - registration.getAnsProperties().getClientPort()); + log.info("INFO_ANS_REGISTER, " + dom + " " + + registration.getAnsProperties().getClientIp() + ":" + + registration.getAnsProperties().getClientPort() + + " register finished"); } catch (Exception e) { - logger.error("ERR_ANS_REGISTER, {} register failed...{},", dom, - registration.toString(), e); + log.error("ERR_ANS_REGISTER, " + dom + " register failed..." + + registration.toString() + ",", e); } } } @@ -77,10 +77,10 @@ public class AnsServiceRegistry implements ServiceRegistry { @Override public void deregister(AnsRegistration registration) { - logger.info("De-registering from ANSServer now..."); + log.info("De-registering from ANSServer now..."); if (StringUtils.isEmpty(registration.getServiceId())) { - logger.info("No dom to de-register for client..."); + log.info("No dom to de-register for client..."); return; } @@ -89,11 +89,11 @@ public class AnsServiceRegistry implements ServiceRegistry { registration.getPort(), registration.getCluster()); } catch (Exception e) { - logger.error("ERR_ANS_DEREGISTER, de-register failed...{},", - registration.toString(), e); + log.error("ERR_ANS_DEREGISTER, de-register failed..." + + registration.toString() + ",", e); } - logger.info("De-registration finished."); + log.info("De-registration finished."); } @Override diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java index 7734e0371..93393ed9e 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfiguration.java @@ -17,7 +17,9 @@ package org.springframework.cloud.alicloud.ans.ribbon; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import com.netflix.client.config.IClientConfig; @@ -27,11 +29,12 @@ import com.netflix.loadbalancer.ServerList; * @author xiaolongzuo */ @Configuration +@Conditional(MigrateOnConditionMissingClass.class) public class AnsRibbonClientConfiguration { @Bean @ConditionalOnMissingBean - public ServerList ribbonServerList(IClientConfig config) { + public ServerList ansRibbonServerList(IClientConfig config) { AnsServerList serverList = new AnsServerList(config.getClientName()); return serverList; } diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java index 8438a7f35..d19f62870 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServer.java @@ -16,12 +16,16 @@ package org.springframework.cloud.alicloud.ans.ribbon; -import java.util.Collections; -import java.util.Map; - import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; import com.netflix.loadbalancer.Server; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + /** * @author xiaolongzuo */ @@ -34,7 +38,8 @@ public class AnsServer extends Server { public AnsServer(final Host host, final String dom) { super(host.getIp(), host.getPort()); this.host = host; - this.metadata = Collections.emptyMap(); + this.metadata = new HashMap(); + this.metadata.put("source", "ANS"); metaInfo = new MetaInfo() { @Override public String getAppName() { @@ -48,16 +53,44 @@ public class AnsServer extends Server { @Override public String getServiceIdForDiscovery() { - return null; + return dom; } @Override public String getInstanceId() { - return null; + return AnsServer.this.host.getIp() + ":" + dom + ":" + + AnsServer.this.host.getPort(); } }; } + @Override + public boolean isAlive() { + + return true; + } + + /** + * + * @param timeOut Unit: Seconds + * @return + */ + public boolean isAlive(long timeOut) { + try { + String hostName = this.host.getHostname(); + hostName = hostName != null && hostName.trim().length() > 0 ? hostName + : this.host.getIp(); + Socket socket = new Socket(); + socket.connect(new InetSocketAddress(hostName, this.host.getPort()), + (int) TimeUnit.SECONDS.toMillis(timeOut)); + socket.close(); + return true; + } + catch (IOException e) { + return false; + } + } + @Override public MetaInfo getMetaInfo() { return metaInfo; @@ -71,4 +104,9 @@ public class AnsServer extends Server { return metadata; } + @Override + public String toString() { + return "AnsServer{" + "metaInfo=" + metaInfo + ", host=" + host + ", metadata=" + + metadata + '}'; + } } diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java index f34f19ffd..d6a3d9df5 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerList.java @@ -60,10 +60,12 @@ public class AnsServerList extends AbstractServerList { List result = new ArrayList(hosts.size()); for (Host host : hosts) { if (host.isValid()) { - result.add(hostToServer(host)); + AnsServer ansServer = hostToServer(host); + if (ansServer.isAlive(3)) { + result.add(ansServer); + } } } - return result; } diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java new file mode 100644 index 000000000..5bda207c3 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/MigrateRibbonCofiguration.java @@ -0,0 +1,20 @@ +package org.springframework.cloud.alicloud.ans.ribbon; + +import org.springframework.cloud.alicloud.ans.migrate.MigrateRibbonBeanPostProcessor; +import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +import com.netflix.client.config.IClientConfig; + +@Configuration +@Conditional(MigrateOnConditionClass.class) +public class MigrateRibbonCofiguration { + + @Bean + public MigrateRibbonBeanPostProcessor migrateBeanPostProcessor(IClientConfig clientConfig) { + + return new MigrateRibbonBeanPostProcessor(clientConfig); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java index 4333cb534..cf7d52ff1 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/ribbon/RibbonAnsAutoConfiguration.java @@ -34,6 +34,7 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnBean(SpringClientFactory.class) @ConditionalOnRibbonAns @AutoConfigureAfter(RibbonAutoConfiguration.class) -@RibbonClients(defaultConfiguration = AnsRibbonClientConfiguration.class) +@RibbonClients(defaultConfiguration = { AnsRibbonClientConfiguration.class, + MigrateRibbonCofiguration.class }) public class RibbonAnsAutoConfiguration { } diff --git a/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories b/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories index 63d6cd5c8..050c64ec2 100644 --- a/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories @@ -1,6 +1,10 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alicloud.ans.endpoint.AnsEndpointAutoConfiguration,\ org.springframework.cloud.alicloud.ans.ribbon.RibbonAnsAutoConfiguration,\ - org.springframework.cloud.alicloud.ans.AnsAutoConfiguration + org.springframework.cloud.alicloud.ans.AnsAutoConfiguration,\ + org.springframework.cloud.alicloud.ans.migrate.MigrateEndpointAutoConfiguration,\ + org.springframework.cloud.alicloud.ans.migrate.MigrationAutoconfiguration org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration +org.springframework.context.ApplicationListener=\ + org.springframework.cloud.alicloud.ans.migrate.MigrateRefreshEventListener \ No newline at end of file diff --git a/spring-cloud-alicloud-context/pom.xml b/spring-cloud-alicloud-context/pom.xml index 39e73ab50..496aea377 100644 --- a/spring-cloud-alicloud-context/pom.xml +++ b/spring-cloud-alicloud-context/pom.xml @@ -50,6 +50,12 @@ provided + + com.alibaba.ans + ans-sdk + provided + + com.aliyun.oss aliyun-sdk-oss diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java new file mode 100644 index 000000000..022c5e19d --- /dev/null +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java @@ -0,0 +1,107 @@ +package org.springframework.cloud.alicloud.context.sms; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.alicloud.context.AliCloudProperties; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import java.io.Serializable; + +/** + * @author pbting + */ +@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms") +public class SmsConfigProperties implements Serializable { + + // 产品名称:云通信短信API产品,开发者无需替换 + public static final String smsProduct = "Dysmsapi"; + // 产品域名,开发者无需替换 + public static final String smsDomain = "dysmsapi.aliyuncs.com"; + + private AliCloudProperties aliCloudProperties; + + /** + * + */ + private String reportQueueName; + /** + * + */ + private String upQueueName; + + /** + * + */ + protected String connnectTimeout = "10000"; + + /** + * + */ + protected String readTimeout = "10000"; + + public SmsConfigProperties(AliCloudProperties aliCloudProperties) { + this.aliCloudProperties = aliCloudProperties; + } + + public String getConnnectTimeout() { + return connnectTimeout; + } + + public void setConnnectTimeout(String connnectTimeout) { + this.connnectTimeout = connnectTimeout; + } + + public String getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(String readTimeout) { + this.readTimeout = readTimeout; + } + + public void overiideFromEnv(Environment environment) { + overiideCustomFromEnv(environment); + if (StringUtils.isEmpty(connnectTimeout)) { + String resolveResult = environment.resolveRequiredPlaceholders( + "${spring.cloud.alibaba.sms.connect-timeout:}"); + this.setConnnectTimeout( + StringUtils.isEmpty(resolveResult) ? "10000" : resolveResult); + } + + if (StringUtils.isEmpty(readTimeout)) { + String resolveResult = environment.resolveRequiredPlaceholders( + "${spring.cloud.alibaba.sms.read-timeout:}"); + this.setReadTimeout( + StringUtils.isEmpty(resolveResult) ? "10000" : resolveResult); + } + } + + public void overiideCustomFromEnv(Environment environment) { + // nothing to do + } + + public String getReportQueueName() { + return reportQueueName; + } + + public void setReportQueueName(String reportQueueName) { + this.reportQueueName = reportQueueName; + } + + public String getUpQueueName() { + return upQueueName; + } + + public String getAccessKeyId() { + return aliCloudProperties.getAccessKey(); + } + + public String getAccessKeySecret() { + return aliCloudProperties.getSecretKey(); + } + + public void setUpQueueName(String upQueueName) { + this.upQueueName = upQueueName; + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java new file mode 100644 index 000000000..555642627 --- /dev/null +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java @@ -0,0 +1,26 @@ +package org.springframework.cloud.alicloud.context.sms; + +import org.springframework.core.env.Environment; + +import javax.annotation.PostConstruct; + +/** + * @author pbting + */ +public class SmsConfigRegistration { + + private Environment environment; + + private SmsConfigProperties smsConfigProperties; + + public SmsConfigRegistration(Environment environment, + SmsConfigProperties smsConfigProperties) { + this.environment = environment; + this.smsConfigProperties = smsConfigProperties; + } + + @PostConstruct + public void initSmsConfigRegistration() { + smsConfigProperties.overiideFromEnv(environment); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java new file mode 100644 index 000000000..6f1e44160 --- /dev/null +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java @@ -0,0 +1,30 @@ +package org.springframework.cloud.alicloud.context.sms; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alicloud.context.AliCloudProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@EnableConfigurationProperties +@ConditionalOnClass(name = "com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest") +@ConditionalOnProperty(value = "spring.cloud.alibaba.deshao.enable.sms", matchIfMissing = true) +public class SmsContextAutoConfiguration { + + @Bean + public SmsConfigProperties smsConfigProperties( + AliCloudProperties aliCloudProperties) { + + return new SmsConfigProperties(aliCloudProperties); + } + + @Bean + public SmsConfigRegistration smsConfigRegistration(Environment environment, + SmsConfigProperties smsConfigProperties) { + + return new SmsConfigRegistration(environment, smsConfigProperties); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/resources/META-INF/spring.factories b/spring-cloud-alicloud-context/src/main/resources/META-INF/spring.factories index a14c70778..f99f05028 100644 --- a/spring-cloud-alicloud-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alicloud-context/src/main/resources/META-INF/spring.factories @@ -6,7 +6,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alicloud.context.ans.AnsContextAutoConfiguration,\ org.springframework.cloud.alicloud.context.oss.OssContextAutoConfiguration,\ org.springframework.cloud.alicloud.context.scx.ScxContextAutoConfiguration,\ - org.springframework.cloud.alicloud.context.statistics.StatisticsTaskStarter + org.springframework.cloud.alicloud.context.statistics.StatisticsTaskStarter,\ + org.springframework.cloud.alicloud.context.sms.SmsContextAutoConfiguration org.springframework.context.ApplicationListener=\ org.springframework.cloud.alicloud.context.ans.AnsContextApplicationListener,\ org.springframework.cloud.alicloud.context.nacos.NacosParameterInitListener,\ diff --git a/spring-cloud-alicloud-sms/pom.xml b/spring-cloud-alicloud-sms/pom.xml new file mode 100644 index 000000000..001a46adc --- /dev/null +++ b/spring-cloud-alicloud-sms/pom.xml @@ -0,0 +1,83 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba + 0.2.2.BUILD-SNAPSHOT + + 4.0.0 + + org.springframework.cloud + spring-cloud-alicloud-sms + Spring Cloud Alibaba Cloud SMS + + + + + org.springframework.cloud + spring-cloud-alicloud-context + + + com.aliyun + aliyun-java-sdk-core + + + + + + + com.aliyun + aliyun-java-sdk-core + + + com.aliyun + aliyun-java-sdk-dysmsapi + + + com.aliyun.mns + aliyun-sdk-mns + + + com.aliyun + aliyun-java-sdk-dysmsapi + + + + org.springframework.boot + spring-boot-actuator + provided + true + + + + org.springframework.boot + spring-boot-actuator-autoconfigure + provided + true + + + + org.springframework.boot + spring-boot-configuration-processor + provided + true + + + + org.slf4j + slf4j-api + provided + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java new file mode 100644 index 000000000..02273a696 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.profile.DefaultProfile; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author pbting + */ +public abstract class AbstractSmsService implements ISmsService { + + private ConcurrentHashMap acsClientConcurrentHashMap = new ConcurrentHashMap<>(); + + public IAcsClient getHangZhouRegionClientProfile(String accessKeyId, + String accessKeySecret) { + + return acsClientConcurrentHashMap.computeIfAbsent( + getKey("cn-hangzhou", accessKeyId, accessKeySecret), + (iacsClient) -> new DefaultAcsClient(DefaultProfile + .getProfile("cn-hangzhou", accessKeyId, accessKeySecret))); + } + + private String getKey(String regionId, String accessKeyId, String accessKeySecret) { + + return regionId + ":" + accessKeyId + ":" + accessKeySecret; + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/ISmsService.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/ISmsService.java new file mode 100644 index 000000000..54a8201cf --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/ISmsService.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.*; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; + +/** + * @author pbting + */ +public interface ISmsService { + + /** + * + * @param accessKeyId + * @param secret + * @return IAcsClient + */ + IAcsClient getHangZhouRegionClientProfile(String accessKeyId, String secret); + + /** + * + * @param sendSmsRequest + * @throws ServerException + * @throws ClientException + * @return SendSmsResponse + */ + SendSmsResponse sendSmsRequest(SendSmsRequest sendSmsRequest) + throws ServerException, ClientException; + + /** + * + * @param sendBatchSmsRequest + * @throws ServerException + * @throws ClientException + * @return SendBatchSmsResponse + */ + SendBatchSmsResponse sendSmsBatchRequest(SendBatchSmsRequest sendBatchSmsRequest) + throws ServerException, ClientException; + + /** + * 因为阿里云支持多个 + * accessKeyId/accessKeySecret,当不想使用默认的配置accessKeyId/accessKeySecret时,可以使用这个方法来支持额外 + * 的accessKeyId/accessKeySecret 发送 + * @param sendSmsRequest + * @param accessKeyId + * @param accessKeySecret + * @return + * @throws ServerException + * @throws ClientException + */ + SendSmsResponse sendSmsRequest(SendSmsRequest sendSmsRequest, String accessKeyId, + String accessKeySecret) throws ServerException, ClientException; + + /** + * + * @param sendSmsRequest + * @param accessKeyId + * @param accessKeySecret + * @throws ServerException + * @throws ClientException + * @return SendBatchSmsResponse + */ + SendBatchSmsResponse sendSmsBatchRequest(SendBatchSmsRequest sendSmsRequest, + String accessKeyId, String accessKeySecret) + throws ServerException, ClientException; + + /** + * + * @param smsReportMessageListener + * @return boolean + */ + boolean startSmsReportMessageListener( + SmsReportMessageListener smsReportMessageListener); + + /** + * + * @param smsUpMessageListener + * @return boolean + */ + boolean startSmsUpMessageListener(SmsUpMessageListener smsUpMessageListener); + + /** + * + * @param request + * @param accessKeyId + * @param accessKeySecret + * @return QuerySendDetailsResponse + */ + QuerySendDetailsResponse querySendDetails(QuerySendDetailsRequest request, + String accessKeyId, String accessKeySecret) throws ClientException; + + /** + * + * @param request + * @return QuerySendDetailsResponse + */ + QuerySendDetailsResponse querySendDetails(QuerySendDetailsRequest request) + throws ClientException; +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java new file mode 100644 index 000000000..0556ea068 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.profile.DefaultProfile; +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.cloud.alicloud.context.sms.SmsConfigProperties; +import org.springframework.cloud.alicloud.sms.base.MessageListener; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author pbting + */ +@Component +public class SmsInitializerEventListener + implements ApplicationListener { + + private final AtomicBoolean isCalled = new AtomicBoolean(false); + + private SmsConfigProperties msConfigProperties; + + private ISmsService smsService; + + public SmsInitializerEventListener(SmsConfigProperties msConfigProperties, + ISmsService smsService) { + this.msConfigProperties = msConfigProperties; + this.smsService = smsService; + } + + @Override + public void onApplicationEvent(ApplicationStartedEvent event) { + if (!isCalled.compareAndSet(false, true)) { + return; + } + + // 整个application context refreshed then do + // 可自助调整超时时间 + System.setProperty("sun.net.client.defaultConnectTimeout", + msConfigProperties.getConnnectTimeout()); + System.setProperty("sun.net.client.defaultReadTimeout", + msConfigProperties.getReadTimeout()); + // 初始化acsClient,暂不支持region化 + try { + DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", + SmsConfigProperties.smsProduct, SmsConfigProperties.smsDomain); + Collection messageListeners = event.getApplicationContext() + .getBeansOfType(MessageListener.class).values(); + if (messageListeners.isEmpty()) { + return; + } + + for (MessageListener messageListener : messageListeners) { + if (SmsReportMessageListener.class.isInstance(messageListener)) { + if (msConfigProperties.getReportQueueName() != null + && msConfigProperties.getReportQueueName().trim() + .length() > 0) { + smsService.startSmsReportMessageListener( + (SmsReportMessageListener) messageListener); + continue; + } + + throw new IllegalArgumentException("the SmsReport queue name for " + + messageListener.getClass().getCanonicalName() + + " must be set."); + } + + if (SmsUpMessageListener.class.isInstance(messageListener)) { + + if (msConfigProperties.getUpQueueName() != null + && msConfigProperties.getUpQueueName().trim().length() > 0) { + smsService.startSmsUpMessageListener( + (SmsUpMessageListener) messageListener); + continue; + } + + throw new IllegalArgumentException("the SmsUp queue name for " + + messageListener.getClass().getCanonicalName() + + " must be set."); + } + } + } + catch (ClientException e) { + throw new RuntimeException( + "initialize sms profile end point cause an exception"); + } + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsMessageListener.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsMessageListener.java new file mode 100644 index 000000000..5fc34dd52 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsMessageListener.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +import org.springframework.cloud.alicloud.sms.base.MessageListener; + +/** + * @author pbting + */ +public interface SmsMessageListener extends MessageListener { +} diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsReportMessageListener.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsReportMessageListener.java new file mode 100644 index 000000000..c214a628e --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsReportMessageListener.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +/** + * @author pbting + */ +public interface SmsReportMessageListener extends SmsMessageListener { +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java new file mode 100644 index 000000000..d32c8c64a --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +import com.aliyuncs.dysmsapi.model.v20170525.*; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.cloud.alicloud.context.sms.SmsConfigProperties; +import org.springframework.cloud.alicloud.sms.base.DefaultAlicomMessagePuller; +import org.springframework.cloud.alicloud.sms.endpoint.EndpointManager; +import org.springframework.cloud.alicloud.sms.endpoint.ReceiveMessageEntity; + +import java.text.ParseException; + +/** + * @author pbting + */ +public final class SmsServiceImpl extends AbstractSmsService { + + private static final Log log = LogFactory.getLog(SmsServiceImpl.class); + /** + * will expose user to call this method send sms message + * @param sendSmsRequest + * @return + */ + private SmsConfigProperties smsConfigProperties; + + public SmsServiceImpl(SmsConfigProperties smsConfigProperties) { + this.smsConfigProperties = smsConfigProperties; + } + + public SendSmsResponse sendSmsRequest(SendSmsRequest sendSmsRequest) + throws ClientException { + + return sendSmsRequest(sendSmsRequest, smsConfigProperties.getAccessKeyId(), + smsConfigProperties.getAccessKeySecret()); + } + + /** + * 因为阿里云支持多个 + * accessKeyId/accessKeySecret,当不想使用默认的配置accessKeyId/accessKeySecret时,可以使用这个方法来支持额外 + * 的accessKeyId/accessKeySecret 发送 + * @param sendSmsRequest + * @param accessKeyId + * @param accessKeySecret + * @throws ServerException + * @throws ClientException + * @return SendSmsResponse + */ + public SendSmsResponse sendSmsRequest(SendSmsRequest sendSmsRequest, + String accessKeyId, String accessKeySecret) + throws ServerException, ClientException { + EndpointManager.addSendSmsRequest(sendSmsRequest); + // hint 此处可能会抛出异常,注意catch + return getHangZhouRegionClientProfile(accessKeyId, accessKeySecret) + .getAcsResponse(sendSmsRequest); + } + + /** + * + * @param smsReportMessageListener + * @return boolean + */ + public boolean startSmsReportMessageListener( + SmsReportMessageListener smsReportMessageListener) { + String messageType = "SmsReport";// 短信回执:SmsReport,短信上行:SmsUp + String queueName = smsConfigProperties.getReportQueueName(); + return startReceiveMsg(messageType, queueName, smsReportMessageListener); + } + + /** + * + * @param smsUpMessageListener + * @return boolean + */ + public boolean startSmsUpMessageListener(SmsUpMessageListener smsUpMessageListener) { + String messageType = "SmsUp";// 短信回执:SmsReport,短信上行:SmsUp + String queueName = smsConfigProperties.getUpQueueName(); + return startReceiveMsg(messageType, queueName, smsUpMessageListener); + } + + /** + * + * @param messageType + * @param queueName + * @param messageListener + * @return boolean + */ + private boolean startReceiveMsg(String messageType, String queueName, + SmsMessageListener messageListener) { + String accessKeyId = smsConfigProperties.getAccessKeyId(); + String accessKeySecret = smsConfigProperties.getAccessKeySecret(); + boolean result = true; + try { + new DefaultAlicomMessagePuller().startReceiveMsg(accessKeyId, accessKeySecret, + messageType, queueName, messageListener); + EndpointManager.addReceiveMessageEntity( + new ReceiveMessageEntity(messageType, queueName, messageListener)); + } + catch (ClientException e) { + log.error("start sms report message listener cause an exception", e); + result = false; + } + catch (ParseException e) { + log.error("start sms report message listener cause an exception", e); + result = false; + } + return result; + } + + /** + * + * @param sendBatchSmsRequest + * @throws ServerException + * @throws ClientException + * @return SendBatchSmsResponse + */ + @Override + public SendBatchSmsResponse sendSmsBatchRequest( + SendBatchSmsRequest sendBatchSmsRequest) + throws ServerException, ClientException { + + return sendSmsBatchRequest(sendBatchSmsRequest, + smsConfigProperties.getAccessKeyId(), + smsConfigProperties.getAccessKeySecret()); + } + + /** + * + * @param sendBatchSmsRequest + * @param accessKeyId + * @param accessKeySecret + * @throws ClientException + * @return SendBatchSmsResponse + */ + @Override + public SendBatchSmsResponse sendSmsBatchRequest( + SendBatchSmsRequest sendBatchSmsRequest, String accessKeyId, + String accessKeySecret) throws ClientException { + EndpointManager.addSendBatchSmsRequest(sendBatchSmsRequest); + return getHangZhouRegionClientProfile(accessKeyId, accessKeySecret) + .getAcsResponse(sendBatchSmsRequest); + } + + /** + * + * @param request + * @param accessKeyId + * @param accessKeySecret + * @throws ClientException + * @return QuerySendDetailsResponse + */ + @Override + public QuerySendDetailsResponse querySendDetails(QuerySendDetailsRequest request, + String accessKeyId, String accessKeySecret) throws ClientException { + return getHangZhouRegionClientProfile(accessKeyId, accessKeySecret) + .getAcsResponse(request); + } + + /** + * + * @param request + * @throws ClientException + * @return QuerySendDetailsResponse + */ + @Override + public QuerySendDetailsResponse querySendDetails(QuerySendDetailsRequest request) + throws ClientException { + return querySendDetails(request, smsConfigProperties.getAccessKeyId(), + smsConfigProperties.getAccessKeySecret()); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsUpMessageListener.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsUpMessageListener.java new file mode 100644 index 000000000..4da614382 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsUpMessageListener.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms; + +/** + * @author pbting + */ +public interface SmsUpMessageListener extends SmsMessageListener { +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/DefaultAlicomMessagePuller.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/DefaultAlicomMessagePuller.java new file mode 100755 index 000000000..50fe2ed6e --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/DefaultAlicomMessagePuller.java @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.common.ClientException; +import com.aliyun.mns.common.ServiceException; +import com.aliyun.mns.model.Message; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; + +/** + * 阿里通信官方消息默认拉取工具类 + */ +public class DefaultAlicomMessagePuller { + + private Log logger = LogFactory.getLog(DefaultAlicomMessagePuller.class); + + private String mnsAccountEndpoint = "https://1943695596114318.mns.cn-hangzhou.aliyuncs.com/";// 阿里通信消息的endpoint,固定。 + private String endpointNameForPop = "cn-hangzhou"; + private String regionIdForPop = "cn-hangzhou"; + private String domainForPop = "dybaseapi.aliyuncs.com"; + private TokenGetterForAlicom tokenGetter; + private MessageListener messageListener; + private boolean isRunning = false; + private Integer pullMsgThreadSize = 1; + private boolean debugLogOpen = false; + private Integer sleepSecondWhenNoData = 30; + + public void openDebugLog(boolean debugLogOpen) { + this.debugLogOpen = debugLogOpen; + } + + public Integer getSleepSecondWhenNoData() { + return sleepSecondWhenNoData; + } + + public void setSleepSecondWhenNoData(Integer sleepSecondWhenNoData) { + this.sleepSecondWhenNoData = sleepSecondWhenNoData; + } + + public Integer getPullMsgThreadSize() { + return pullMsgThreadSize; + } + + public void setPullMsgThreadSize(Integer pullMsgThreadSize) { + if (pullMsgThreadSize != null && pullMsgThreadSize > 1) { + this.pullMsgThreadSize = pullMsgThreadSize; + } + } + + private ExecutorService executorService; + + public ExecutorService getExecutorService() { + return executorService; + } + + public void setExecutorService(ExecutorService executorService) { + this.executorService = executorService; + } + + protected static final Map sLockObjMap = new HashMap(); + protected static Map sPollingMap = new ConcurrentHashMap(); + protected Object lockObj; + + public boolean setPolling(String queueName) { + synchronized (lockObj) { + Boolean ret = sPollingMap.get(queueName); + if (ret == null || !ret) { + sPollingMap.put(queueName, true); + return true; + } + return false; + } + } + + public void clearPolling(String queueName) { + synchronized (lockObj) { + sPollingMap.put(queueName, false); + lockObj.notifyAll(); + if (debugLogOpen) { + logger.info("PullMessageTask_WakeUp:Everyone WakeUp and Work!"); + } + } + } + + public boolean isRunning() { + return isRunning; + } + + public void setRunning(boolean running) { + isRunning = running; + } + + private class PullMessageTask implements Runnable { + private String messageType; + private String queueName; + + @Override + public void run() { + + boolean polling = false; + while (isRunning) { + try { + synchronized (lockObj) { + Boolean p = sPollingMap.get(queueName); + if (p != null && p) { + try { + if (debugLogOpen) { + logger.info("PullMessageTask_sleep:" + + Thread.currentThread().getName() + + " Have a nice sleep!"); + } + polling = false; + lockObj.wait(); + } + catch (InterruptedException e) { + if (debugLogOpen) { + logger.info("PullMessageTask_Interrupted!" + + Thread.currentThread().getName() + + " QueueName is " + queueName); + } + continue; + } + } + } + + TokenForAlicom tokenObject = tokenGetter.getTokenByMessageType( + messageType, queueName, mnsAccountEndpoint); + CloudQueue queue = tokenObject.getQueue(); + Message popMsg = null; + if (!polling) { + popMsg = queue.popMessage(); + if (debugLogOpen) { + SimpleDateFormat format = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + logger.info("PullMessageTask_popMessage:" + + Thread.currentThread().getName() + "-popDone at " + + "," + format.format(new Date()) + " msgSize=" + + (popMsg == null ? 0 : popMsg.getMessageId())); + } + if (popMsg == null) { + polling = true; + continue; + } + } + else { + if (setPolling(queueName)) { + if (debugLogOpen) { + logger.info("PullMessageTask_setPolling:" + + Thread.currentThread().getName() + " Polling!"); + } + } + else { + continue; + } + do { + if (debugLogOpen) { + logger.info("PullMessageTask_Keep_Polling" + + Thread.currentThread().getName() + + "KEEP Polling!"); + } + try { + popMsg = queue.popMessage(sleepSecondWhenNoData); + } + catch (ClientException e) { + if (debugLogOpen) { + logger.info( + "PullMessageTask_Pop_Message:ClientException Refresh accessKey" + + e); + } + tokenObject = tokenGetter.getTokenByMessageType( + messageType, queueName, mnsAccountEndpoint); + queue = tokenObject.getQueue(); + + } + catch (ServiceException e) { + if (debugLogOpen) { + logger.info( + "PullMessageTask_Pop_Message:ServiceException Refresh accessKey" + + e); + } + tokenObject = tokenGetter.getTokenByMessageType( + messageType, queueName, mnsAccountEndpoint); + queue = tokenObject.getQueue(); + + } + catch (Exception e) { + if (debugLogOpen) { + logger.info( + "PullMessageTask_Pop_Message:Exception Happened when polling popMessage: " + + e); + } + } + } + while (popMsg == null && isRunning); + clearPolling(queueName); + } + boolean dealResult = messageListener.dealMessage(popMsg); + if (dealResult) { + // remember to delete message when consume message successfully. + if (debugLogOpen) { + logger.info("PullMessageTask_Deal_Message:" + + Thread.currentThread().getName() + "deleteMessage " + + popMsg.getMessageId()); + } + queue.deleteMessage(popMsg.getReceiptHandle()); + } + } + catch (ClientException e) { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName, e); + break; + + } + catch (ServiceException e) { + if (e.getErrorCode().equals("AccessDenied")) { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName + + ",please check messageType and queueName", e); + } + else { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName, e); + } + break; + + } + catch (com.aliyuncs.exceptions.ClientException e) { + if (e.getErrCode().equals("InvalidAccessKeyId.NotFound")) { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName + + ",please check AccessKeyId", e); + } + if (e.getErrCode().equals("SignatureDoesNotMatch")) { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName + + ",please check AccessKeySecret", e); + } + else { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName, e); + } + break; + + } + catch (Exception e) { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName, e); + try { + Thread.sleep(sleepSecondWhenNoData); + } + catch (InterruptedException e1) { + logger.error("PullMessageTask_execute_error,messageType:" + + messageType + ",queueName:" + queueName, e); + } + } + } + + } + + } + + /** + * @param accessKeyId accessKeyId + * @param accessKeySecret accessKeySecret + * @param messageType 消息类型 + * @param queueName 队列名称 + * @param messageListener 回调的listener,用户自己实现 + * @throws com.aliyuncs.exceptions.ClientException + * @throws ParseException + */ + public void startReceiveMsg(String accessKeyId, String accessKeySecret, + String messageType, String queueName, MessageListener messageListener) + throws com.aliyuncs.exceptions.ClientException, ParseException { + + tokenGetter = new TokenGetterForAlicom(accessKeyId, accessKeySecret, + endpointNameForPop, regionIdForPop, domainForPop, null); + + this.messageListener = messageListener; + isRunning = true; + PullMessageTask task = new PullMessageTask(); + task.messageType = messageType; + task.queueName = queueName; + + synchronized (sLockObjMap) { + lockObj = sLockObjMap.get(queueName); + if (lockObj == null) { + lockObj = new Object(); + sLockObjMap.put(queueName, lockObj); + } + } + + if (executorService == null) { + ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor( + pullMsgThreadSize, + new BasicThreadFactory.Builder() + .namingPattern( + "PullMessageTask-" + messageType + "-thread-pool-%d") + .daemon(true).build()); + executorService = scheduledExecutorService; + } + for (int i = 0; i < pullMsgThreadSize; i++) { + executorService.execute(task); + } + } + + /** + * @param accessKeyId accessKeyId + * @param accessKeySecret accessKeySecret + * @param messageType 消息类型 + * @param queueName 队列名称 + * @param messageListener 回调的listener,用户自己实现 + * @throws com.aliyuncs.exceptions.ClientException + * @throws ParseException + */ + public void startReceiveMsgForVPC(String accessKeyId, String accessKeySecret, + String messageType, String queueName, String regionIdForPop, + String endpointNameForPop, String domainForPop, String mnsAccountEndpoint, + MessageListener messageListener) + throws com.aliyuncs.exceptions.ClientException, ParseException { + this.mnsAccountEndpoint = mnsAccountEndpoint; + tokenGetter = new TokenGetterForAlicom(accessKeyId, accessKeySecret, + endpointNameForPop, regionIdForPop, domainForPop, null); + + this.messageListener = messageListener; + isRunning = true; + PullMessageTask task = new PullMessageTask(); + task.messageType = messageType; + task.queueName = queueName; + + synchronized (sLockObjMap) { + lockObj = sLockObjMap.get(queueName); + if (lockObj == null) { + lockObj = new Object(); + sLockObjMap.put(queueName, lockObj); + } + } + + if (executorService == null) { + ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor( + pullMsgThreadSize, + new BasicThreadFactory.Builder() + .namingPattern( + "PullMessageTask-" + messageType + "-thread-pool-%d") + .daemon(true).build()); + executorService = scheduledExecutorService; + } + for (int i = 0; i < pullMsgThreadSize; i++) { + executorService.execute(task); + } + } + + /** + * 虚商用户定制接收消息方法 + * @param accessKeyId accessKeyId + * @param accessKeySecret accessKeySecret + * @param ownerId 实际的ownerId + * @param messageType 消息类型 + * @param queueName 队列名称 + * @param messageListener 回调listener + * @throws com.aliyuncs.exceptions.ClientException + * @throws ParseException + */ + public void startReceiveMsgForPartnerUser(String accessKeyId, String accessKeySecret, + Long ownerId, String messageType, String queueName, + MessageListener messageListener) + throws com.aliyuncs.exceptions.ClientException, ParseException { + + tokenGetter = new TokenGetterForAlicom(accessKeyId, accessKeySecret, + endpointNameForPop, regionIdForPop, domainForPop, ownerId); + + this.messageListener = messageListener; + isRunning = true; + PullMessageTask task = new PullMessageTask(); + task.messageType = messageType; + task.queueName = queueName; + + synchronized (sLockObjMap) { + lockObj = sLockObjMap.get(queueName); + if (lockObj == null) { + lockObj = new Object(); + sLockObjMap.put(queueName, lockObj); + } + } + + if (executorService == null) { + ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor( + pullMsgThreadSize, + new BasicThreadFactory.Builder() + .namingPattern( + "PullMessageTask-" + messageType + "-thread-pool-%d") + .daemon(true).build()); + executorService = scheduledExecutorService; + } + for (int i = 0; i < pullMsgThreadSize; i++) { + executorService.execute(task); + } + } + + public void stop() { + isRunning = false; + } + +} diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/MessageListener.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/MessageListener.java new file mode 100755 index 000000000..9921232a6 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/MessageListener.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyun.mns.model.Message; + +public interface MessageListener { + + boolean dealMessage(Message message); + +} diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueRequest.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueRequest.java new file mode 100644 index 000000000..956ecadbf --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueRequest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyuncs.RpcAcsRequest; + +public class QueryTokenForMnsQueueRequest + extends RpcAcsRequest { + private String resourceOwnerAccount; + private String messageType; + private Long resourceOwnerId; + private Long ownerId; + + public QueryTokenForMnsQueueRequest() { + super("Dybaseapi", "2017-05-25", "QueryTokenForMnsQueue"); + } + + public String getResourceOwnerAccount() { + return this.resourceOwnerAccount; + } + + public void setResourceOwnerAccount(String resourceOwnerAccount) { + this.resourceOwnerAccount = resourceOwnerAccount; + if (resourceOwnerAccount != null) { + this.putQueryParameter("ResourceOwnerAccount", resourceOwnerAccount); + } + + } + + public String getMessageType() { + return this.messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + if (messageType != null) { + this.putQueryParameter("MessageType", messageType); + } + + } + + public Long getResourceOwnerId() { + return this.resourceOwnerId; + } + + public void setResourceOwnerId(Long resourceOwnerId) { + this.resourceOwnerId = resourceOwnerId; + if (resourceOwnerId != null) { + this.putQueryParameter("ResourceOwnerId", resourceOwnerId.toString()); + } + + } + + public Long getOwnerId() { + return this.ownerId; + } + + public void setOwnerId(Long ownerId) { + this.ownerId = ownerId; + if (ownerId != null) { + this.putQueryParameter("OwnerId", ownerId.toString()); + } + + } + + public Class getResponseClass() { + return QueryTokenForMnsQueueResponse.class; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponse.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponse.java new file mode 100644 index 000000000..56c401714 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponse.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyuncs.AcsResponse; +import com.aliyuncs.transform.UnmarshallerContext; + +public class QueryTokenForMnsQueueResponse extends AcsResponse { + private String requestId; + private String code; + private String message; + private QueryTokenForMnsQueueResponse.MessageTokenDTO messageTokenDTO; + + public QueryTokenForMnsQueueResponse() { + } + + public String getRequestId() { + return this.requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getCode() { + return this.code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + public QueryTokenForMnsQueueResponse.MessageTokenDTO getMessageTokenDTO() { + return this.messageTokenDTO; + } + + public void setMessageTokenDTO( + QueryTokenForMnsQueueResponse.MessageTokenDTO messageTokenDTO) { + this.messageTokenDTO = messageTokenDTO; + } + + public QueryTokenForMnsQueueResponse getInstance(UnmarshallerContext context) { + return QueryTokenForMnsQueueResponseUnmarshaller.unmarshall(this, context); + } + + public static class MessageTokenDTO { + private String accessKeyId; + private String accessKeySecret; + private String securityToken; + private String createTime; + private String expireTime; + + public MessageTokenDTO() { + } + + public String getAccessKeyId() { + return this.accessKeyId; + } + + public void setAccessKeyId(String accessKeyId) { + this.accessKeyId = accessKeyId; + } + + public String getAccessKeySecret() { + return this.accessKeySecret; + } + + public void setAccessKeySecret(String accessKeySecret) { + this.accessKeySecret = accessKeySecret; + } + + public String getSecurityToken() { + return this.securityToken; + } + + public void setSecurityToken(String securityToken) { + this.securityToken = securityToken; + } + + public String getCreateTime() { + return this.createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getExpireTime() { + return this.expireTime; + } + + public void setExpireTime(String expireTime) { + this.expireTime = expireTime; + } + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponseUnmarshaller.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponseUnmarshaller.java new file mode 100644 index 000000000..627e8bb5f --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/QueryTokenForMnsQueueResponseUnmarshaller.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyuncs.transform.UnmarshallerContext; + +public class QueryTokenForMnsQueueResponseUnmarshaller { + + public QueryTokenForMnsQueueResponseUnmarshaller() { + } + + public static QueryTokenForMnsQueueResponse unmarshall( + QueryTokenForMnsQueueResponse queryTokenForMnsQueueResponse, + UnmarshallerContext context) { + queryTokenForMnsQueueResponse.setRequestId( + context.stringValue("QueryTokenForMnsQueueResponse.RequestId")); + queryTokenForMnsQueueResponse + .setCode(context.stringValue("QueryTokenForMnsQueueResponse.Code")); + queryTokenForMnsQueueResponse + .setMessage(context.stringValue("QueryTokenForMnsQueueResponse.Message")); + QueryTokenForMnsQueueResponse.MessageTokenDTO messageTokenDTO = new QueryTokenForMnsQueueResponse.MessageTokenDTO(); + messageTokenDTO.setAccessKeyId(context.stringValue( + "QueryTokenForMnsQueueResponse.MessageTokenDTO.AccessKeyId")); + messageTokenDTO.setAccessKeySecret(context.stringValue( + "QueryTokenForMnsQueueResponse.MessageTokenDTO.AccessKeySecret")); + messageTokenDTO.setSecurityToken(context.stringValue( + "QueryTokenForMnsQueueResponse.MessageTokenDTO.SecurityToken")); + messageTokenDTO.setCreateTime(context + .stringValue("QueryTokenForMnsQueueResponse.MessageTokenDTO.CreateTime")); + messageTokenDTO.setExpireTime(context + .stringValue("QueryTokenForMnsQueueResponse.MessageTokenDTO.ExpireTime")); + queryTokenForMnsQueueResponse.setMessageTokenDTO(messageTokenDTO); + return queryTokenForMnsQueueResponse; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenForAlicom.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenForAlicom.java new file mode 100755 index 000000000..8af1a63c2 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenForAlicom.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.client.MNSClient; + +/** + * 用于接收云通信消息的临时token + * + */ +public class TokenForAlicom { + private String messageType; + private String token; + private Long expireTime; + private String tempAccessKeyId; + private String tempAccessKeySecret; + private MNSClient client; + private CloudQueue queue; + + public String getMessageType() { + return messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public Long getExpireTime() { + return expireTime; + } + + public void setExpireTime(Long expireTime) { + this.expireTime = expireTime; + } + + public String getTempAccessKeyId() { + return tempAccessKeyId; + } + + public void setTempAccessKeyId(String tempAccessKeyId) { + this.tempAccessKeyId = tempAccessKeyId; + } + + public String getTempAccessKeySecret() { + return tempAccessKeySecret; + } + + public void setTempAccessKeySecret(String tempAccessKeySecret) { + this.tempAccessKeySecret = tempAccessKeySecret; + } + + public MNSClient getClient() { + return client; + } + + public void setClient(MNSClient client) { + this.client = client; + } + + public CloudQueue getQueue() { + return queue; + } + + public void setQueue(CloudQueue queue) { + this.queue = queue; + } + + public void closeClient() { + if (client != null) { + this.client.close(); + } + } + +} diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenGetterForAlicom.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenGetterForAlicom.java new file mode 100755 index 000000000..270f9a56b --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/base/TokenGetterForAlicom.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.base; + +import com.aliyun.mns.client.CloudAccount; +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.client.MNSClient; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; +import com.aliyuncs.http.FormatType; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.http.ProtocolType; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 获取接收云通信消息的临时token + * + */ +public class TokenGetterForAlicom { + private Log logger = LogFactory.getLog(TokenGetterForAlicom.class); + private String accessKeyId; + private String accessKeySecret; + private String endpointNameForPop; + private String regionIdForPop; + private String domainForPop; + private IAcsClient iAcsClient; + private Long ownerId; + private final static String productName = "Dybaseapi"; + private long bufferTime = 1000 * 60 * 2;// 过期时间小于2分钟则重新获取,防止服务器时间误差 + private final Object lock = new Object(); + private ConcurrentMap tokenMap = new ConcurrentHashMap(); + + public TokenGetterForAlicom(String accessKeyId, String accessKeySecret, + String endpointNameForPop, String regionIdForPop, String domainForPop, + Long ownerId) throws ClientException { + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.endpointNameForPop = endpointNameForPop; + this.regionIdForPop = regionIdForPop; + this.domainForPop = domainForPop; + this.ownerId = ownerId; + init(); + } + + private void init() throws ClientException { + DefaultProfile.addEndpoint(endpointNameForPop, regionIdForPop, productName, + domainForPop); + IClientProfile profile = DefaultProfile.getProfile(regionIdForPop, accessKeyId, + accessKeySecret); + profile.getHttpClientConfig().setCompatibleMode(true); + iAcsClient = new DefaultAcsClient(profile); + } + + private TokenForAlicom getTokenFromRemote(String messageType) + throws ServerException, ClientException, ParseException { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); + QueryTokenForMnsQueueRequest request = new QueryTokenForMnsQueueRequest(); + request.setAcceptFormat(FormatType.JSON); + request.setMessageType(messageType); + request.setOwnerId(ownerId); + request.setProtocol(ProtocolType.HTTPS); + request.setMethod(MethodType.POST); + QueryTokenForMnsQueueResponse response = iAcsClient.getAcsResponse(request); + String resultCode = response.getCode(); + if (resultCode != null && "OK".equals(resultCode)) { + QueryTokenForMnsQueueResponse.MessageTokenDTO dto = response + .getMessageTokenDTO(); + TokenForAlicom token = new TokenForAlicom(); + String timeStr = dto.getExpireTime(); + token.setMessageType(messageType); + token.setExpireTime(df.parse(timeStr).getTime()); + token.setToken(dto.getSecurityToken()); + token.setTempAccessKeyId(dto.getAccessKeyId()); + token.setTempAccessKeySecret(dto.getAccessKeySecret()); + return token; + } + else { + logger.error("getTokenFromRemote_error,messageType:" + messageType + ",code:" + + response.getCode() + ",message:" + response.getMessage()); + throw new ServerException(response.getCode(), response.getMessage()); + } + } + + public TokenForAlicom getTokenByMessageType(String messageType, String queueName, + String mnsAccountEndpoint) + throws ServerException, ClientException, ParseException { + TokenForAlicom token = tokenMap.get(messageType); + Long now = System.currentTimeMillis(); + if (token == null || (token.getExpireTime() - now) < bufferTime) {// 过期时间小于2分钟则重新获取,防止服务器时间误差 + synchronized (lock) { + token = tokenMap.get(messageType); + if (token == null || (token.getExpireTime() - now) < bufferTime) { + TokenForAlicom oldToken = null; + if (token != null) { + oldToken = token; + } + token = getTokenFromRemote(messageType); + // 因为换token时需要重建client和关闭老的client,所以创建client的代码和创建token放在一起 + CloudAccount account = new CloudAccount(token.getTempAccessKeyId(), + token.getTempAccessKeySecret(), mnsAccountEndpoint, + token.getToken()); + // logger.warn("ak:"+token.getTempAccessKey()); + // logger.warn("token:"+token.getToken()); + MNSClient client = account.getMNSClient(); + CloudQueue queue = client.getQueueRef(queueName); + token.setClient(client); + token.setQueue(queue); + tokenMap.put(messageType, token); + if (oldToken != null) { + oldToken.closeClient(); + } + } + } + } + return token; + } +} diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java new file mode 100644 index 000000000..12e1760ba --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alicloud.context.sms.SmsConfigProperties; +import org.springframework.cloud.alicloud.sms.ISmsService; +import org.springframework.cloud.alicloud.sms.SmsInitializerEventListener; +import org.springframework.cloud.alicloud.sms.SmsServiceImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; + +/** + * @author pbting + */ +@Configuration +@EnableConfigurationProperties +@ConditionalOnClass(value = SendSmsRequest.class) +@ConditionalOnProperty(value = "spring.cloud.alicloud.sms.enable", matchIfMissing = true) +public class SmsAutoConfiguration { + + @Bean + public SmsServiceImpl smsService(SmsConfigProperties smsConfigProperties) { + return new SmsServiceImpl(smsConfigProperties); + } + + @Bean + public SmsInitializerEventListener smsInitializePostListener( + SmsConfigProperties msConfigProperties, ISmsService smsService) { + return new SmsInitializerEventListener(msConfigProperties, smsService); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/EndpointManager.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/EndpointManager.java new file mode 100644 index 000000000..3b807d08e --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/EndpointManager.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.endpoint; + +import com.aliyuncs.dysmsapi.model.v20170525.SendBatchSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.locks.ReentrantLock; + +/** + * + */ +public final class EndpointManager { + + private final static int BACKLOG_SIZE = 20; + + private final static ReentrantLock SEND_REENTRANT_LOCK = new ReentrantLock(true); + private final static ReentrantLock SEND_BATCH_REENTRANT_LOCK = new ReentrantLock( + true); + + private final static LinkedBlockingQueue SEND_SMS_REQUESTS = new LinkedBlockingQueue( + BACKLOG_SIZE); + private final static LinkedBlockingQueue SEND_BATCH_SMS_REQUESTS = new LinkedBlockingQueue( + BACKLOG_SIZE); + private final static LinkedBlockingQueue RECEIVE_MESSAGE_ENTITIES = new LinkedBlockingQueue( + BACKLOG_SIZE); + + public static void addSendSmsRequest(SendSmsRequest sendSmsRequest) { + if (SEND_SMS_REQUESTS.offer(sendSmsRequest)) { + return; + } + try { + SEND_REENTRANT_LOCK.lock(); + SEND_SMS_REQUESTS.poll(); + SEND_SMS_REQUESTS.offer(sendSmsRequest); + } + finally { + SEND_REENTRANT_LOCK.unlock(); + } + } + + public static void addSendBatchSmsRequest(SendBatchSmsRequest sendBatchSmsRequest) { + if (SEND_BATCH_SMS_REQUESTS.offer(sendBatchSmsRequest)) { + return; + } + try { + SEND_BATCH_REENTRANT_LOCK.lock(); + SEND_BATCH_SMS_REQUESTS.poll(); + SEND_BATCH_SMS_REQUESTS.offer(sendBatchSmsRequest); + } + finally { + SEND_BATCH_REENTRANT_LOCK.unlock(); + } + } + + public static void addReceiveMessageEntity( + ReceiveMessageEntity receiveMessageEntity) { + if (RECEIVE_MESSAGE_ENTITIES.offer(receiveMessageEntity)) { + return; + } + RECEIVE_MESSAGE_ENTITIES.poll(); + RECEIVE_MESSAGE_ENTITIES.offer(receiveMessageEntity); + } + + public static Map getSmsEndpointMessage() { + List sendSmsRequests = new LinkedList<>(); + List sendBatchSmsRequests = new LinkedList<>(); + List receiveMessageEntities = new LinkedList<>(); + try { + SEND_REENTRANT_LOCK.lock(); + SEND_BATCH_REENTRANT_LOCK.lock(); + sendSmsRequests.addAll(SEND_SMS_REQUESTS); + sendBatchSmsRequests.addAll(SEND_BATCH_SMS_REQUESTS); + } + finally { + SEND_REENTRANT_LOCK.unlock(); + SEND_BATCH_REENTRANT_LOCK.unlock(); + } + receiveMessageEntities.addAll(RECEIVE_MESSAGE_ENTITIES); + + Map endpointMessages = new HashMap<>(); + endpointMessages.put("send-sms-request", sendSmsRequests); + endpointMessages.put("send-batch-sms-request", sendBatchSmsRequests); + endpointMessages.put("message-listener", receiveMessageEntities); + + return endpointMessages; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/ReceiveMessageEntity.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/ReceiveMessageEntity.java new file mode 100644 index 000000000..3e941c3c5 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/ReceiveMessageEntity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.endpoint; + +import org.springframework.cloud.alicloud.sms.base.MessageListener; + +import java.io.Serializable; + +/** + * @author pbting + */ +public class ReceiveMessageEntity implements Serializable { + private String messageType; + private String queueName; + private MessageListener messageListener; + + public ReceiveMessageEntity(String messageType, String queueName, + MessageListener messageListener) { + this.messageType = messageType; + this.queueName = queueName; + this.messageListener = messageListener; + } + + public String getMessageType() { + return messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + } + + public String getQueueName() { + return queueName; + } + + public void setQueueName(String queueName) { + this.queueName = queueName; + } + + public MessageListener getMessageListener() { + return messageListener; + } + + public void setMessageListener(MessageListener messageListener) { + this.messageListener = messageListener; + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpoint.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpoint.java new file mode 100644 index 000000000..d254e0ebe --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpoint.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.endpoint; + +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; + +import java.util.Map; + +@Endpoint(id = "sms-info") +public class SmsEndpoint { + + @ReadOperation + public Map invoke() { + + return EndpointManager.getSmsEndpointMessage(); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpointAutoConfiguration.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpointAutoConfiguration.java new file mode 100644 index 000000000..1db0ec254 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/endpoint/SmsEndpointAutoConfiguration.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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.sms.endpoint; + +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; + +@ConditionalOnWebApplication +@ConditionalOnClass(Endpoint.class) +public class SmsEndpointAutoConfiguration { + + @Bean + public SmsEndpoint smsEndpoint() { + return new SmsEndpoint(); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/resources/META-INF/spring.factories b/spring-cloud-alicloud-sms/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..875d39db0 --- /dev/null +++ b/spring-cloud-alicloud-sms/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.springframework.cloud.alicloud.sms.config.SmsAutoConfiguration,\ + org.springframework.cloud.alicloud.sms.endpoint.SmsEndpointAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-starter-alicloud/pom.xml b/spring-cloud-starter-alicloud/pom.xml index 5427b6eca..df47cfbbd 100644 --- a/spring-cloud-starter-alicloud/pom.xml +++ b/spring-cloud-starter-alicloud/pom.xml @@ -15,5 +15,6 @@ spring-cloud-starter-alicloud-acm spring-cloud-starter-alicloud-ans spring-cloud-starter-alicloud-schedulerx + spring-cloud-starter-alicloud-sms \ No newline at end of file diff --git a/spring-cloud-starter-alicloud/spring-cloud-starter-alicloud-sms/pom.xml b/spring-cloud-starter-alicloud/spring-cloud-starter-alicloud-sms/pom.xml new file mode 100644 index 000000000..57a398f76 --- /dev/null +++ b/spring-cloud-starter-alicloud/spring-cloud-starter-alicloud-sms/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.springframework.cloud + spring-cloud-starter-alicloud + 0.2.2.BUILD-SNAPSHOT + + spring-cloud-starter-alicloud-sms + Spring Cloud Starter Alibaba Cloud SMS + + + + org.springframework.cloud + spring-cloud-alicloud-sms + + + +