浏览代码

:tada: 3.0.0.RELEASE 架构升级适配 SpringCloud 2020

smallchill 4 年之前
父节点
当前提交
17d8fce5f7
共有 79 个文件被更改,包括 797 次插入786 次删除
  1. 3 3
      README.md
  2. 1 1
      blade-core-boot/pom.xml
  3. 1 1
      blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeBootAutoConfiguration.java
  4. 1 1
      blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeWebMvcConfiguration.java
  5. 1 1
      blade-core-boot/src/main/java/org/springblade/core/boot/config/MybatisPlusConfiguration.java
  6. 1 1
      blade-core-boot/src/main/java/org/springblade/core/boot/config/RetryConfiguration.java
  7. 1 1
      blade-core-boot/src/main/java/org/springblade/core/boot/logger/RequestLogAspect.java
  8. 1 1
      blade-core-boot/src/main/java/org/springblade/core/boot/tenant/TenantConfiguration.java
  9. 1 1
      blade-core-boot/src/main/resources/bootstrap.yml
  10. 6 26
      blade-core-cloud/pom.xml
  11. 42 0
      blade-core-cloud/src/main/java/org/springblade/core/cloud/client/BladeCloudApplication.java
  12. 54 0
      blade-core-cloud/src/main/java/org/springblade/core/cloud/config/BladeCloudAutoConfiguration.java
  13. 1 1
      blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFallbackFactory.java
  14. 0 96
      blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignAutoConfiguration.java
  15. 2 2
      blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignFallback.java
  16. 136 0
      blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignSentinel.java
  17. 3 0
      blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/EnableBladeFeign.java
  18. 2 2
      blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeAccountGetter.java
  19. 2 2
      blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeFeignAccountGetter.java
  20. 1 2
      blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeFeignRequestHeaderInterceptor.java
  21. 4 4
      blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeHttpHeadersCallable.java
  22. 5 5
      blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeHttpHeadersContextHolder.java
  23. 8 6
      blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java
  24. 5 5
      blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateHeaderInterceptor.java
  25. 0 71
      blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHystrixAutoConfiguration.java
  26. 0 93
      blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHystrixConcurrencyStrategy.java
  27. 2 2
      blade-core-cloud/src/main/java/org/springblade/core/cloud/props/BladeFeignHeadersProperties.java
  28. 26 0
      blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java
  29. 168 0
      blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelInvocationHandler.java
  30. 1 2
      blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeSpringMvcContract.java
  31. 1 1
      blade-core-cloud/src/main/java/org/springblade/core/cloud/version/VersionMappingAutoConfiguration.java
  32. 0 230
      blade-core-cloud/src/main/java/org/springframework/cloud/openfeign/BladeFeignClientsRegistrar.java
  33. 0 99
      blade-core-cloud/src/main/java/org/springframework/cloud/openfeign/BladeHystrixTargeter.java
  34. 0 39
      blade-core-cloud/src/main/java/org/springframework/cloud/openfeign/Targeter.java
  35. 1 1
      blade-core-develop/pom.xml
  36. 1 1
      blade-core-launch/pom.xml
  37. 1 1
      blade-core-launch/src/main/java/org/springblade/core/launch/StartEventListener.java
  38. 1 1
      blade-core-launch/src/main/java/org/springblade/core/launch/config/BladeLaunchConfiguration.java
  39. 1 1
      blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
  40. 1 1
      blade-core-launch/src/main/java/org/springblade/core/launch/server/ServerInfo.java
  41. 1 1
      blade-core-log/pom.xml
  42. 1 1
      blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
  43. 1 1
      blade-core-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java
  44. 4 2
      blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java
  45. 1 1
      blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
  46. 1 1
      blade-core-mybatis/pom.xml
  47. 1 1
      blade-core-oss/pom.xml
  48. 1 1
      blade-core-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java
  49. 1 1
      blade-core-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java
  50. 1 1
      blade-core-report/pom.xml
  51. 1 1
      blade-core-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java
  52. 1 1
      blade-core-secure/pom.xml
  53. 1 1
      blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java
  54. 1 1
      blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
  55. 1 1
      blade-core-social/pom.xml
  56. 1 1
      blade-core-social/src/main/java/org/springblade/core/social/config/SocialConfiguration.java
  57. 1 1
      blade-core-swagger/pom.xml
  58. 1 1
      blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerAutoConfiguration.java
  59. 1 1
      blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java
  60. 1 1
      blade-core-test/pom.xml
  61. 0 30
      blade-core-test/src/main/java/org/springblade/core/test/BladeBaseTest.java
  62. 2 0
      blade-core-test/src/main/java/org/springblade/core/test/BladeBootTest.java
  63. 11 8
      blade-core-test/src/main/java/org/springblade/core/test/BladeSpringExtension.java
  64. 1 1
      blade-core-tool/pom.xml
  65. 1 1
      blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java
  66. 1 1
      blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java
  67. 1 1
      blade-core-tool/src/main/java/org/springblade/core/tool/config/RedisTemplateConfiguration.java
  68. 1 1
      blade-core-tool/src/main/java/org/springblade/core/tool/config/ToolConfiguration.java
  69. 1 1
      blade-core-tool/src/main/java/org/springblade/core/tool/config/XssConfiguration.java
  70. 2 2
      blade-core-tool/src/main/java/org/springblade/core/tool/utils/RedisUtil.java
  71. 1 1
      blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java
  72. 7 1
      blade-core-transaction/pom.xml
  73. 33 0
      blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignBlockingLoadBalancerClient.java
  74. 85 0
      blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignClientAutoConfiguration.java
  75. 74 0
      blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignObjectWrapper.java
  76. 49 0
      blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataRetryableFeignBlockingLoadBalancerClient.java
  77. 3 2
      blade-core-transaction/src/main/java/org/springblade/core/transaction/annotation/SeataCloudApplication.java
  78. 2 2
      blade-core-transaction/src/main/java/org/springblade/core/transaction/config/DataSourceConfiguration.java
  79. 13 8
      pom.xml

+ 3 - 3
README.md

@@ -1,7 +1,7 @@
  <p align="center">
   <img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
-   <img src="https://img.shields.io/badge/Spring%20Cloud-Hoxton.SR8-blue.svg" alt="Coverage Status">
-   <img src="https://img.shields.io/badge/Spring%20Boot-2.2.11.RELEASE-blue.svg" alt="Downloads">
+   <img src="https://img.shields.io/badge/Spring%20Cloud-2020-blue.svg" alt="Coverage Status">
+   <img src="https://img.shields.io/badge/Spring%20Boot-2.4.1-blue.svg" alt="Downloads">
  </p>  
 
 ## SpringBlade微服务开发平台
@@ -14,7 +14,7 @@
 * 极简封装了多租户底层,用更少的代码换来拓展性更强的SaaS多租户系统。
 * 借鉴OAuth2,实现了多终端认证系统,可控制子系统的token权限互相隔离。
 * 借鉴Security,封装了Secure模块,采用JWT做Token认证,可拓展集成Redis等细颗粒度控制方案。
-* 稳定生产了一年,经历了从Camden -> Greenwich的技术架构,也经历了从fat jar -> docker -> k8s + jenkins的部署架构
+* 稳定生产了一年,经历了从 Camden -> Hoxton -> 2020 的技术架构,也经历了从fat jar -> docker -> k8s + jenkins的部署架构
 * 项目分包明确,规范微服务的开发模式,使包与包之间的分工清晰。
 
 ## 架构图

+ 1 - 1
blade-core-boot/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.springblade</groupId>
         <artifactId>blade-tool</artifactId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeBootAutoConfiguration.java

@@ -30,7 +30,7 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
  * @author Chill
  */
 @Slf4j
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @EnableConfigurationProperties({
 	BladeProperties.class
 })

+ 1 - 1
blade-core-boot/src/main/java/org/springblade/core/boot/config/BladeWebMvcConfiguration.java

