上一节我们使用了ribbon(基于http/tcp)进行微服务的调用,ribbon的调用比较简单,通过ribbon组件对请求的服务进行拦截,通过eureka server 获取到服务实例的ip:port,然后再去调用api。本节课我们使用更简单的方式来实现,使用声明式的web服务客户端feign,我们只需要使用feign来声明接口,利用注解来进行配置就可以使用了,是不是很简单?实际工作中,我们也只会用到feign来进行服务之间的调用(大多数)。接下来,我们来实例操作一把。
为了代码的重用性,我们来创建一个新的project mscx-ad-feign-sdk作为feign的服务调用工具。
创建项目mscx-ad-feign-sdk
三部曲之step 1(加依赖)
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
mscx-ad
com.sxzhongf
1.0-snapshot
4.0.0
jar
mscx-ad-feign-sdk
只定义微服务feign调用用到的请求对象和响应对象,而不涉及具体的实现类。
com.sxzhongf
mscx-ad-feign-sdk
1.0-snapshot
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-openfeign
com.sxzhongf
mscx-ad-common
1.0-snapshot
org.springframework.cloud
spring-cloud-starter-hystrix
1.2.7.release
org.springframework.boot
spring-boot-maven-plugin
三部曲之step 2(加注解@enablefeignclients,添加在具体的微服务中,使用我们自定义的feignclient)
/**
* isponsorfeignclient for service using
*
* @author isaac.zhang | 若初
*/
@feignclient(value = "mscx-ad-sponsor", fallback = sponsorclienthystrix.class)
public interface isponsorfeignclient {
@requestmapping(value = "/ad-sponsor/plan/get", method = requestmethod.post)
commonresponse> getadplansusefeign(@requestbody adplangetrequestvo requestvo);
@requestmapping(value = "/ad-sponsor/user/get", method = requestmethod.get)
/**
* feign 埋坑之 如果是get请求,必须在所有参数前添加{@link requestparam},不能使用{@link param}
* 会被自动转发为post请求。
*/
commonresponse getusers(@requestparam(value = "username") string username);
}
---
@restcontroller
@slf4j
@requestmapping(path = "/search-feign")
public class searchfeigncontroller {
/**
* 注入我们自定义的feignclient
*/
private final isponsorfeignclient sponsorfeignclient;
@autowired
public searchfeigncontroller(isponsorfeignclient sponsorfeignclient) {
this.sponsorfeignclient = sponsorfeignclient;
}
@getmapping(path = "/user/get")
public commonresponse getusers(@param(value = "username") string username) {
log.info("ad-search::getusersfeign -> {}", json.tojsonstring(username));
commonresponse commonresponse = sponsorfeignclient.getusers(username);
return commonresponse;
}
}
三部曲之step 3(加配置,工具类库不需要,添加在具体的微服务中)
我们上面的实例中有一个问题,如果说我们的广告提供服务出现了问题,那么我们通过使用feignclient 调用的apisponsorfeignclient.getusers(username);就会报错,如果长时间报错,会引起大规模的服务错误问题,也就有是我们常说的服务雪崩效应,我们要怎样避免一个服务出错而拖垮整个系统的问题呢?这里我们需要引入一个组件hystrix来处理服务错误。
三部曲之step1(加依赖)
从上图我们可以看到,我们引入feign依赖的时候,它本身已经依赖了hystrix,根据maven依赖的传递性,我们可以知道我们自己的服务已经包含了hystrix的依赖支持,我们可以直接使用了~
三部曲之step2(加注解) @enablehystrix // 开启hystrix 断路器
三部曲之step3(改配置)
feign:
hystrix:
enabled: true
使用hystrix来配置feign实现调用容错
@component
public class sponsorclienthystrix implements isponsorfeignclient {
@override
public commonresponse> getadplansusefeign(adplangetrequestvo requestvo) {
return new commonresponse<>(-1, "mscx-ad-sponsor feign & hystrix get plan error.");
}
@override
public commonresponse getusers(string username) {
return new commonresponse<>(-1, "mscx-ad-sponsor feign & hystrix get user error.");
}
}
在isponsorfeignclient类中,添加出错处理类(fallback)
@feignclient(value = "mscx-ad-sponsor", fallback = sponsorclienthystrix.class)
public interface isponsorfeignclient {
...
在sponsorclienthystrix中,我们要特别注意2点
该类必须添加@component注解,以便可以加入spring 容器中
该类需要实现isponsorfeignclientfeign的客户端接口
通过上面的实现,我们的服务在调用过程中,如果发生错误,就会进行服务降级,调用到出错应该调用的默认处理类中的方法,也就实现了我们想要做的短路处理来保护我们的当前服务。