在之前我们进行远程服务调用是使用的Spring提供的RestTemplate进行调用,虽然也完成了功能,但是写法是非常不优雅的,还需要进行拼接字符串来进行参数传递。为了解决这个问题,引入SrpingCloud的组件Feign。
Feign简介:
Feign可以把Rest请求进行伪装,伪装成类似于SpringMVC的Controller一样。你不用再自己去拼接url、拼接参数等操作,一切都交给Feign去做。
Feign是Netflix开发的声明式、模板化的HTTP客户端,Feign可以帮助我们更加便捷、优雅的调用HTTP API。
在SpringCloud中,使用Feign非常简单:创建一个接口,并且在接口上添加一些注解,代码就完成了。
SpringCloud对Feign进行了增强,使Feign支持了SpringMVC的注解,并整合了Ribbon、Eureka和Hystrix,从而让Feign的使用更加方便。
改良入门程序,使用Feign进行远程调用:
1、添加Feign的启动器:
<!--引入Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、在引导类上添加注解启用Feign:
3、创建UserClient接口,使用UserClient接口进行远程连接:
package com.xsh.consumer.client;
import com.xsh.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient("SERVICE-PRODUCER")
public interface UserClient {
@RequestMapping("user/findByid/{uid}")
public User findByid(@PathVariable Integer uid);
}
@FeignClient注解:注解的参数是你需要远程连接的服务名
接口内的方法是你需要远程连接的服务提供方的方法,方法必须保持一直,并且访问路径也要一致。
4、在服务消费方使用UserClient进行远程调用:
package com.xsh.consumer.controller;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.xsh.consumer.client.UserClient;
import com.xsh.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/consumer/user")
public class UserController {
@Autowired
private UserClient userClient;
@RequestMapping("/{uid}")
@HystrixCommand
public String findByid(@PathVariable Integer uid){
return userClient.findByid(uid).toString();
}
}
直接注入UserClient,然后使用其中的接口方法即可实现远程连接。
使用Feign开启Hystrix熔断器:
Feign默认情况下是集成了Hystrix的,但是是不开启的,所以我们首先要在配置文件中覆盖默认配置来开启Hystrix。
1、开启Hystrix:
feign:
hystrix:
enabled: true #开启Hystrix
2、创建UserClient的实现类,编写熔断方法
package com.xsh.consumer.client;
import com.xsh.consumer.pojo.User;
import org.springframework.stereotype.Component;
@Component
public class UserClientImpl implements UserClient {
@Override
public User findByid(Integer uid) {
User user=new User();
user.setUname("服务器正忙!");
return user;
}
}
实现类实现UserClient接口方法,实现方法就是熔断方法,返回提示信息,然后该实现类要使用注解交由Spring容器来管理。
3、将实现类通过@FeignClient注解的参数绑定打Hystrix中:
package com.xsh.consumer.client;
import com.xsh.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "SERVICE-PRODUCER",fallback = UserClientImpl.class)
public interface UserClient {
@RequestMapping("user/findByid/{uid}")
public User findByid(@PathVariable Integer uid);
}
至此,就可以实现使用Feign开启Hystrix进行熔断。
服务网关Zuul简介:
服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外提供Rest API的过程中,除了具备服务器路由、负载均衡功能之外,它还具备了权限控制等功能。
SpringCloud中的Zuul就担任了这样一个角色,为微服务架构提供前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,是的服务集群主体能够具备更高的可复用性和可测试性。
Zuul是Netflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用。
Zuul核心是一系列的过滤器,这些过滤器可以完成以下功能:
- 身份认证与安全:识别每个资源的验证请求,并拒绝那些与要求不符的请求。
- 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
- 动态路由:动态的将请求路由到不同的后端集群。
- 压力测试:逐渐增加指向集群的流量,以了解性能。
- 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
- 静态响应处理:在边缘位置直接建立部分响应,从而避免转发到内部集群。
- 多区域弹性
加入Zuul网关之后的微服务架构:
不管是来自客户端的请求,还是内部服务调用,一切服务的请求都会经过Zuul这个网关,然后再由网关来实现鉴权、动态路由等等操作,Zuul就是我们服务的唯一入口。
入门案例:通过Zuul网关路由到服务提供方
1、创建module
2、修改pom.xml文件,引入启动器
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xsh</groupId>
<artifactId>service-zuul</artifactId>
<version>1.0-SNAPSHOT</version>
<!--定义SpringCloud的版本号-->
<properties>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
<!--统一管理SpringCloud版本号-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3、覆盖默认配置
server:
port: 10010
spring:
application:
name: service-zuul
4、在引导类上添加注解启用Zuul
package com.xsh.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringCloudApplication
@EnableZuulProxy //启用Zuul网管组件
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
5、配置路由转发到服务提供方
zuul:
routes:
service-producer: #路由名称,自定义,一般以服务名称
path: /service-producer/**
url: http://localhost:8081
配置完成之后通过http://localhost:10010/service-producer/user/findByid/1该路径就可以访问到服务提供方的接口。
我们是通过配置的路由访问Zuul网关,然后由网关转发到服务提供方接口的。
Zuul网关的四种路由配置方式:
在入门案例中,使用的是第一种配置方式,通过自定义的名称转发到固定服务提供方的接口。
**第二种配置方式:**引入Eureka,通过服务id拉取服务列表进行转发,并且可以进行负载均衡
zuul:
routes:
service-producer: #路由名称,自定义,一般以服务名称
path: /service-producer/**
#url: http://localhost:8081
serviceId: SERVICE-PRODUCER
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
这种配置方式是通过Eureka拉取服务列表来进行转发的,所以还需要在Zuul的module中引入Eureka。
**第三种配置方式:**相当于第二种配置方式的简化
zuul:
routes:
service-producer: /service-producer/** #路由名称,自定义,一般以服务名称
#path: /service-producer/**
#url: http://localhost:8081
#serviceId: SERVICE-PRODUCER
第四种配置方式: 其实也可以不配,Zuul默认会通过服务id进行拉取转发,不过通常还是采用第三种方式进行简单的灵活设置。
路由前缀配置:
zuul:
routes:
service-producer: /service-producer
prefix: /api
通过zuul.perfix属性可以配置路由的前缀,配置了路由前缀之后,访问路由必须加上对应的前缀才可以访问。
Zuul过滤器:
Zuul作为网关的其中一个重要功能,就是实现请求的鉴权,而这个动作我们通常是通过Zuul提供的过滤器来实现的。
1、IZuulFilter接口和ZuulFilter实现类
IZuulFilter是Zuul网关过滤器的最顶层接口,ZuulFiter是IZuulFilter的抽象实现类。
ZuulFilter的具体方法说明:
public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType();
abstract public int filterOrder();
boolean shouldFilter(); //继承自IZuulFilter
Object run() throws ZuulException; //继承自IZuulFilter
}
shouldFilter():方法返回一个布尔值,判断该过滤器的逻辑代码是否需要执行,返回true则执行,false则不执行。
run():过滤器的业务逻辑代码。
filterType():返回字符串,代表过滤器的类型。包含如下四种:
- pre:请求在被路由之前执行;
- route:在请求被路由时执行;
- post:在route和error过滤器之后执行;
- error:处理请求发生错误时执行。
filterOrder():通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
2、过滤器执行生命周期