@@ -31,7 +31,7 @@ import java.util.List;
  * @author Chill
  */
 @Slf4j
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @EnableCaching
 @Order(Ordered.HIGHEST_PRECEDENCE)
 public class BladeWebMvcConfiguration implements WebMvcConfigurer {

+ 1 - 1
blade-core-boot/src/main/java/org/springblade/core/boot/config/MybatisPlusConfiguration.java

@@ -33,7 +33,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @MapperScan("org.springblade.**.mapper.**")
 public class MybatisPlusConfiguration {

+ 1 - 1
blade-core-boot/src/main/java/org/springblade/core/boot/config/RetryConfiguration.java

@@ -28,7 +28,7 @@ import org.springframework.retry.interceptor.RetryOperationsInterceptor;
  * @author Chill
  */
 @Slf4j
-@Configuration
+@Configuration(proxyBeanMethods = false)
 public class RetryConfiguration {
 
 	@Bean

+ 1 - 1
blade-core-boot/src/main/java/org/springblade/core/boot/logger/RequestLogAspect.java

@@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
  */
 @Slf4j
 @Aspect
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @Profile({AppConstant.DEV_CODE, AppConstant.TEST_CODE})
 public class RequestLogAspect {
 

+ 1 - 1
blade-core-boot/src/main/java/org/springblade/core/boot/tenant/TenantConfiguration.java

@@ -29,7 +29,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @AutoConfigureBefore(MybatisPlusConfiguration.class)
 @EnableConfigurationProperties(BladeTenantProperties.class)

+ 1 - 1
blade-core-boot/src/main/resources/bootstrap.yml

@@ -97,7 +97,7 @@ mybatis-plus:
 swagger:
   title: SpringBlade 接口文档系统
   description: SpringBlade 接口文档系统
-  version: 2.8.0
+  version: 3.0.0
   license: Powered By SpringBlade
   licenseUrl: https://bladex.vip
   terms-of-service-url: https://bladex.vip

+ 6 - 26
blade-core-cloud/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -22,42 +22,22 @@
             <artifactId>blade-core-secure</artifactId>
             <version>${blade.tool.version}</version>
         </dependency>
-        <!--Spring-->
+        <!--Feign-->
         <dependency>
-            <groupId>org.springframework.retry</groupId>
-            <artifactId>spring-retry</artifactId>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
         </dependency>
-        <!--Feign-->
         <dependency>
             <groupId>io.github.openfeign</groupId>
             <artifactId>feign-okhttp</artifactId>
-            <version>10.4.0</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-openfeign</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>commons-logging</groupId>
-                    <artifactId>commons-logging</artifactId>
-                </exclusion>
-            </exclusions>
+            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
         </dependency>
-        <!--Hystrix-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>commons-logging</groupId>
-                    <artifactId>commons-logging</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <!-- Actuator -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-actuator</artifactId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
         </dependency>
         <!-- Admin -->
         <dependency>

+ 42 - 0
blade-core-cloud/src/main/java/org/springblade/core/cloud/client/BladeCloudApplication.java

@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * 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.springblade.core.cloud.client;
+
+import org.springblade.core.launch.constant.AppConstant;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+import java.lang.annotation.*;
+
+/**
+ * Cloud启动注解配置
+ *
+ * @author Chill
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@EnableDiscoveryClient
+@EnableCircuitBreaker
+@EnableFeignClients(AppConstant.BASE_PACKAGES)
+@SpringBootApplication(exclude = RibbonAutoConfiguration.class)
+public @interface BladeCloudApplication {
+
+}

+ 54 - 0
blade-core-cloud/src/main/java/org/springblade/core/cloud/config/BladeCloudAutoConfiguration.java

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * 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.springblade.core.cloud.config;
+
+import com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration;
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+import feign.Feign;
+import org.springblade.core.cloud.feign.BladeFeignSentinel;
+import org.springblade.core.cloud.sentinel.BladeBlockExceptionHandler;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+
+
+/**
+ * blade cloud 增强配置
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureBefore(SentinelFeignAutoConfiguration.class)
+public class BladeCloudAutoConfiguration {
+
+	@Bean
+	@Scope("prototype")
+	@ConditionalOnMissingBean
+	@ConditionalOnProperty(name = "feign.sentinel.enabled")
+	public Feign.Builder feignSentinelBuilder() {
+		return BladeFeignSentinel.builder();
+	}
+
+	@Bean
+	@ConditionalOnMissingBean
+	public BlockExceptionHandler blockExceptionHandler() {
+		return new BladeBlockExceptionHandler();
+	}
+
+}

+ 1 - 1
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFallbackFactory.java

@@ -16,9 +16,9 @@
 package org.springblade.core.cloud.feign;
 
 import feign.Target;
-import feign.hystrix.FallbackFactory;
 import lombok.AllArgsConstructor;
 import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cloud.openfeign.FallbackFactory;
 
 /**
  * 默认 Fallback,避免写过多fallback类

+ 0 - 96
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignAutoConfiguration.java

@@ -1,96 +0,0 @@
-/*
- * Copyright 2013-2015 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.springblade.core.cloud.feign;
-
-import com.netflix.hystrix.HystrixCommand;
-import feign.Contract;
-import feign.Feign;
-import feign.RequestInterceptor;
-import feign.hystrix.HystrixFeign;
-import org.springblade.core.tool.convert.EnumToStringConverter;
-import org.springblade.core.tool.convert.StringToEnumConverter;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.cloud.openfeign.BladeFeignClientsRegistrar;
-import org.springframework.cloud.openfeign.BladeHystrixTargeter;
-import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.cloud.openfeign.Targeter;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
-import org.springframework.context.annotation.Scope;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.converter.ConverterRegistry;
-
-import java.util.ArrayList;
-
-
-/**
- * blade feign 增强配置
- *
- * @author L.cm
- */
-@Configuration
-@ConditionalOnClass(Feign.class)
-@Import(BladeFeignClientsRegistrar.class)
-@AutoConfigureAfter(EnableFeignClients.class)
-public class BladeFeignAutoConfiguration {
-
-	@Bean
-	@ConditionalOnMissingBean(Targeter.class)
-	public Targeter bladeFeignTargeter() {
-		return new BladeHystrixTargeter();
-	}
-
-	@Configuration("hystrixFeignConfiguration")
-	@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
-	protected static class HystrixFeignConfiguration {
-		@Bean
-		@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-		@ConditionalOnProperty("feign.hystrix.enabled")
-		public Feign.Builder feignHystrixBuilder(
-			RequestInterceptor requestInterceptor, Contract feignContract) {
-			return HystrixFeign.builder()
-				.contract(feignContract)
-				.decode404()
-				.requestInterceptor(requestInterceptor);
-		}
-
-		@Bean
-		@ConditionalOnMissingBean
-		public RequestInterceptor requestInterceptor() {
-			return new BladeFeignRequestHeaderInterceptor();
-		}
-	}
-
-	/**
-	 * blade enum 《-》 String 转换配置
-	 * @param conversionService ConversionService
-	 * @return SpringMvcContract
-	 */
-	@Bean
-	public Contract feignContract(@Qualifier("mvcConversionService") ConversionService conversionService) {
-		ConverterRegistry converterRegistry =  ((ConverterRegistry) conversionService);
-		converterRegistry.addConverter(new EnumToStringConverter());
-		converterRegistry.addConverter(new StringToEnumConverter());
-		return new BladeSpringMvcContract(new ArrayList<>(), conversionService);
-	}
-}

+ 2 - 2
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignFallback.java

@@ -41,7 +41,7 @@ public class BladeFeignFallback<T> implements MethodInterceptor {
 	private final Class<T> targetType;
 	private final String targetName;
 	private final Throwable cause;
-	private final String code = "code";
+	private final static String CODE = "code";
 
 	@Nullable
 	@Override
@@ -66,7 +66,7 @@ public class BladeFeignFallback<T> implements MethodInterceptor {
 		// 转换成 jsonNode 读取,因为直接转换,可能 对方放回的并 不是 R 的格式。
 		JsonNode resultNode = JsonUtil.readTree(content);
 		// 判断是否 R 格式 返回体
-		if (resultNode.has(code)) {
+		if (resultNode.has(CODE)) {
 			return JsonUtil.getInstance().convertValue(resultNode, R.class);
 		}
 		return R.fail(resultNode.toString());

+ 136 - 0
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignSentinel.java

@@ -0,0 +1,136 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.cloud.feign;
+
+import com.alibaba.cloud.sentinel.feign.SentinelContractHolder;
+import feign.Contract;
+import feign.Feign;
+import feign.InvocationHandlerFactory;
+import feign.Target;
+import lombok.SneakyThrows;
+import org.springblade.core.cloud.sentinel.BladeSentinelInvocationHandler;
+import org.springframework.beans.BeansException;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.cloud.openfeign.FeignContext;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * feign集成sentinel自动配置
+ * 重写 {@link com.alibaba.cloud.sentinel.feign.SentinelFeign} 适配最新API
+ *
+ * @author Chill
+ */
+public class BladeFeignSentinel {
+
+	public static Builder builder() {
+		return new Builder();
+	}
+
+	public static final class Builder extends Feign.Builder
+		implements ApplicationContextAware {
+		private Contract contract = new Contract.Default();
+		private ApplicationContext applicationContext;
+		private FeignContext feignContext;
+
+		@Override
+		public Feign.Builder invocationHandlerFactory(
+			InvocationHandlerFactory invocationHandlerFactory) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public Builder contract(Contract contract) {
+			this.contract = contract;
+			return this;
+		}
+
+		@Override
+		public Feign build() {
+			super.invocationHandlerFactory(new InvocationHandlerFactory() {
+				@SneakyThrows
+				@Override
+				public InvocationHandler create(Target target,
+												Map<Method, MethodHandler> dispatch) {
+					Object feignClientFactoryBean = Builder.this.applicationContext.getBean("&" + target.type().getName());
+
+					Class fallback = (Class) getFieldValue(feignClientFactoryBean, "fallback");
+					Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean, "fallbackFactory");
+					String name = (String) getFieldValue(feignClientFactoryBean, "name");
+
+					Object fallbackInstance;
+					FallbackFactory fallbackFactoryInstance;
+					// 判断fallback类型
+					if (void.class != fallback) {
+						fallbackInstance = getFromContext(name, "fallback", fallback, target.type());
+						return new BladeSentinelInvocationHandler(target, dispatch, new FallbackFactory.Default(fallbackInstance));
+					}
+					if (void.class != fallbackFactory) {
+						fallbackFactoryInstance = (FallbackFactory) getFromContext(name, "fallbackFactory", fallbackFactory, FallbackFactory.class);
+						return new BladeSentinelInvocationHandler(target, dispatch, fallbackFactoryInstance);
+					}
+					// 默认fallbackFactory
+					BladeFallbackFactory bladeFallbackFactory = new BladeFallbackFactory(target);
+					return new BladeSentinelInvocationHandler(target, dispatch, bladeFallbackFactory);
+				}
+
+				private Object getFromContext(String name, String type, Class fallbackType, Class targetType) {
+					Object fallbackInstance = feignContext.getInstance(name, fallbackType);
+					if (fallbackInstance == null) {
+						throw new IllegalStateException(
+							String.format("No %s instance of type %s found for feign client %s",
+								type, fallbackType, name)
+						);
+					}
+
+					if (!targetType.isAssignableFrom(fallbackType)) {
+						throw new IllegalStateException(
+							String.format("Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
+								type, fallbackType, targetType, name)
+						);
+					}
+					return fallbackInstance;
+				}
+			});
+			super.contract(new SentinelContractHolder(contract));
+			return super.build();
+		}
+
+		private Object getFieldValue(Object instance, String fieldName) {
+			Field field = ReflectionUtils.findField(instance.getClass(), fieldName);
+			field.setAccessible(true);
+			try {
+				return field.get(instance);
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+			return null;
+		}
+
+		@Override
+		public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+			this.applicationContext = applicationContext;
+			feignContext = this.applicationContext.getBean(FeignContext.class);
+		}
+	}
+
+}

+ 3 - 0
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/EnableBladeFeign.java

@@ -18,6 +18,8 @@ package org.springblade.core.cloud.feign;
 
 
 import org.springblade.core.launch.constant.AppConstant;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 
 import java.lang.annotation.*;
@@ -31,6 +33,7 @@ import java.lang.annotation.*;
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @EnableFeignClients(AppConstant.BASE_PACKAGES)
+@EnableAutoConfiguration(exclude = RibbonAutoConfiguration.class)
 public @interface EnableBladeFeign {
 	/**
 	 * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation

+ 2 - 2
blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeAccountGetter.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeAccountGetter.java

@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springblade.core.cloud.hystrix;
+package org.springblade.core.cloud.header;
 
 import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.SecureUtil;
@@ -27,7 +27,7 @@ import javax.servlet.http.HttpServletRequest;
  *
  * @author Chill
  */
-public class BladeAccountGetter implements BladeHystrixAccountGetter {
+public class BladeAccountGetter implements BladeFeignAccountGetter {
 
 	@Override
 	public String get(HttpServletRequest request) {

+ 2 - 2
blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHystrixAccountGetter.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeFeignAccountGetter.java

@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springblade.core.cloud.hystrix;
+package org.springblade.core.cloud.header;
 
 
 import org.springframework.lang.Nullable;
@@ -25,7 +25,7 @@ import javax.servlet.http.HttpServletRequest;
  *
  * @author L.cm
  */
-public interface BladeHystrixAccountGetter {
+public interface BladeFeignAccountGetter {
 
 	/**
 	 * 账号信息获取器

+ 1 - 2
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeFeignRequestHeaderInterceptor.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeFeignRequestHeaderInterceptor.java

@@ -13,11 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springblade.core.cloud.feign;
+package org.springblade.core.cloud.header;
 
 import feign.RequestInterceptor;
 import feign.RequestTemplate;
-import org.springblade.core.cloud.hystrix.BladeHttpHeadersContextHolder;
 import org.springframework.http.HttpHeaders;
 
 /**

+ 4 - 4
blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHttpHeadersCallable.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeHttpHeadersCallable.java

@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springblade.core.cloud.hystrix;
+package org.springblade.core.cloud.header;
 
-import org.springblade.core.cloud.props.BladeHystrixHeadersProperties;
+import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
 import org.springframework.http.HttpHeaders;
 import org.springframework.lang.Nullable;
 
@@ -33,8 +33,8 @@ public class BladeHttpHeadersCallable<V> implements Callable<V> {
 	private HttpHeaders httpHeaders;
 
 	public BladeHttpHeadersCallable(Callable<V> delegate,
-									@Nullable BladeHystrixAccountGetter accountGetter,
-									BladeHystrixHeadersProperties properties) {
+									@Nullable BladeFeignAccountGetter accountGetter,
+									BladeFeignHeadersProperties properties) {
 		this.delegate = delegate;
 		this.httpHeaders = BladeHttpHeadersContextHolder.toHeaders(accountGetter, properties);
 	}

+ 5 - 5
blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHttpHeadersContextHolder.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/header/BladeHttpHeadersContextHolder.java

@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springblade.core.cloud.hystrix;
+package org.springblade.core.cloud.header;
 
-import org.springblade.core.cloud.props.BladeHystrixHeadersProperties;
+import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
 import org.springblade.core.tool.utils.StringUtil;
 import org.springblade.core.tool.utils.WebUtil;
 import org.springframework.core.NamedThreadLocal;
@@ -35,7 +35,7 @@ import java.util.List;
  * @author L.cm
  */
 public class BladeHttpHeadersContextHolder {
-	private static final ThreadLocal<HttpHeaders> HTTP_HEADERS_HOLDER = new NamedThreadLocal<>("Blade hystrix HttpHeaders");
+	private static final ThreadLocal<HttpHeaders> HTTP_HEADERS_HOLDER = new NamedThreadLocal<>("Blade Feign HttpHeaders");
 
 	/**
 	 * 请求和转发的ip
@@ -59,8 +59,8 @@ public class BladeHttpHeadersContextHolder {
 
 	@Nullable
 	public static HttpHeaders toHeaders(
-		@Nullable BladeHystrixAccountGetter accountGetter,
-		BladeHystrixHeadersProperties properties) {
+		@Nullable BladeFeignAccountGetter accountGetter,
+		BladeFeignHeadersProperties properties) {
 		HttpServletRequest request = WebUtil.getRequest();
 		if (request == null) {
 			return null;

+ 8 - 6
blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java

@@ -18,12 +18,13 @@ package org.springblade.core.cloud.http;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.AllArgsConstructor;
-import org.springblade.core.cloud.hystrix.BladeHystrixAccountGetter;
-import org.springblade.core.cloud.props.BladeHystrixHeadersProperties;
+import org.springblade.core.cloud.header.BladeFeignAccountGetter;
+import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
 import org.springblade.core.tool.utils.Charsets;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
 import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
@@ -47,9 +48,10 @@ import java.util.concurrent.TimeUnit;
  *
  * @author L.cm
  */
-@Configuration
-@ConditionalOnClass(okhttp3.OkHttpClient.class)
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
+@ConditionalOnClass(okhttp3.OkHttpClient.class)
+@EnableConfigurationProperties(BladeFeignHeadersProperties.class)
 public class RestTemplateConfiguration {
 	private final ObjectMapper objectMapper;
 
@@ -135,8 +137,8 @@ public class RestTemplateConfiguration {
 
 	@Bean
 	public RestTemplateHeaderInterceptor requestHeaderInterceptor(
-		@Autowired(required = false) @Nullable BladeHystrixAccountGetter accountGetter,
-		BladeHystrixHeadersProperties properties) {
+		@Autowired(required = false) @Nullable BladeFeignAccountGetter accountGetter,
+		BladeFeignHeadersProperties properties) {
 		return new RestTemplateHeaderInterceptor(accountGetter,properties);
 	}
 

+ 5 - 5
blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateHeaderInterceptor.java

@@ -16,9 +16,9 @@
 package org.springblade.core.cloud.http;
 
 import lombok.AllArgsConstructor;
-import org.springblade.core.cloud.hystrix.BladeHttpHeadersContextHolder;
-import org.springblade.core.cloud.hystrix.BladeHystrixAccountGetter;
-import org.springblade.core.cloud.props.BladeHystrixHeadersProperties;
+import org.springblade.core.cloud.header.BladeHttpHeadersContextHolder;
+import org.springblade.core.cloud.header.BladeFeignAccountGetter;
+import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpRequest;
 import org.springframework.http.client.ClientHttpRequestExecution;
@@ -36,8 +36,8 @@ import java.io.IOException;
 @AllArgsConstructor
 public class RestTemplateHeaderInterceptor implements ClientHttpRequestInterceptor {
 	@Nullable
-	private final BladeHystrixAccountGetter accountGetter;
-	private final BladeHystrixHeadersProperties properties;
+	private final BladeFeignAccountGetter accountGetter;
+	private final BladeFeignHeadersProperties properties;
 
 	@Override
 	public ClientHttpResponse intercept(

+ 0 - 71
blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHystrixAutoConfiguration.java

@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
- * <p>
- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.gnu.org/licenses/lgpl.html
- * <p>
- * 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.springblade.core.cloud.hystrix;
-
-import com.netflix.hystrix.Hystrix;
-import com.netflix.hystrix.strategy.HystrixPlugins;
-import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
-import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
-import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
-import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
-import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
-import org.springblade.core.cloud.props.BladeHystrixHeadersProperties;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.lang.Nullable;
-
-import javax.annotation.PostConstruct;
-
-/**
- * Hystrix 配置
- *
- * @author L.cm
- */
-@Configuration
-@ConditionalOnClass(Hystrix.class)
-@EnableConfigurationProperties(BladeHystrixHeadersProperties.class)
-public class BladeHystrixAutoConfiguration {
-	@Nullable
-	@Autowired(required = false)
-	private HystrixConcurrencyStrategy existingConcurrencyStrategy;
-	@Nullable
-	@Autowired(required = false)
-	private BladeHystrixAccountGetter accountGetter;
-	@Autowired
-	private BladeHystrixHeadersProperties properties;
-
-	@PostConstruct
-	public void init() {
-		// Keeps references of existing Hystrix plugins.
-		HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
-		HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
-		HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
-		HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();
-
-		HystrixPlugins.reset();
-
-		// Registers existing plugins excepts the Concurrent Strategy plugin.
-		HystrixConcurrencyStrategy strategy = new BladeHystrixConcurrencyStrategy(existingConcurrencyStrategy, accountGetter, properties);
-		HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);
-		HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
-		HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
-		HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
-		HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
-	}
-
-}

+ 0 - 93
blade-core-cloud/src/main/java/org/springblade/core/cloud/hystrix/BladeHystrixConcurrencyStrategy.java

@@ -1,93 +0,0 @@
-/**
- * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
- * <p>
- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.gnu.org/licenses/lgpl.html
- * <p>
- * 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.springblade.core.cloud.hystrix;
-
-import com.netflix.hystrix.HystrixThreadPoolKey;
-import com.netflix.hystrix.HystrixThreadPoolProperties;
-import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
-import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
-import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
-import com.netflix.hystrix.strategy.properties.HystrixProperty;
-import lombok.AllArgsConstructor;
-import org.springblade.core.cloud.props.BladeHystrixHeadersProperties;
-import org.springframework.lang.Nullable;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Hystrix传递ThreaLocal中的一些变量
- *
- * <p>
- * https://github.com/Netflix/Hystrix/issues/92#issuecomment-260548068
- * https://github.com/spring-cloud/spring-cloud-sleuth/issues/39
- * https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security
- * https://github.com/spring-projects/spring-security/blob/master/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextCallable.java
- * </p>
- *
- * @author L.cm
- */
-@AllArgsConstructor
-public class BladeHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
-	@Nullable
-	private final HystrixConcurrencyStrategy existingConcurrencyStrategy;
-	@Nullable
-	private final BladeHystrixAccountGetter accountGetter;
-	private final BladeHystrixHeadersProperties properties;
-
-	@Override
-	public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
-		return existingConcurrencyStrategy != null
-			? existingConcurrencyStrategy.getBlockingQueue(maxQueueSize)
-			: super.getBlockingQueue(maxQueueSize);
-	}
-
-	@Override
-	public <T> HystrixRequestVariable<T> getRequestVariable(
-		HystrixRequestVariableLifecycle<T> rv) {
-		return existingConcurrencyStrategy != null
-			? existingConcurrencyStrategy.getRequestVariable(rv)
-			: super.getRequestVariable(rv);
-	}
-
-	@Override
-	public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
-											HystrixProperty<Integer> corePoolSize,
-											HystrixProperty<Integer> maximumPoolSize,
-											HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
-											BlockingQueue<Runnable> workQueue) {
-		return existingConcurrencyStrategy != null
-			? existingConcurrencyStrategy.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue)
-			: super.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
-	}
-
-	@Override
-	public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
-		return existingConcurrencyStrategy != null
-			? existingConcurrencyStrategy.getThreadPool(threadPoolKey, threadPoolProperties)
-			: super.getThreadPool(threadPoolKey, threadPoolProperties);
-	}
-
-	@Override
-	public <T> Callable<T> wrapCallable(Callable<T> callable) {
-		Callable<T> wrapCallable = new BladeHttpHeadersCallable<>(callable, accountGetter, properties);
-		return existingConcurrencyStrategy != null
-			? existingConcurrencyStrategy.wrapCallable(wrapCallable)
-			: super.wrapCallable(wrapCallable);
-	}
-}

+ 2 - 2
blade-core-cloud/src/main/java/org/springblade/core/cloud/props/BladeHystrixHeadersProperties.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/props/BladeFeignHeadersProperties.java

@@ -32,8 +32,8 @@ import java.util.List;
 @Getter
 @Setter
 @RefreshScope
-@ConfigurationProperties("blade.hystrix.headers")
-public class BladeHystrixHeadersProperties {
+@ConfigurationProperties("blade.feign.headers")
+public class BladeFeignHeadersProperties {
 
 	/**
 	 * 用于 聚合层 向调用层传递用户信息 的请求头,默认:x-blade-account

+ 26 - 0
blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java

@@ -0,0 +1,26 @@
+package org.springblade.core.cloud.sentinel;
+
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Sentinel统一限流策略
+ *
+ * @author Chill
+ */
+public class BladeBlockExceptionHandler implements BlockExceptionHandler {
+	@Override
+	public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
+		// Return 429 (Too Many Requests) by default.
+		response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
+		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+		response.getWriter().print(JsonUtil.toJson(R.fail(e.getMessage())));
+	}
+}

+ 168 - 0
blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeSentinelInvocationHandler.java

@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * 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.springblade.core.cloud.sentinel;
+
+import com.alibaba.cloud.sentinel.feign.SentinelContractHolder;
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.SphU;
+import com.alibaba.csp.sentinel.Tracer;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import feign.Feign;
+import feign.InvocationHandlerFactory;
+import feign.MethodMetadata;
+import feign.Target;
+import org.springframework.cloud.openfeign.FallbackFactory;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static feign.Util.checkNotNull;
+
+/**
+ * 重写SentinelInvocationHandler适配最新API
+ *
+ * @author Chill
+ */
+public class BladeSentinelInvocationHandler implements InvocationHandler {
+
+	private final Target<?> target;
+
+	private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
+
+	private FallbackFactory fallbackFactory;
+
+	private Map<Method, Method> fallbackMethodMap;
+
+	public BladeSentinelInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch,
+								   FallbackFactory fallbackFactory) {
+		this.target = checkNotNull(target, "target");
+		this.dispatch = checkNotNull(dispatch, "dispatch");
+		this.fallbackFactory = fallbackFactory;
+		this.fallbackMethodMap = toFallbackMethod(dispatch);
+	}
+
+	public BladeSentinelInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
+		this.target = checkNotNull(target, "target");
+		this.dispatch = checkNotNull(dispatch, "dispatch");
+	}
+
+	@Override
+	public Object invoke(final Object proxy, final Method method, final Object[] args)
+		throws Throwable {
+		if ("equals".equals(method.getName())) {
+			try {
+				Object otherHandler = args.length > 0 && args[0] != null
+					? Proxy.getInvocationHandler(args[0]) : null;
+				return equals(otherHandler);
+			} catch (IllegalArgumentException e) {
+				return false;
+			}
+		} else if ("hashCode".equals(method.getName())) {
+			return hashCode();
+		} else if ("toString".equals(method.getName())) {
+			return toString();
+		}
+
+		Object result;
+		InvocationHandlerFactory.MethodHandler methodHandler = this.dispatch.get(method);
+		// only handle by HardCodedTarget
+		if (target instanceof Target.HardCodedTarget) {
+			Target.HardCodedTarget hardCodedTarget = (Target.HardCodedTarget) target;
+			MethodMetadata methodMetadata = SentinelContractHolder.METADATA_MAP
+				.get(hardCodedTarget.type().getName()
+					+ Feign.configKey(hardCodedTarget.type(), method));
+			// resource default is HttpMethod:protocol://url
+			if (methodMetadata == null) {
+				result = methodHandler.invoke(args);
+			} else {
+				String resourceName = methodMetadata.template().method().toUpperCase()
+					+ ":" + hardCodedTarget.url() + methodMetadata.template().path();
+				Entry entry = null;
+				try {
+					ContextUtil.enter(resourceName);
+					entry = SphU.entry(resourceName, EntryType.OUT, 1, args);
+					result = methodHandler.invoke(args);
+				} catch (Throwable ex) {
+					// fallback handle
+					if (!BlockException.isBlockException(ex)) {
+						Tracer.trace(ex);
+					}
+					if (fallbackFactory != null) {
+						try {
+							Object fallbackResult = fallbackMethodMap.get(method)
+								.invoke(fallbackFactory.create(ex), args);
+							return fallbackResult;
+						} catch (IllegalAccessException e) {
+							// shouldn't happen as method is public due to being an
+							// interface
+							throw new AssertionError(e);
+						} catch (InvocationTargetException e) {
+							throw new AssertionError(e.getCause());
+						}
+					} else {
+						// throw exception if fallbackFactory is null
+						throw ex;
+					}
+				} finally {
+					if (entry != null) {
+						entry.exit(1, args);
+					}
+					ContextUtil.exit();
+				}
+			}
+		} else {
+			// other target type using default strategy
+			result = methodHandler.invoke(args);
+		}
+
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof BladeSentinelInvocationHandler) {
+			BladeSentinelInvocationHandler other = (BladeSentinelInvocationHandler) obj;
+			return target.equals(other.target);
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return target.hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return target.toString();
+	}
+
+	static Map<Method, Method> toFallbackMethod(Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
+		Map<Method, Method> result = new LinkedHashMap<>();
+		for (Method method : dispatch.keySet()) {
+			method.setAccessible(true);
+			result.put(method, method);
+		}
+		return result;
+	}
+
+}

+ 1 - 2
blade-core-cloud/src/main/java/org/springblade/core/cloud/feign/BladeSpringMvcContract.java → blade-core-cloud/src/main/java/org/springblade/core/cloud/version/BladeSpringMvcContract.java

@@ -13,12 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springblade.core.cloud.feign;
+package org.springblade.core.cloud.version;
 
 import feign.MethodMetadata;
 import org.springblade.core.cloud.annotation.ApiVersion;
 import org.springblade.core.cloud.annotation.UrlVersion;
-import org.springblade.core.cloud.version.BladeMediaType;
 import org.springblade.core.tool.utils.StringPool;
 import org.springblade.core.tool.utils.StringUtil;
 import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;

+ 1 - 1
blade-core-cloud/src/main/java/org/springblade/core/cloud/version/VersionMappingAutoConfiguration.java

@@ -27,7 +27,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author L.cm
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @ConditionalOnWebApplication
 public class VersionMappingAutoConfiguration {
 	@Bean

+ 0 - 230
blade-core-cloud/src/main/java/org/springframework/cloud/openfeign/BladeFeignClientsRegistrar.java

@@ -1,230 +0,0 @@
-/**
- * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
- * <p>
- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.gnu.org/licenses/lgpl.html
- * <p>
- * 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.openfeign;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import org.springblade.core.cloud.feign.BladeFeignAutoConfiguration;
-import org.springframework.beans.factory.BeanClassLoaderAware;
-import org.springframework.beans.factory.config.BeanDefinitionHolder;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
-import org.springframework.core.annotation.AnnotatedElementUtils;
-import org.springframework.core.annotation.AnnotationAttributes;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.support.SpringFactoriesLoader;
-import org.springframework.core.type.AnnotationMetadata;
-import org.springframework.lang.Nullable;
-import org.springframework.util.StringUtils;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * feign 自动配置
- *
- * @author L.cm
- */
-@NoArgsConstructor
-public class BladeFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
-	@Getter
-	private ClassLoader beanClassLoader;
-	@Getter
-	private Environment environment;
-
-	@Override
-	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
-		registerFeignClients(metadata, registry);
-	}
-
-	@Override
-	public void setBeanClassLoader(ClassLoader classLoader) {
-		this.beanClassLoader = classLoader;
-	}
-
-	private void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
-		List<String> feignClients = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
-		// 如果 spring.factories 里为空
-		if (feignClients.isEmpty()) {
-			return;
-		}
-		for (String className : feignClients) {
-			try {
-				Class<?> clazz = beanClassLoader.loadClass(className);
-				AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz, FeignClient.class);
-				if (attributes == null) {
-					continue;
-				}
-				// 如果已经存在该 bean,支持原生的 Feign
-				if (registry.containsBeanDefinition(className)) {
-					continue;
-				}
-				registerClientConfiguration(registry, getClientName(attributes), attributes.get("configuration"));
-
-				validate(attributes);
-				BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
-				definition.addPropertyValue("url", getUrl(attributes));
-				definition.addPropertyValue("path", getPath(attributes));
-				String name = getName(attributes);
-				definition.addPropertyValue("name", name);
-
-				// 兼容最新版本的 spring-cloud-openfeign,尚未发布
-				StringBuilder aliasBuilder = new StringBuilder(18);
-				if (attributes.containsKey("contextId")) {
-					String contextId = getContextId(attributes);
-					aliasBuilder.append(contextId);
-					definition.addPropertyValue("contextId", contextId);
-				} else {
-					aliasBuilder.append(name);
-				}
-
-				definition.addPropertyValue("type", className);
-				definition.addPropertyValue("decode404", attributes.get("decode404"));
-				definition.addPropertyValue("fallback", attributes.get("fallback"));
-				definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
-				definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
-
-				AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
-
-				// alias
-				String alias = aliasBuilder.append("FeignClient").toString();
-
-				// has a default, won't be null
-				boolean primary = (Boolean)attributes.get("primary");
-
-				beanDefinition.setPrimary(primary);
-
-				String qualifier = getQualifier(attributes);
-				if (StringUtils.hasText(qualifier)) {
-					alias = qualifier;
-				}
-
-				BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias });
-				BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
-
-			} catch (ClassNotFoundException e) {
-				e.printStackTrace();
-			}
-		}
-	}
-
-	/**
-	 * Return the class used by {@link SpringFactoriesLoader} to load configuration
-	 * candidates.
-	 * @return the factory class
-	 */
-	private Class<?> getSpringFactoriesLoaderFactoryClass() {
-		return BladeFeignAutoConfiguration.class;
-	}
-
-	private void validate(Map<String, Object> attributes) {
-		AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
-		// This blows up if an aliased property is overspecified
-		// FIXME annotation.getAliasedString("name", FeignClient.class, null);
-		FeignClientsRegistrar.validateFallback(annotation.getClass("fallback"));
-		FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory"));
-	}
-
-	private String getName(Map<String, Object> attributes) {
-		String name = (String) attributes.get("serviceId");
-		if (!StringUtils.hasText(name)) {
-			name = (String) attributes.get("name");
-		}
-		if (!StringUtils.hasText(name)) {
-			name = (String) attributes.get("value");
-		}
-		name = resolve(name);
-		return FeignClientsRegistrar.getName(name);
-	}
-
-	private String getContextId(Map<String, Object> attributes) {
-		String contextId = (String) attributes.get("contextId");
-		if (!StringUtils.hasText(contextId)) {
-			return getName(attributes);
-		}
-
-		contextId = resolve(contextId);
-		return FeignClientsRegistrar.getName(contextId);
-	}
-
-	private String resolve(String value) {
-		if (StringUtils.hasText(value)) {
-			return this.environment.resolvePlaceholders(value);
-		}
-		return value;
-	}
-
-	private String getUrl(Map<String, Object> attributes) {
-		String url = resolve((String) attributes.get("url"));
-		return FeignClientsRegistrar.getUrl(url);
-	}
-
-	private String getPath(Map<String, Object> attributes) {
-		String path = resolve((String) attributes.get("path"));
-		return FeignClientsRegistrar.getPath(path);
-	}
-
-	@Nullable
-	private String getQualifier(@Nullable Map<String, Object> client) {
-		if (client == null) {
-			return null;
-		}
-		String qualifier = (String) client.get("qualifier");
-		if (StringUtils.hasText(qualifier)) {
-			return qualifier;
-		}
-		return null;
-	}
-
-	@Nullable
-	private String getClientName(@Nullable Map<String, Object> client) {
-		if (client == null) {
-			return null;
-		}
-		String value = (String) client.get("contextId");
-		if (!StringUtils.hasText(value)) {
-			value = (String) client.get("value");
-		}
-		if (!StringUtils.hasText(value)) {
-			value = (String) client.get("name");
-		}
-		if (!StringUtils.hasText(value)) {
-			value = (String) client.get("serviceId");
-		}
-		if (StringUtils.hasText(value)) {
-			return value;
-		}
-
-		throw new IllegalStateException("Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
-	}
-
-	private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
-		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
-		builder.addConstructorArgValue(name);
-		builder.addConstructorArgValue(configuration);
-		registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
-	}
-
-	@Override
-	public void setEnvironment(Environment environment) {
-		this.environment = environment;
-	}
-
-}

+ 0 - 99
blade-core-cloud/src/main/java/org/springframework/cloud/openfeign/BladeHystrixTargeter.java

@@ -1,99 +0,0 @@
-/*
- * Copyright 2013-2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.springframework.cloud.openfeign;
-
-import feign.Feign;
-import feign.Target;
-import feign.hystrix.FallbackFactory;
-import feign.hystrix.HystrixFeign;
-import feign.hystrix.SetterFactory;
-import org.springblade.core.cloud.feign.BladeFallbackFactory;
-import org.springframework.lang.Nullable;
-
-/**
- * 添加 blade 默认的 fallbackFactory L.cm 2019.01.19
- *
- * @author L.cm
- * @author Spencer Gibb
- * @author Erik Kringen
- */
-@SuppressWarnings("unchecked")
-public class BladeHystrixTargeter implements Targeter {
-
-	@Override
-	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
-						Target.HardCodedTarget<T> target) {
-		if (!(feign instanceof HystrixFeign.Builder)) {
-			return feign.target(target);
-		}
-		HystrixFeign.Builder builder = (HystrixFeign.Builder) feign;
-		SetterFactory setterFactory = getOptional(factory.getName(), context, SetterFactory.class);
-		if (setterFactory != null) {
-			builder.setterFactory(setterFactory);
-		}
-		Class<?> fallback = factory.getFallback();
-		if (fallback != void.class) {
-			return targetWithFallback(factory.getName(), context, target, builder, fallback);
-		}
-		Class<?> fallbackFactory = factory.getFallbackFactory();
-		if (fallbackFactory != void.class) {
-			return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);
-		}
-		// blade 默认的 fallbackFactory
-		BladeFallbackFactory bladeFallbackFactory = new BladeFallbackFactory(target);
-		return (T) builder.target(target, bladeFallbackFactory);
-	}
-
-	private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
-											Target.HardCodedTarget<T> target,
-											HystrixFeign.Builder builder,
-											Class<?> fallbackFactoryClass) {
-		FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>)
-			getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
-		return builder.target(target, fallbackFactory);
-	}
-
-
-	private <T> T targetWithFallback(String feignClientName, FeignContext context,
-									 Target.HardCodedTarget<T> target,
-									 HystrixFeign.Builder builder, Class<?> fallback) {
-		T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
-		return builder.target(target, fallbackInstance);
-	}
-
-	private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context, Class<?> beanType,
-								 Class<T> targetType) {
-		Object fallbackInstance = context.getInstance(feignClientName, beanType);
-		if (fallbackInstance == null) {
-			throw new IllegalStateException(String.format("No " + fallbackMechanism +
-				" instance of type %s found for feign client %s", beanType, feignClientName));
-		}
-
-		if (!targetType.isAssignableFrom(beanType)) {
-			throw new IllegalStateException(String.format(
-				"Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of " +
-					"type %s is not assignable to %s for feign client %s", beanType, targetType, feignClientName));
-		}
-		return (T) fallbackInstance;
-	}
-
-	@Nullable
-	private <T> T getOptional(String feignClientName, FeignContext context, Class<T> beanType) {
-		return context.getInstance(feignClientName, beanType);
-	}
-}

