88import com .fasterxml .jackson .databind .ObjectMapper ;
99import com .github .cadecode .uniboot .common .core .util .JacksonUtil ;
1010import com .github .cadecode .uniboot .framework .api .consts .HttpConst ;
11+ import com .github .cadecode .uniboot .framework .base .config .FeignConfig .ApacheHttpFeignConfig ;
12+ import com .github .cadecode .uniboot .framework .base .config .FeignConfig .DefaultFeignConfig ;
1113import com .github .cadecode .uniboot .framework .base .feign .FeignClientDecorator ;
1214import com .github .cadecode .uniboot .framework .base .feign .FeignErrorDecoder ;
1315import com .github .cadecode .uniboot .framework .base .security .model .SysUserDetails ;
1719import feign .Client .Default ;
1820import feign .Logger .Level ;
1921import feign .RequestInterceptor ;
20- import feign .RequestTemplate ;
2122import feign .codec .ErrorDecoder ;
23+ import feign .httpclient .ApacheHttpClient ;
24+ import lombok .extern .slf4j .Slf4j ;
25+ import org .apache .http .client .HttpClient ;
2226import org .springframework .boot .autoconfigure .condition .ConditionalOnProperty ;
2327import org .springframework .cloud .client .loadbalancer .LoadBalancedRetryFactory ;
2428import org .springframework .cloud .client .loadbalancer .LoadBalancerClient ;
2832import org .springframework .cloud .openfeign .loadbalancer .RetryableFeignBlockingLoadBalancerClient ;
2933import org .springframework .context .annotation .Bean ;
3034import org .springframework .context .annotation .Configuration ;
35+ import org .springframework .context .annotation .Import ;
3136
3237import javax .servlet .http .HttpServletRequest ;
3338
3742 * @author Cade Li
3843 * @since 2023/7/29
3944 */
45+ @ Slf4j
4046@ Configuration
47+ @ Import ({ApacheHttpFeignConfig .class , DefaultFeignConfig .class })
4148public class FeignConfig {
4249
4350 /**
4451 * feign 拦截器
4552 */
4653 @ Bean
4754 public RequestInterceptor requestInterceptor () {
48- return this ::configRequestTemplate ;
49- }
50-
51- protected void configRequestTemplate (RequestTemplate requestTemplate ) {
52- // 设置内部请求来源标识
53- requestTemplate .header (HttpConst .HEAD_SOURCE , HttpConst .HEAD_SOURCE_VALUE );
54- HttpServletRequest servletRequest = RequestUtil .getRequest ();
55- if (ObjUtil .isNull (servletRequest )) {
56- return ;
57- }
58- // 配置客户端 IP
59- requestTemplate .header (HttpConst .HEAD_FORWARDED_FOR , ServletUtil .getClientIP (servletRequest ));
60- // 传递 trace id
61- String traceId = ServletUtil .getHeader (servletRequest , HttpConst .HEAD_TRACE_ID , CharsetUtil .CHARSET_UTF_8 );
62- if (ObjUtil .isNotEmpty (traceId )) {
63- requestTemplate .header (HttpConst .HEAD_TRACE_ID , traceId );
64- }
65- // 传递用户 token
66- String token = SecurityUtil .getTokenFromRequest (servletRequest );
67- if (StrUtil .isNotEmpty (token )) {
68- requestTemplate .header (HttpConst .HEAD_TOKEN , token );
69- }
70- // 传递用户信息
71- String userDetailsJson = ServletUtil .getHeader (servletRequest , HttpConst .HEAD_USER_DETAILS , CharsetUtil .CHARSET_UTF_8 );
72- // 不存在则生成
73- if (StrUtil .isEmpty (userDetailsJson )) {
74- SysUserDetails userDetailsDto = SecurityUtil .getUserDetails (null );
75- userDetailsJson = JacksonUtil .toJson (userDetailsDto );
76- }
77- requestTemplate .header (HttpConst .HEAD_USER_DETAILS , EscapeUtil .escape (userDetailsJson ));
78- }
79-
80- // 覆盖 feign 配置
81- // org.springframework.cloud.openfeign.loadbalancer.DefaultFeignLoadBalancerConfiguration
82-
83- @ Bean
84- @ ConditionalOnProperty (value = "spring.cloud.loadbalancer.retry.enabled" , havingValue = "false" )
85- public Client feignClient (LoadBalancerClient loadBalancerClient , LoadBalancerProperties properties ,
86- LoadBalancerClientFactory loadBalancerClientFactory ) {
87- FeignClientDecorator decorator = new FeignClientDecorator (new Default (null , null ));
88- return new FeignBlockingLoadBalancerClient (decorator , loadBalancerClient , properties , loadBalancerClientFactory );
89- }
90-
91- @ Bean
92- @ ConditionalOnProperty (value = "spring.cloud.loadbalancer.retry.enabled" , havingValue = "true" , matchIfMissing = true )
93- public Client feignRetryClient (LoadBalancerClient loadBalancerClient , LoadBalancedRetryFactory loadBalancedRetryFactory ,
94- LoadBalancerProperties properties , LoadBalancerClientFactory loadBalancerClientFactory ) {
95- FeignClientDecorator decorator = new FeignClientDecorator (new Default (null , null ));
96- return new RetryableFeignBlockingLoadBalancerClient (decorator , loadBalancerClient , loadBalancedRetryFactory , properties , loadBalancerClientFactory );
55+ return requestTemplate -> {
56+ // 设置内部请求来源标识
57+ requestTemplate .header (HttpConst .HEAD_SOURCE , HttpConst .HEAD_SOURCE_VALUE );
58+ HttpServletRequest servletRequest = RequestUtil .getRequest ();
59+ if (ObjUtil .isNull (servletRequest )) {
60+ return ;
61+ }
62+ // 配置客户端 IP
63+ requestTemplate .header (HttpConst .HEAD_FORWARDED_FOR , ServletUtil .getClientIP (servletRequest ));
64+ // 传递 trace id
65+ String traceId = ServletUtil .getHeader (servletRequest , HttpConst .HEAD_TRACE_ID , CharsetUtil .CHARSET_UTF_8 );
66+ if (ObjUtil .isNotEmpty (traceId )) {
67+ requestTemplate .header (HttpConst .HEAD_TRACE_ID , traceId );
68+ }
69+ // 传递用户 token
70+ String token = SecurityUtil .getTokenFromRequest (servletRequest );
71+ if (StrUtil .isNotEmpty (token )) {
72+ requestTemplate .header (HttpConst .HEAD_TOKEN , token );
73+ }
74+ // 传递用户信息
75+ String userDetailsJson = ServletUtil .getHeader (servletRequest , HttpConst .HEAD_USER_DETAILS , CharsetUtil .CHARSET_UTF_8 );
76+ // 不存在则生成
77+ if (StrUtil .isEmpty (userDetailsJson )) {
78+ SysUserDetails userDetailsDto = SecurityUtil .getUserDetails (null );
79+ userDetailsJson = JacksonUtil .toJson (userDetailsDto );
80+ }
81+ requestTemplate .header (HttpConst .HEAD_USER_DETAILS , EscapeUtil .escape (userDetailsJson ));
82+ };
9783 }
9884
9985 /**
@@ -111,4 +97,57 @@ public ErrorDecoder errorDecoder(ObjectMapper objectMapper) {
11197 public Level feignLogLevel () {
11298 return Level .BASIC ;
11399 }
100+
101+ /**
102+ * 覆盖 feign 配置, {@link org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration}
103+ * 参照 DefaultFeignLoadBalancerConfiguration
104+ * 集成 FeignClientDecorator 装饰类
105+ */
106+ @ ConditionalOnProperty (value = "feign.httpclient.enabled" , havingValue = "false" )
107+ static class DefaultFeignConfig {
108+ @ Bean
109+ @ ConditionalOnProperty (value = "spring.cloud.loadbalancer.retry.enabled" , havingValue = "false" )
110+ public Client feignClient (LoadBalancerClient loadBalancerClient , LoadBalancerProperties properties ,
111+ LoadBalancerClientFactory loadBalancerClientFactory ) {
112+ log .debug ("Feign client use default" );
113+ FeignClientDecorator decorator = new FeignClientDecorator (new Default (null , null ));
114+ return new FeignBlockingLoadBalancerClient (decorator , loadBalancerClient , properties , loadBalancerClientFactory );
115+ }
116+
117+ @ Bean
118+ @ ConditionalOnProperty (value = "spring.cloud.loadbalancer.retry.enabled" , havingValue = "true" , matchIfMissing = true )
119+ public Client feignRetryClient (LoadBalancerClient loadBalancerClient , LoadBalancedRetryFactory loadBalancedRetryFactory ,
120+ LoadBalancerProperties properties , LoadBalancerClientFactory loadBalancerClientFactory ) {
121+ log .debug ("Feign client use default, is retryable" );
122+ FeignClientDecorator decorator = new FeignClientDecorator (new Default (null , null ));
123+ return new RetryableFeignBlockingLoadBalancerClient (decorator , loadBalancerClient , loadBalancedRetryFactory , properties , loadBalancerClientFactory );
124+ }
125+ }
126+
127+ /**
128+ * 覆盖 feign 配置, {@link org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration}
129+ * 参照 HttpClientFeignLoadBalancerConfiguration
130+ * 集成 FeignClientDecorator 装饰类,使用 ApacheHttpClient
131+ */
132+ @ ConditionalOnProperty (value = "feign.httpclient.enabled" , havingValue = "true" , matchIfMissing = true )
133+ static class ApacheHttpFeignConfig {
134+ @ Bean
135+ @ ConditionalOnProperty (value = "spring.cloud.loadbalancer.retry.enabled" , havingValue = "false" )
136+ public Client apacheFeignClient (LoadBalancerClient loadBalancerClient , HttpClient httpClient ,
137+ LoadBalancerProperties properties , LoadBalancerClientFactory loadBalancerClientFactory ) {
138+ log .debug ("Feign client use apache httpclient" );
139+ FeignClientDecorator decorator = new FeignClientDecorator (new ApacheHttpClient (httpClient ));
140+ return new FeignBlockingLoadBalancerClient (decorator , loadBalancerClient , properties , loadBalancerClientFactory );
141+ }
142+
143+ @ Bean
144+ @ ConditionalOnProperty (value = "spring.cloud.loadbalancer.retry.enabled" , havingValue = "true" , matchIfMissing = true )
145+ public Client apacheFeignRetryClient (LoadBalancerClient loadBalancerClient , HttpClient httpClient ,
146+ LoadBalancedRetryFactory loadBalancedRetryFactory , LoadBalancerProperties properties ,
147+ LoadBalancerClientFactory loadBalancerClientFactory ) {
148+ log .debug ("Feign client use apache httpclient, is retryable" );
149+ FeignClientDecorator decorator = new FeignClientDecorator (new ApacheHttpClient (httpClient ));
150+ return new RetryableFeignBlockingLoadBalancerClient (decorator , loadBalancerClient , loadBalancedRetryFactory , properties , loadBalancerClientFactory );
151+ }
152+ }
114153}
0 commit comments