- 什么是RestTemplate?
要理解什么是RestTemplate需要先了解REST。REST的全称是Representational State Transfer,意为表现层状态转化,是一种互联网软件架构风格,满足这种风格的程序或设计就可认为是REST或Restful的。REST定义一套请求资源的规范:用URI定位资源,用HTTP请求类型(GET,POST,PUT,DELETE)来描述操作。满足REST风格的Server提供Restful API(REST风格的接口),处于不同平台的Client便可以使用一套API来消费Server提供的服务。
RestTemplate是Spring框架提供的基于REST的服务组件,底层对HTTP请求及响应进行了封装,提供访问远程REST服务的方法,例如封装了GET请求的getForObject(String, Class, String...)方法,封装了DELETE请求的delete(String, String...)方法等等,可以简化代码的开发。
- 什么是Feign?
那么,让我们实现一个服务提供者consumer并使用这两种方法实现跨服务调用。
之前已经提到过,所谓服务提供者provider与服务消费者consumer只是从业务角度对他们进行划分,而从代码角度来看,他们都是Eureka Client。因此创建consumer的过程与provider大致相同。
- 在父工程下新建一个Module,命名为consumer
- 在pom.xml中添加Eureka Client依赖。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
- 在resources下创建配置文件application.yml,添加EurekaClient相关的配置,并命名为consumer
server:
port: 8020
spring:
application:
name: consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
- 之后在java路径下创建启动类ConsumerApplication。
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
- 启动注册中心,运行ConsumerApplication,访问http://localhost:8761/,应该看到服务消费者consumer已经完成注册。
使用RestTemplate访问REST服务
- RestTemplate 实例化
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- 创建ConsumerController类,通过@Autowired将IoC容器中的RestTemplate实例注入进来,在业务方法中可通过RestTemplate访问REST服务。
@RestController
@RequestMapping("consumer4actor")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
private void method(){
}
}- RestTemplate 的相关方法
- public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)。url 为请求的目标资源,responseType 为响应数据的封装模版,uriVariables 是一个动态参数,可以根据实际请求传入参数。 getForEntity 方法的返回值类型为 ResponseEntity,通过调用其 getBody 方法可获取结果对象。
- public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)。getForObject 方法的使用与 getForEntity 很类似,唯一的区别在于 getForObject 的返回值就是目标对象,无需通过调用 getBody 方法来获取.
@GetMapping("/findAll2") public Collection<Actor> findAll2(){ return restTemplate.getForObject("http://localhost:8010/actor/findAll",Collection.class); }
@GetMapping("/findAll")
public Collection<Actor> findAll(){
return restTemplate.getForEntity("http://localhost:8010/actor/findAll",Collection.class).getBody();
}- public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) . url 为请求的目标资源,request 为要保存的目标对象,responseType为响应数据的封装模版,uriVariables 是一个动态参数,可以根据实际请求传入参数。postForEntity 方法的返回值类型也是 ResponseEntity,通过调用其 getBody 方法可获取结果对象.
- public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables).
postForObject 方法的使用与 postForEntity 类似,唯一的区别在于 postForObject 的返回值就是目标对象,无需通过调用 getBody 方法来获取
@PostMapping("/save")
public Collection<Actor> save(@RequestBody Actor actor){
return restTemplate.postForEntity("http://localhost:8010/actor/save",actor,Collection.class).getBody();
}为了获得actor的集合,需要把provider微服务的ActorController略做修改,save方法保存后调用findAll()返回所有actor。
@PostMapping("/save")
public Collection<Actor> save(@RequestBody Actor actor){
actorMapper.save(actor);
return actorMapper.findAll();
} @PostMapping("/save2")
public Collection<Actor> save2(@RequestBody Actor actor){
return restTemplate.postForObject("http://localhost:8010/actor/save",actor,Collection.class);
}- public void put(String url, @Nullable Object request, Object... uriVariables). url 为请求的目标资源,request 为要修改的目标对象,uriVariables 是一个动态参数,可以根据实际请求传入参数.
- public void delete(String url, Object... uriVariables).
@DeleteMapping("/deleteById/{id}")
public void DeleteById(@PathVariable("id") Long id){
restTemplate.delete("http://localhost:8010/actor/deleteById/{id}",id);
}
依次启动 注册中心、ProviderApplication、ConsumerApplication,通过 Postman 工具来分别测试 ConsumerController的业务方法- findAll接口
- findAll2接口
重新调用findAll接口查看删除结果
Feign跨服务调用
在 Spring Cloud 中使用 Feign 非常简单,Feign 是一个声明式的 Web Service 客户端,所以只需要创建一个接口,同时在接口上添加相关注解即可完成服务提供方的接口绑定.
- 在pom.xml中添加Feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>- 修改启动类ConsumerApplication,添加注解@EnableFeignClients.该注解声明启用Feign.
- 接下来通过接口的方式调用Provider服务,创建ConsumeByFeignClient接口
@FeignClient(value = "provider")
public interface ConsumeByFeignClient {
@GetMapping("/actor/findAll")
public List<Actor> getAllByFeign();
}
@FeignClient 指定 Feign 要调用的微服务,直接指定服务提供者在注册中心的 application name 即可。- 修改ConsumerController,注入ConsumeByFeignClient,并调用接口的getAllByFeign方法
@Autowired
private ConsumeByFeignClient consumeByFeignClient;
@GetMapping("findAllByFeign")
public Collection<Actor> findAllByFeign(){
return consumeByFeignClient.getAllByFeign();
}
- 重新启动ConsumerApplication,使用PostMan工具调用findAllByFeign接口
调用成功.这里我仅定义了findAll接口,其他方法类似,就不赘述了.
本节实现了服务消费者,并通过RestTemplate和Feign两种方式实现了跨服务接口调用,可以发现,RestTemplate的方式需要得知服务提供者的具体地址,在url中显式填写。
而Feign只需要指定服务提供者在注册中心的名称即可,通过声明式接口的形式来调用服务,非常方便。同时Spring Cloud Feign是基于Ribbon实现,且使用更简单,同时集成了Hystrix,故具有可插拔,基于注解,负载均衡,服务熔断等一系列便捷功能,在实际开发中更推荐使用Feign.










No comments:
Post a Comment