远程服务调用

RestTemplate对象:

spring web模块中提供了一个RestTemplate对象,基于此对象可以完成远程(Remote)服务的

调用

@Bean
public RestTemplate restTemplate(){//基于此对象实现远端服务调用
    return new RestTemplate();
}

1.从spring容器中获取RestTemplate对象的方法中实现对远程服务

2.定义远程服务的url

3.基于RestTemplate的对象中得方法进行服务调用

package com.jt.consumer.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;


/**
 * 定义服务消费端Controller,在这个Controller对象
 * 的方法中实现对远端服务sca-provider的调用
 */
@RestController
public class ConsumerController {
    /**
     * 从spring容器获取一个RestTemplate对象,
     * 基于此对象实现远端服务调用
     */
    @Autowired
    private RestTemplate restTemplate;
    /**
     * 在此方法中通过一个RestTemplate对象调用远端sca-provider中的服务
     * @return
     * 访问此方法的url: http://localhost:8090/consumer/doRestEcho1
     */
    @GetMapping("/consumer/doRestEcho1")
    public String doRestEcho01(){
        //1.定义要调用的远端服务的url
        String url="http://localhost:8081/provider/echo/8090";
        //2.基于restTemplate对象中的相关方法进行服务调用
        return restTemplate.getForObject(url, String.class);
    }

}

远程服务调用成功:

 报错分析:500  404

 服务调用时底层404问题,例如: 

 

 服务调用时,连接异常,例如:

 LoadBalancerClient应用

服务负载均衡设计及实现(重点)

loadBalancaerClient对象可以基于服务名从nacos中获取多个服务实例、并且基于一定负载均衡算法进行远程服务调用。

 1.基于服务名获取服务实例

2.基于服务实例构建要访问的url

服务实例.getHost() 获取ip地址
服务实例.getPort() 获取端口号
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Value("${spring.application.name:8090}")
    private String appName;

    @GetMapping("/consumer/doRestEcho02")
    public String doRestEcho02(){
        //基于服务名获取服务实例
         ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
         //基于服务实例构建要访问的url
        //serviceInstance.getHost() 获取ip地址
        //serviceInstance.getPort() 获取端口号
        String url = String.format("http://%s:%s/provider/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
        System.out.println("request url:"+url);
        return restTemplate.getForObject(url, String.class);
    }
}

流程: 

 @LoadBalanced

当我们使用@loadBalanced注解描述RestTemplate对象时,假如此时再基于RestTemplate对象对远程服务进行远程服务进行访问时 ,就会先被一个拦截器拦截下来,请求被拦截到以后就会先基于服务名找到服务实例(负载均衡)

@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(){
    return new RestTemplate();
}

如何定义算法: 当默然的负载均衡算法不满足我的时候我们可以自定义算法:
基于ribbon中的IRwle接口,可以自定义算法。

基于Feign的远程服务调用(重点)

feign 是一种声明式web服务客户端,底层封装了对Rest技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。

  添加feign的添加依赖:

feign 依赖(此依赖添加以后,会为我们的项目注入一个feign starter组件)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

第二步:在启动类上添加@EnableFeignClients注解

@EnableFeignClients作用启动一个feignStarter组件,组件的作用是扫描@FeignClient下的接口,
为相关的接口构建实现类,在实现类的内部对远端服务的调用。
package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    @Bean
    public RestTemplate restTemplate(){//基于此对象实现远端服务调用
        return new RestTemplate();
    }

定义Http请求API,基于此API借助OpenFeign访问远端服务

这里的@feignClient注解用于描述feign远成服务调用接口,假如在项目配置类或者启动类上添加了

@EnableFeignClients注解,系统会在启动时,扫描@feignClient注解描述的接口,并为接口创建实现类对象(这个实现类我们称为代理对象),此对象内部会封装对远程服务调用的过程。

@feignClient注解中name属性的值有两个层面:

1)RemoteProviderService接口类型对象交给spring管理时,这个对象(bea)的名字

2)远程调用服务名 

package com.jt.consumer.controller.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

//name是远程服务的名字
@FeignClient(name = "sca-provider3")
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

创建FeignConsumerController中并添加feign访问

package com.jt.consumer.controller;
@RestController
@RequestMapping("/consumer/ ")
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;
    /**基于feign方式的服务调用*/
    @GetMapping("/echo/{msg}")
    public String doFeignEcho(@PathVariable  String msg){
        //基于feign方式进行远端服务调用(前提是服务必须存在)
        return remoteProviderService.echoMessage(msg);
    }
}

启动消费者服务,在浏览器中直接通过feign客户端进行访问,如图所示(反复刷新检测其响应结果):

feign错误演示: 

 

 404:

 Feign配置进阶实践:

一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务
启动就会失败,例如,假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败,例如:

 @FeignClient(name="sca-provider")
 public interface RemoteOtherService {
     @GetMapping("/doSomeThing")
     public String doSomeThing();
}

其启动异常如下

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识(这个标识是Bean对象的名字)即可,例如:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如,在Feign应用中通过FallbackFactory接口的实现类进行默认的相关处理,例如:

定义FallbackFactory接口的实现,代码如下:

package com.cy.service.factory;
/**
 * 基于此对象处理RemoteProviderService接口调用时出现的服务中断,超时等问题
 */
@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
    /**
     * 此方法会在RemoteProviderService接口服务调用时,出现了异常后执行.
     * @param throwable 用于接收异常
     */
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
                return "服务维护中,稍等片刻再访问";
        };
    }
}

:在Feign访问接口中应用FallbackFactory对象:

@FeignClient(name = "sca-provider", contextId = "remoteProviderService",
             fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{msg}")
    public String echoMsg(@PathVariable String msg);
}

:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制.

feign:  
  hystrix:
    enabled: true #默认值为false


 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值