+ 0 - 39
blade-core-cloud/src/main/java/org/springframework/cloud/openfeign/Targeter.java

@@ -1,39 +0,0 @@
-/*
- * Copyright 2013-2016 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.openfeign;
-
-import feign.Feign;
-import feign.Target;
-
-/**
- * @author Spencer Gibb
- */
-public interface Targeter {
-	/**
-	 * target
-	 *
-	 * @param factory
-	 * @param feign
-	 * @param context
-	 * @param target
-	 * @param <T>
-	 * @return T
-	 */
-	<T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
-				 Target.HardCodedTarget<T> target);
-}

+ 1 - 1
blade-core-develop/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
blade-core-launch/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-launch/src/main/java/org/springblade/core/launch/StartEventListener.java

@@ -30,7 +30,7 @@ import org.springframework.util.StringUtils;
  * @author Chill
  */
 @Slf4j
-@Configuration
+@Configuration(proxyBeanMethods = false)
 public class StartEventListener {
 
 	@Async

+ 1 - 1
blade-core-launch/src/main/java/org/springblade/core/launch/config/BladeLaunchConfiguration.java

@@ -27,7 +27,7 @@ import org.springframework.core.annotation.Order;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @Order(Ordered.HIGHEST_PRECEDENCE)
 @EnableConfigurationProperties({

+ 1 - 1
blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java

@@ -25,7 +25,7 @@ public interface AppConstant {
 	/**
 	 * 应用版本
 	 */
-	String APPLICATION_VERSION = "2.8.0";
+	String APPLICATION_VERSION = "3.0.0";
 
 	/**
 	 * 基础包

+ 1 - 1
blade-core-launch/src/main/java/org/springblade/core/launch/server/ServerInfo.java

@@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration;
  * @author Chill
  */
 @Getter
-@Configuration
+@Configuration(proxyBeanMethods = false)
 public class ServerInfo implements SmartInitializingSingleton {
 	private final ServerProperties serverProperties;
 	private String hostName;

+ 1 - 1
blade-core-log/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java

@@ -41,7 +41,7 @@ import javax.servlet.Servlet;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @ConditionalOnWebApplication
 @AutoConfigureBefore(ErrorMvcAutoConfiguration.class)

+ 1 - 1
blade-core-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java

@@ -34,7 +34,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @ConditionalOnWebApplication
 public class BladeLogToolAutoConfiguration {

+ 4 - 2
blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java

@@ -18,6 +18,7 @@ package org.springblade.core.log.error;
 import org.springblade.core.tool.jackson.JsonUtil;
 import org.springframework.boot.autoconfigure.web.ErrorProperties;
 import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
+import org.springframework.boot.web.error.ErrorAttributeOptions;
 import org.springframework.boot.web.servlet.error.ErrorAttributes;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -41,12 +42,13 @@ public class BladeErrorController extends BasicErrorController {
 
 	@Override
 	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
-		Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
+		boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
+		Map<String, Object> body = getErrorAttributes(request, (includeStackTrace) ? ErrorAttributeOptions.of(ErrorAttributeOptions.Include.STACK_TRACE) : ErrorAttributeOptions.defaults());
 		HttpStatus status = getStatus(request);
 		response.setStatus(status.value());
 		MappingJackson2JsonView view = new MappingJackson2JsonView();
 		view.setObjectMapper(JsonUtil.getInstance());
-		view.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
+		view.setContentType(MediaType.APPLICATION_JSON_VALUE);
 		return new ModelAndView(view, body);
 	}
 

+ 1 - 1
blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java

@@ -55,7 +55,7 @@ import java.util.Set;
  * @author Chill
  */
 @Slf4j
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @ConditionalOnClass({Servlet.class, DispatcherServlet.class})
 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
 @RestControllerAdvice

+ 1 - 1
blade-core-mybatis/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-oss/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
blade-core-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java

@@ -37,7 +37,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @AutoConfigureAfter(QiniuConfiguration.class)
 @EnableConfigurationProperties(OssProperties.class)

+ 1 - 1
blade-core-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java

@@ -36,7 +36,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @EnableConfigurationProperties(OssProperties.class)
 @ConditionalOnProperty(value = "oss.name", havingValue = "qiniu")

+ 1 - 1
blade-core-report/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
blade-core-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java

@@ -40,7 +40,7 @@ import javax.servlet.Servlet;
  * @author Chill
  */
 @Order
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @ConditionalOnProperty(value = "report.enabled", havingValue = "true", matchIfMissing = true)
 @EnableConfigurationProperties({ReportProperties.class, ReportDatabaseProperties.class})
 @ImportResource("classpath:ureport-console-context.xml")

+ 1 - 1
blade-core-secure/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-secure/src/main/java/org/springblade/core/secure/config/RegistryConfiguration.java

@@ -29,7 +29,7 @@ import org.springframework.core.annotation.Order;
  * @author Chill
  */
 @Order
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AutoConfigureBefore(SecureConfiguration.class)
 public class RegistryConfiguration {
 

+ 1 - 1
blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java

@@ -39,7 +39,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  * @author Chill
  */
 @Order
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @EnableConfigurationProperties({BladeSecureProperties.class})
 public class SecureConfiguration implements WebMvcConfigurer {

+ 1 - 1
blade-core-social/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
blade-core-social/src/main/java/org/springblade/core/social/config/SocialConfiguration.java

@@ -29,7 +29,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @EnableConfigurationProperties(SocialProperties.class)
 public class SocialConfiguration {
 

+ 1 - 1
blade-core-swagger/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerAutoConfiguration.java

@@ -41,7 +41,7 @@ import java.util.List;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @EnableSwagger
 @EnableConfigurationProperties(SwaggerProperties.class)
 @Import(BeanValidatorPluginsConfiguration.class)

+ 1 - 1
blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java

@@ -55,7 +55,7 @@ public class SwaggerProperties {
 	/**
 	 * 版本
 	 **/
-	private String version = "2.8.0";
+	private String version = "3.0.0";
 	/**
 	 * 许可证
 	 **/

+ 1 - 1
blade-core-test/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.springblade</groupId>
         <artifactId>blade-tool</artifactId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 0 - 30
blade-core-test/src/main/java/org/springblade/core/test/BladeBaseTest.java

@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
- * <p>
- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.gnu.org/licenses/lgpl.html
- * <p>
- * 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.springblade.core.test;
-
-import org.junit.runner.RunWith;
-import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
-
-/**
- * boot test 基类
- *
- * @author L.cm
- */
-@RunWith(BladeSpringRunner.class)
-public abstract class BladeBaseTest extends AbstractJUnit4SpringContextTests {
-
-}

+ 2 - 0
blade-core-test/src/main/java/org/springblade/core/test/BladeBootTest.java

@@ -16,6 +16,7 @@
 
 package org.springblade.core.test;
 
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.core.annotation.AliasFor;
 
@@ -31,6 +32,7 @@ import java.lang.annotation.*;
 @Documented
 @Inherited
 @SpringBootTest
+@ExtendWith(BladeSpringExtension.class)
 public @interface BladeBootTest {
 	/**
 	 * 服务名:appName

+ 11 - 8
blade-core-test/src/main/java/org/springblade/core/test/BladeSpringRunner.java → blade-core-test/src/main/java/org/springblade/core/test/BladeSpringExtension.java

@@ -17,7 +17,7 @@
 package org.springblade.core.test;
 
 
-import org.junit.runners.model.InitializationError;
+import org.junit.jupiter.api.extension.ExtensionContext;
 import org.springblade.core.launch.BladeApplication;
 import org.springblade.core.launch.constant.AppConstant;
 import org.springblade.core.launch.constant.NacosConstant;
@@ -25,7 +25,8 @@ import org.springblade.core.launch.constant.SentinelConstant;
 import org.springblade.core.launch.service.LauncherService;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.lang.NonNull;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -35,14 +36,16 @@ import java.util.stream.Collectors;
  *
  * @author L.cm
  */
-public class BladeSpringRunner extends SpringJUnit4ClassRunner {
+public class BladeSpringExtension extends SpringExtension {
 
-	public BladeSpringRunner(Class<?> clazz) throws InitializationError {
-		super(clazz);
-		setUpTestClass(clazz);
+	@Override
+	public void beforeAll(@NonNull ExtensionContext context) throws Exception {
+		super.beforeAll(context);
+		setUpTestClass(context);
 	}
 
-	private void setUpTestClass(Class<?> clazz) {
+	private void setUpTestClass(ExtensionContext context) {
+		Class<?> clazz = context.getRequiredTestClass();
 		BladeBootTest bladeBootTest = AnnotationUtils.getAnnotation(clazz, BladeBootTest.class);
 		if (bladeBootTest == null) {
 			throw new BladeBootTestException(String.format("%s must be @BladeBootTest .", clazz));
@@ -74,7 +77,7 @@ public class BladeSpringRunner extends SpringJUnit4ClassRunner {
 			launcherList.stream().sorted(Comparator.comparing(LauncherService::getOrder)).collect(Collectors.toList())
 				.forEach(launcherService -> launcherService.launcher(builder, appName, profile));
 		}
-		System.err.println(String.format("---[junit.test]:[%s]---启动中,读取到的环境变量:[%s]", appName, profile));
+		System.err.printf("---[junit.test]:[%s]---启动中,读取到的环境变量:[%s]%n", appName, profile);
 	}
 
 }

+ 1 - 1
blade-core-tool/pom.xml

@@ -6,7 +6,7 @@
     <parent>
         <groupId>org.springblade</groupId>
         <artifactId>blade-tool</artifactId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java

@@ -41,7 +41,7 @@ import java.util.TimeZone;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @ConditionalOnClass(ObjectMapper.class)
 @AutoConfigureBefore(JacksonAutoConfiguration.class)

+ 1 - 1
blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java

@@ -34,7 +34,7 @@ import java.util.List;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @Order(Ordered.HIGHEST_PRECEDENCE)
 public class MessageConfiguration implements WebMvcConfigurer {

+ 1 - 1
blade-core-tool/src/main/java/org/springblade/core/tool/config/RedisTemplateConfiguration.java

@@ -41,7 +41,7 @@ import java.time.Duration;
  * @author Chill
  */
 @EnableCaching
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AutoConfigureBefore(RedisAutoConfiguration.class)
 public class RedisTemplateConfiguration {
 

+ 1 - 1
blade-core-tool/src/main/java/org/springblade/core/tool/config/ToolConfiguration.java

@@ -28,7 +28,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @Order(Ordered.HIGHEST_PRECEDENCE)
 public class ToolConfiguration implements WebMvcConfigurer {
 

+ 1 - 1
blade-core-tool/src/main/java/org/springblade/core/tool/config/XssConfiguration.java

@@ -33,7 +33,7 @@ import javax.servlet.DispatcherType;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @AllArgsConstructor
 @ConditionalOnProperty(value = "blade.xss.enabled", havingValue = "true")
 @EnableConfigurationProperties({XssProperties.class, XssUrlProperties.class})

+ 2 - 2
blade-core-tool/src/main/java/org/springblade/core/tool/utils/RedisUtil.java

@@ -3,6 +3,7 @@ package org.springblade.core.tool.utils;
 import lombok.AllArgsConstructor;
 import org.springframework.data.redis.core.RedisTemplate;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -69,13 +70,12 @@ public class RedisUtil {
 	 *
 	 * @param key 可以传一个值 或多个
 	 */
-	@SuppressWarnings("unchecked")
 	public void del(String... key) {
 		if (key != null && key.length > 0) {
 			if (key.length == 1) {
 				redisTemplate.delete(key[0]);
 			} else {
-				redisTemplate.delete(CollectionUtil.arrayToList(key));
+				redisTemplate.delete(Arrays.asList(key));
 			}
 		}
 	}

+ 1 - 1
blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java

@@ -127,7 +127,7 @@ public class WebUtil extends org.springframework.web.util.WebUtils {
 	 * @param result   结果对象
 	 */
 	public static void renderJson(HttpServletResponse response, Object result) {
-		renderJson(response, result, MediaType.APPLICATION_JSON_UTF8_VALUE);
+		renderJson(response, result, MediaType.APPLICATION_JSON_VALUE);
 	}
 
 	/**

+ 7 - 1
blade-core-transaction/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.8.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -15,11 +15,17 @@
     <packaging>jar</packaging>
 
     <dependencies>
+        <!-- Blade-->
         <dependency>
             <groupId>org.springblade</groupId>
             <artifactId>blade-core-mybatis</artifactId>
             <version>${blade.tool.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-cloud</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
         <!-- Cloud-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>

+ 33 - 0
blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignBlockingLoadBalancerClient.java

@@ -0,0 +1,33 @@
+package com.alibaba.cloud.seata.feign;
+
+import feign.Client;
+import feign.Request;
+import feign.Response;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
+import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
+
+import java.io.IOException;
+
+/**
+ * 重写SeataFeignBlockingLoadBalancerClient以适配最新API
+ *
+ * @author Chill
+ */
+public class SeataFeignBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient {
+
+	public SeataFeignBlockingLoadBalancerClient(Client delegate,
+												BlockingLoadBalancerClient loadBalancerClient,
+												SeataFeignObjectWrapper seataFeignObjectWrapper,
+												LoadBalancerProperties properties,
+												LoadBalancerClientFactory loadBalancerClientFactory) {
+		super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient, properties, loadBalancerClientFactory);
+	}
+
+	@Override
+	public Response execute(Request request, Request.Options options) throws IOException {
+		return super.execute(request, options);
+	}
+
+}

+ 85 - 0
blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignClientAutoConfiguration.java

@@ -0,0 +1,85 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.seata.feign;
+
+import feign.Client;
+import feign.Feign;
+import feign.Retryer;
+import lombok.RequiredArgsConstructor;
+import org.springblade.core.cloud.feign.BladeFeignSentinel;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.cloud.openfeign.FeignAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+
+/**
+ * 重写SeataFeignClientAutoConfiguration以适配最新API
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnClass(Client.class)
+@AutoConfigureBefore(FeignAutoConfiguration.class)
+public class SeataFeignClientAutoConfiguration {
+
+	@Bean
+	@Scope("prototype")
+	@ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU")
+	@ConditionalOnProperty(name = "feign.sentinel.enabled", havingValue = "true")
+	Feign.Builder feignSentinelBuilder(BeanFactory beanFactory) {
+		return BladeFeignSentinel.builder().retryer(Retryer.NEVER_RETRY)
+			.client(new SeataFeignClient(beanFactory));
+	}
+
+	@Bean
+	@ConditionalOnMissingBean
+	@Scope("prototype")
+	Feign.Builder feignBuilder(BeanFactory beanFactory) {
+		return SeataFeignBuilder.builder(beanFactory);
+	}
+
+	@Configuration(proxyBeanMethods = false)
+	@RequiredArgsConstructor
+	protected static class FeignBeanPostProcessorConfiguration {
+		private final LoadBalancedRetryFactory loadBalancedRetryFactory;
+		private final LoadBalancerProperties properties;
+		private final LoadBalancerClientFactory loadBalancerClientFactory;
+
+		@Bean
+		SeataBeanPostProcessor seataBeanPostProcessor(SeataFeignObjectWrapper seataFeignObjectWrapper) {
+			return new SeataBeanPostProcessor(seataFeignObjectWrapper);
+		}
+
+		@Bean
+		SeataContextBeanPostProcessor seataContextBeanPostProcessor(BeanFactory beanFactory) {
+			return new SeataContextBeanPostProcessor(beanFactory);
+		}
+
+		@Bean
+		SeataFeignObjectWrapper seataFeignObjectWrapper(BeanFactory beanFactory) {
+			return new SeataFeignObjectWrapper(beanFactory, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
+		}
+
+	}
+}

+ 74 - 0
blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataFeignObjectWrapper.java

@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.seata.feign;
+
+import feign.Client;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
+import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
+import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient;
+
+/**
+ * 重写SeataFeignObjectWrapper以适配最新API
+ *
+ * @author Chill
+ */
+public class SeataFeignObjectWrapper {
+
+	private final BeanFactory beanFactory;
+	private final LoadBalancedRetryFactory loadBalancedRetryFactory;
+	private final LoadBalancerProperties properties;
+	private final LoadBalancerClientFactory loadBalancerClientFactory;
+
+	private SpringClientFactory springClientFactory;
+
+	SeataFeignObjectWrapper(BeanFactory beanFactory, LoadBalancedRetryFactory loadBalancedRetryFactory, LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) {
+		this.beanFactory = beanFactory;
+		this.loadBalancedRetryFactory = loadBalancedRetryFactory;
+		this.properties = properties;
+		this.loadBalancerClientFactory = loadBalancerClientFactory;
+	}
+
+	Object wrap(Object bean) {
+		if (bean instanceof Client && !(bean instanceof SeataFeignClient)) {
+			if (bean instanceof FeignBlockingLoadBalancerClient) {
+				FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) bean;
+				return new SeataFeignBlockingLoadBalancerClient(client.getDelegate(),
+					beanFactory.getBean(BlockingLoadBalancerClient.class), this, properties, loadBalancerClientFactory);
+			}
+			if (bean instanceof RetryableFeignBlockingLoadBalancerClient) {
+				RetryableFeignBlockingLoadBalancerClient client = (RetryableFeignBlockingLoadBalancerClient) bean;
+				return new SeataRetryableFeignBlockingLoadBalancerClient(client.getDelegate(),
+					beanFactory.getBean(BlockingLoadBalancerClient.class), this, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
+			}
+			return new SeataFeignClient(this.beanFactory, (Client) bean);
+		}
+		return bean;
+	}
+
+	SpringClientFactory clientFactory() {
+		if (this.springClientFactory == null) {
+			this.springClientFactory = this.beanFactory
+				.getBean(SpringClientFactory.class);
+		}
+		return this.springClientFactory;
+	}
+
+}

+ 49 - 0
blade-core-transaction/src/main/java/com/alibaba/cloud/seata/feign/SeataRetryableFeignBlockingLoadBalancerClient.java

@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.seata.feign;
+
+import feign.Client;
+import feign.Request;
+import feign.Response;
+import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
+import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient;
+
+import java.io.IOException;
+
+/**
+ * 拓展SeataRetryableFeignBlockingLoadBalancerClient以适配最新API
+ *
+ * @author Chill
+ */
+public class SeataRetryableFeignBlockingLoadBalancerClient extends RetryableFeignBlockingLoadBalancerClient {
+
+	public SeataRetryableFeignBlockingLoadBalancerClient(Client delegate,
+														 BlockingLoadBalancerClient loadBalancerClient,
+														 SeataFeignObjectWrapper seataFeignObjectWrapper,
+														 LoadBalancedRetryFactory loadBalancedRetryFactory,
+														 LoadBalancerProperties properties,
+														 LoadBalancerClientFactory loadBalancerClientFactory) {
+		super((Client) seataFeignObjectWrapper.wrap(delegate), loadBalancerClient, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
+	}
+
+	@Override
+	public Response execute(Request request, Request.Options options) throws IOException {
+		return super.execute(request, options);
+	}
+}

+ 3 - 2
blade-core-transaction/src/main/java/org/springblade/core/transaction/annotation/SeataCloudApplication.java

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2028, lengleng (wangiegie@gmail.com).
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
  * <p>
  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
 
 import java.lang.annotation.*;
 
@@ -33,7 +34,7 @@ import java.lang.annotation.*;
 @Inherited
 @EnableDiscoveryClient
 @EnableCircuitBreaker
-@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, RibbonAutoConfiguration.class})
 public @interface SeataCloudApplication {
 
 }

+ 2 - 2
blade-core-transaction/src/main/java/org/springblade/core/transaction/config/DataSourceConfiguration.java

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2028, lengleng (wangiegie@gmail.com).
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
  * <p>
  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
  * you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.springframework.context.annotation.Configuration;
  *
  * @author Chill
  */
-@Configuration
+@Configuration(proxyBeanMethods = false)
 public class DataSourceConfiguration {
 
 }

+ 13 - 8
pom.xml

@@ -5,7 +5,7 @@
 
     <groupId>org.springblade</groupId>
     <artifactId>blade-tool</artifactId>
-    <version>2.8.0</version>
+    <version>3.0.0</version>
     <packaging>pom</packaging>
     <name>blade-tool</name>
     <description>
@@ -36,24 +36,24 @@
     </scm>
 
     <properties>
-        <blade.tool.version>2.8.0</blade.tool.version>
+        <blade.tool.version>3.0.0</blade.tool.version>
 
         <java.version>1.8</java.version>
         <maven.plugin.version>3.8.0</maven.plugin.version>
         <swagger.version>2.10.5</swagger.version>
         <swagger.models.version>1.6.2</swagger.models.version>
-        <knife4j.version>2.0.6</knife4j.version>
-        <mybatis.plus.version>3.4.0</mybatis.plus.version>
+        <knife4j.version>2.0.8</knife4j.version>
+        <mybatis.plus.version>3.4.1</mybatis.plus.version>
         <protostuff.version>1.6.0</protostuff.version>
         <disruptor.version>3.4.2</disruptor.version>
-        <spring.boot.admin.version>2.3.0</spring.boot.admin.version>
+        <spring.boot.admin.version>2.3.1</spring.boot.admin.version>
         <mica.auto.version>1.2.5</mica.auto.version>
         <alibaba.cloud.version>2.2.3.RELEASE</alibaba.cloud.version>
-        <alibaba.seata.version>1.3.0</alibaba.seata.version>
+        <alibaba.seata.version>1.4.1</alibaba.seata.version>
         <spring.plugin.version>2.0.0.RELEASE</spring.plugin.version>
 
-        <spring.boot.version>2.2.11.RELEASE</spring.boot.version>
-        <spring.cloud.version>Hoxton.SR8</spring.cloud.version>
+        <spring.boot.version>2.4.1</spring.boot.version>
+        <spring.cloud.version>2020.0.0</spring.cloud.version>
         <spring.platform.version>Cairo-SR8</spring.platform.version>
 
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -141,6 +141,11 @@
             <artifactId>lombok</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.hibernate.validator</groupId>
+            <artifactId>hibernate-validator</artifactId>
+            <version>6.2.0.Final</version>
+        </dependency>
         <dependency>
             <groupId>net.dreamlu</groupId>
             <artifactId>mica-auto</artifactId>