微服务04:基于Feign的远程服务调用

消费放基于rest方式请求服务提供方的服务时。一种直接的方法就是自己拼接url,拼接参数实现调用,但每次调用都需凭借,不易维护,对于这种死板的东西,肯定会有新的类或方法将其整合。于是Feign诞生

什么是Feign?封装了对Rest技术的应用,可以简化服务消费方的调用,大大较少开发过程

 Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由一些社区进行维护,更名为 OpenFeign。

使用Feign

第一步

编程高楼基础起,jar包导入最先行,第一步仍然是,导入jar包

为什么不需要指定版本号?(因为spring已经集成了版本信息,会自动配置)

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

第二步

在启动类上添加@EnableFeignClients(能够伪装客户?什么鬼翻译)

启动feign的服务

@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {…}

第三步

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

1.使用@FeignClient("服务端名字")注解获取指定服务端(sca-provider)信息

2.生成一个虚拟的接口,并以代理的方法,代理实现调用远端服务的功能

//定义了远程provider服务端用的service接口
//表示需要调用sca-provider服务,contextId 表示为当前对象成为被bean对象的id,
假如contextId 没有指定,那么默认会采取注解中name的名字作为bena的名字
@FeignClient(name = "sca-provider",contextId = "RemoteProviderService")
public interface RemoteProviderService {
    //因为获取的是string对象,所以采用string的方法获取
    @GetMapping("/provider/echo/{msg}")//前提是远端需要有这个服务
    public String getEchoMsg(@PathVariable("msg") String msg);
}

第四步

创建FeignConsumerController中并添加feign访问,代码如下:

@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客户端进行访问,如图所示(反复刷新检测其响应结果):

 总结

consumer.controller-->feign interface-->remote call

通过@EnableFeignCleints注解告诉Springboot启动Feign Starter组件

Feign Starter启动注册全员配置,扫描包下有@FeignClien注解的接口,然后由系统底层创建接口实现类(JDK代理类)并构建新类的对象,让后交给spring管理,注册IOC容器

接口被调用时被动态代理类逻辑拦截,将@FeignClient请求通过编码器生产Reques对象,基于此对象进行远程调用

请求对象经过Ribbon进行负载均衡,找出一个健康的server实例

通过Client携带Request调用远端服务器请求相应

通过解码器生成Respomse返回客户端,将信息流解析为接口返回数据

@FeignClient内的参数说明

@FeignClient(
        name = "sca-provider"       //定义了调用的远程provider服务端用的service名字
       
        //是创建bean对象后的名字,防止一个服务多次启动后产生bean名字冲突的结果
        ,contextId = "RemoteProviderService"    

        //如果服务调用失败(超时,不存在)时,可以有一个备用的方法或通知类(ProviderFallbackFactory.class,可以是提示用户稍后访问,或者其他重试逻辑)
        ,fallbackFactory = ProviderFallbackFactory.class)

可以创建一个继承FallbackFactory接口的方法重写create的方法来进行一个后备的通知和方法

FallbackFactory(后备方法集)接口:

public interface FallbackFactory<T> {
    T create(Throwable var1);

 编写ProviderFallbackFactory.class

@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return new RemoteProviderService() {
            @Override
            public String getEchoMsg(String msg) {
                return "服务器被玩坏了,稍后再试吧";
            }
        };
    }
}

使用lambda表达式(匿名函数)优化

@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return msg -> "服务器被玩坏了,稍后再试吧";
    }
}

打印相关日志

创建日志对象

private static Logger log =LoggerFactory.getLogger(ProviderFallbackFactory.class);

 输出日志

log.error("\r\n服务调用失败"+throwable.getMessage());
@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {

    //记录日志
    //org.slf4j.Logger是Java中的日志规范,定义了一组接口
    //org.slf4j.Logger这个接口的实现由log4j,logback
    private static Logger log =LoggerFactory.getLogger(ProviderFallbackFactory.class);

    @Override
    public RemoteProviderService create(Throwable throwable) {
        //log.info("\r\n服务调用失败"+throwable.getMessage());
        log.error("\r\n服务调用失败"+throwable.getMessage());

        return msg -> "服务器被玩坏了,稍后再试吧";
    }
}

还可以使用Lombok的@Log注解来输出日志

但是该方法只可以用在方法中,且只有log.info的方法可以使用

@Log
@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {

    //记录日志
    //org.slf4j.Logger是Java中的日志规范,定义了一组接口
    //org.slf4j.Logger这个接口的实现由log4j,logback
    //private static Logger log =LoggerFactory.getLogger(ProviderFallbackFactory.class);

    @Override
    public RemoteProviderService create(Throwable throwable) {
        log.info("\r\n服务调用失败"+throwable.getMessage());
        //log.error("\r\n服务调用失败"+throwable.getMessage());
        
        return msg -> "服务器被玩坏了,稍后再试吧";
    }
}

日志的输出级别

ERROR:系统发生了严重的错误,必须啊马上进行处理,否者系统无法继续运行,比如NPE,数据库不可用

WARN:系统仍然可用,但是必须引起关注,最好进行检查和调整。系统可以继续运行。对于存在的问题一般可以分成两类,一种系统存在明显的问题(数据不可用),另一种就是系统存在潜在问题,需要引起注意或给出一些建议。

INFO:重要的的业务逻辑处理完成,在理想的情况下,info的日志要让高级用户和系统管理员理解,并从日志信息中可以知道系统当前的运行状态,比如对于一个机票预定系统来说,当一个用户完成了预定操作之后给与提示谁定了从A到B的机票。另一个就是一个操作系统引起了系统状态的重大改变。比如数据库的更新

DEBUF:主要给开发人员看

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值