优质博文:IT-BLOG-CN
我们这次项目主要从RestTemplate 和 Feign 进行选型分析。
一、Spring Cloud Feign分析
Feign是另外一种客户端负载均衡实现。
我在该模块写了Feign Client的示例代码。
【1】spring-cloud-web-demo-api为服务的sdk模块
【2】spring-cloud-web-demo-service为提供接口服务的模块
【3】spring-cloud-web-demo-client为模拟调用服务的模块
首先在spring-cloud-web-demo-api模块,定义Feign API。spring-cloud-web-demo为spring-cloud-web-demo-service暴露的服务名。
@FeignClient(value = "spring-cloud-web-demo")
public interface UserFeign {
@GetMapping(value = "/user/getUserById", produces = "application/json;charset=utf-8")
Object getUserById(@RequestParam(value = "id", required = false) Long id);
//省略
}
然后通过ClientAutoConfiguration自动装配。(client直接引入api包就可以使用,不需要再EnableFeignClients)
@Configuration
@EnableFeignClients("net.teaho.demo.spring.cloud.web.api")
public class ClientAutoConfiguration {
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
net.teaho.demo.spring.cloud.web.api.config.ClientAutoConfiguration
在service模块如以往Spring MVC般实现api模块接口即可。
@RestController
public class UserController implements UserFeign {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Override
public Object getUserById(Long id) {
return "{"id":1, "name": "test"}";
}
//省略
}
在Client模块,注入bean后直接调用。
@Component
@Slf4j
public class TestService {
@Autowired
private RestTemplate restTemplate;
public Object getOneUser(){
return userController.getUserById(1L);
}
}
二、RestTemplate分析
写了具有客户端负载均衡能力的RestTemplate的请求代码。
类似这样定义:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
RestTemplate究竟是如何利用注册中心实现客户端负载均衡的呢?
实现方式: 就是将上面所说的LoadBalancerInterceptor负载均衡拦截器加到标注了@LoadBalanced的RestTemplate实例中。 LoadBalancerInterceptor拦截器会在执行过程中获取并设置适合的目标请求实例,重新构造请求URI。
// 将配置中标注了@LoadBalanced的RestTemplate注入到这里
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
//将注册的RestTemplateCustomizer(RestTemplate自定义器)集合处理上面的restTemplates集合
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
三、技术选型
最终选择使用OpenFeign,下面说说原因。
和RestTemplate比起来,OpenFeign显得更适合Spring Boot微服务。
Open Feign相当于(HTTP)RPC,相比起RestTemplate,它直接显式将API声明以JAVA接口形式标识出来。 并且因为底层用的动态代理,它还可以(无感知地)替换底层实现。比如,github上就有替换底层逻辑的repo – Open Feign+Dubbo的RPC实现。
通过sdk包的形式,方便了调用,不需要像RestTemplate一样,客户端自行拼接上一串请求参数。在代码编写上也清晰。
要使用就必须知道OpenFeign是怎么实现的呢?
四、OpenFeign 初始化分析
流程图如下:
看看前面例子里我们引入的OpenFeign的东西
【1】@EnableFeignClients(“net.teaho.demo.spring.cloud.web.api”)
【2】@FeignClient(value = “spring-cloud-web-demo”) 还有自动装配引入的
【3】FeignRibbonClientAutoConfiguration
【4】FeignClientsConfiguration
我们就从这两个注解开始分析源码。
【1】首先看@FeignClient注解。
//给接口标注成一个REST调用方
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
//服务名,可以带协议前缀,也可以用${property.name}关联一个配置值。
@AliasFor("name")
String value() default "";
@Deprecated
String serviceId() default "";
//bean name
String contextId() default "";
@AliasFor("value")
String name() default "";
/**
* Sets the <code>@Qualifier</code> value for the feign client.
*/
String qualifier() default "";
//直接指定一个地址,比如http://localhost:12345,一般用于调试
String url() default "";
boolean decode404() default false;
/**
* A custom <code>@Configuration</code> for the feign client. Can contain override
* <code>@Bean</code> definition for the pieces that make up the client, for instance
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
*
* @see FeignClientsConfiguration for the defaults
*/
//可用于覆盖FeignClient默认设置
Class<?>[] configuration() default {};
//回滚类,像我的例子中定义的回滚类必须实现UserFeign接口,看https://clou