SpringCloud——Ribbon和Feign负载均衡、远程调用、熔断
一、Ribbon负载均衡、RPC远程调用——//访问地址:localhost:8001/mm
1、依赖环境
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、在启动类中创建ribbon对象
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
3、在client01中的controller类中代码(client01中调用client02中的服务)
//导入ribbon的bean对象;
@RestController
public class DogController{
@Autowired
private RestTemplate restTemplate;
//这里的请求类型没有要求(@RequestMapping、@GetMapping、@PostMapping);
//注意:通过ribbon方式访问client02的方式时,client02中的请求方式必须是@RequestMapping或@GetMapping方式才行;
@PostMapping("/mm")
public String mm(){
//参数1:Url字符串地址(client02:需要调用的服务的服务名称:——spring.application.name=client02);
//参数2:RPC远程调用服务的返回值的类型;
String mm = restTemplate.getForObject("http://client02:8002/smallCat",String.class);
return mm;
}
}
4、client02中的代码
@RestController
public class CatController {
// @GetMapping("smallCat")
@RequestMapping("smallCat")
public String mm(){
return "获取一致小猫咪!___point:8002";
}
}
二、Feign负载均衡、RPC远程调用——//访问地址:localhost:8001/mm
1、依赖环境
//Feign依赖配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
//如果没有这个依赖项目启动会报错(找不到bean),这个是web项目需要的依赖(非Feign所必须依赖)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、创建Feign接口文件
①接口文件在本地项目中
②接口文件在一个其他的项目中(如工具Commen项目中,或者是一个单独的feign服务器中)
2、1、Feign接口代码:
不论Feign接口文件在多少层目录中,容器都能自动扫描到该接口(前提是启动类中有指定Feign接口文件位置)
package dog.feign;或package dog.feign.a.b.c.feign;
//value:用来指定要远程调用哪个服务提供者的服务名称;
@FeignClient(value = "client02")
public interface ToFeign {
//下面的请求路径和方法mm就是要进行远程调用的路径和方法;
//注意:通过Feign接口方式访问client02的方式时,client02中的请求方式与Feign中的请求方式必须相同;
//(或者使用通用类型:@RequestMapping,但是此种混合用法有时候会出现"Request method 'GET' not supported"问题),之后呢在详细研究TODO;
//注意:请求路径、请求类型、方法名称,要与实际服务提供者中的一模一样
//只是这里是在接口中,方法没有方法体;
@RequestMapping("smallCat")
//无参方法
public String mm();
//如果是有参方法,则在传递参数是接口文件中必须使用@RequestParam()来指定参数,否则参数传不过去;
public String eat(@RequestParam("food")String food);
}
===========重点所在========
2、2、在client01中启动类代码
①Feign接口在本地项目中
-------@EnableFeignClients
//如果Feign接口在本地项目中,则直接使用@EnableFeignClients就可以,而不需要专门指定Feign接口的包路径
//如果手动指定了,就会按照指定地址去查找,如果找不到会报异常;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class StartClient01 {
public static void main(String[] args) {
SpringApplication.run(StartClient01.class,args);
System.out.println("客户端01启动!");
}
}
②Feign接口文件在其他的项目中
重点:::#如果在其他项目中,首先本项目应该引入其他项目的依赖到pom文件中,然后才能通过basePackages来指定feign接口的位置
---- @EnableFeignClients(basePackages = "com.dog.feign")
//如果Feign接口文件在其他的项目中,
//则必须手动指定Feign接口文件的包路径:@EnableFeignClients(basePackages = "com.dog.feign")
//如果不指定会报异常!
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.dog.feign")
public class StartClient01 {
public static void main(String[] args) {
SpringApplication.run(StartClient01.class,args);
System.out.println("客户端01启动!");
}
}
重要:::: 如果是在其他项目中(例如:单独的feign服务器中),还可以添加一个FeignController类,添加@RestController,变成一个对外入口, 该入口中引入feign接口,通过feign接口 通过自定义路径访问该入口中的方法,来调用feign中的方法,进而调用到feign来实现远程调用和负载均衡功能;
(消费端的controller类中可以直接注入feign接口来使用,也可以注入feign中的controller类来使用)
还有:如果feign接口是在feign服务中,那么gaifeign服务的启动类中不能使用@EnableFeignClients注解,否则会造成引用feign就接口的消费者服务无法启动
会报出:The bean 'ayayou-AAAA.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.
以上问题报错的意思是一个项目中存在多个接口使用@FeignClient调用同一个服务,意思是说一个服务只能用@FeignClient使用一次。
2、3、在client01中的controller类中代码
@RestController
public class DogController{
@Autowired
private ToFeign toFeign;
@PostMapping("/mm")
public String mm(){
String mm = toFeign.mm();
return mm;
}
}
2、4、client02中的代码
@RestController
public class CatController {
// @GetMapping("smallCat")
@RequestMapping("smallCat")
public String mm(){
return "获取一致小猫咪!___point:8002";
}
}
总结: ①Feign接口文件中的请求类型最好与远程服务中的请求类型相同; ②远程调用有参方法时,Feign接口文件中方法的参数必须使用@RequestParam()来指定参数,否则参数传不过去; ②客户端请求类型为post时,请求方法体中只能有一个参数(或者变量),否则会报异常; ③请求类型为get时可以有多个参数;
三、Hystrix熔断器简单使用(Hystrix和Feign一同使用)
1、引入依赖
因为Feign已经集成了Hystrix,所以不需要在单独添加Hystrix依赖;(前提是有Feign依赖)
2、添加配置
# 启用feign(系统默认关闭)
#注意:如果Hystrix在类路径下(Feign接口文件与调用者在相同项目中————在同一个Module中),
#则系统默认启用(此时配置文件中可以省略feign的配置)
#个人理解:只要Hystrix的类在--启动类--的下级目录中,则系统都会默认开启
###同样:如果Hystrix不在类路径下(Feign接口文件与调用者在不同项目中————分别在两个Module中),
#####则系统默认关闭(此时配置文件中需要手动配置feign开启)
#如果要禁用Feign的Hystrix支持,则需要在配置文件中设置feign.hystrix.enabled=false
该配置的位置是:需要进行服务调用的消费者的配置文件中进行配置开启或关闭(feign服务器中可以不用配置);
例如:
a要通过feign调用b,则,开启配置需要配置在阿德配置文件中
feign:
hystrix:
enabled: true
#一般情况下,开启配置的代码都可以省略不写
3、添加对Feign的支持
在启动类中添加注解@EnableFeignClients,以支持Feign来调用服务;
#注意:这里一定不要添加 @EnableHystrix这个注解,否则会报异常(待研究);
4、实现回调类(熔断后要执行的类)
创建一个继承与Feign接口文件ToFeign的实现类——ToFeignImpl类,重写方法,当做回调类;
#实现类代码中需要添加——@Component注解来实现自动注册——bean
#注意:如果一个服务中有多个方法,那么feign中就同样有多个相同的方法,因此feign的实现类中就会重写多个方法;
#注意:虽然“fallback = ToFeignImpl.class”属性中只填写一个实现类的字节码对象,但是每个重写的方法会自动对应各自方法的熔断机制
#这是实现类代码:
@Component
public class ToFeignImpl implements ToFeign {
@Override
public String mm() {
return "服务器出错,这里返回的是通过熔断器实现的方法!";
}
}
5、添加fallback属性
#Feign接口类中需要添加——fallback属性,其值为实现类的字节码——ToFeignImpl.class
#这是Feign接口类代码:
@FeignClient(value = "client02",fallback = ToFeignImpl.class)
public interface ToFeign {
@RequestMapping("smallCat")
public String mm();
}
6、测试
①服务都启动
#输出:————获取一致小猫咪!___point:8002
②断掉服务提供者
#输出:————服务器出错,这里返回的是通过熔断器实现的方法!
四、额外内容:@EnableFeignClients
https://blog.csdn.net/weixin_30399871/article/details/102364012?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160255745019725222434856%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160255745019725222434856&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v28-2-102364012.pc_first_rank_v2_rank_v28&utm_term=%40EnableFeignClients%E7%9A%84%E4%BD%9C%E7%94%A8&spm=1018.2118.3001.4187
1、使用注解@EnableFeignClients启用feign客户端;
示例 :
@SpringBootApplication
@EnableFeignClients
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
2、使用注解@FeignClient 定义feign客户端 ;
示例 : 该例子定义了一个feign客户端,将远程服务http://test-service/test/echo映射为一个本地Java方法调用。
@FeignClient(name = "test-service", path = "/test")
public interface TestService {
@RequestMapping(value = "/echo", method = RequestMethod.GET)
TestModel echo(@RequestParam("parameter") String parameter);
}
3、使用注解@Autowired使用上面所定义feign的客户端 ;
@Autowired
TestService testService;
public void run(){
// 这里的使用本地Java API的方式调用远程的Restful接口
TestModel dto = testService.echo("Hello,你好!");
log.info("echo : {}", dto);
}
上面的三个步骤,前两个步骤可以理解为定义feign客户端,第三步是使用所定义的feign客户端。