消费放基于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:主要给开发人员看