微服务架构
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简单的微服务系统如下图:
在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡Ngnix
,再到达服务网关(Zuul集群
),然后再到具体的服。,服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务中心管理,配置服务的配置文件放在Git仓库,方便开发人员随时改配置。
Zuul简介
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
快速入门
创建一个model工程作为服务网关,即service-zuul
。
导入依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
使用注解@EnableZuulProxy
,开启zuul的功能:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableEurekaClient
// 开启zuul的功能
@EnableZuulProxy
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceZuulApplication.class, args);
}
}
配置文件application.yml:
server:
port: 8084
spring:
application:
name: service-zuul
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9100/eureka/
zuul:
# 定义服务转发规则
routes:
# 这个名字任意取的,建议取有意义的
api-ribbon:
# 配置请求URL的请求规则
path: /api-ribbon/**
# 真正的微服务地址,path匹配的请求都转发到这里
serviceId: eureka-ribbon-client
api-feign:
path: /api-feign/**
serviceId: eureka-feign-client
通过zuul访问服务。
服务过滤
过滤器是Zuul的重要组件。
过滤器ZuulFilter是一个抽象类,其实现类需要实现4个方法:
- filterType:返回字符串代表过滤器的类型
a)pre:请求在被路由之前执行
b)routing:在路由请求时调用
c)post:在routing和errror过滤器之后调用
d)error:处理请求时发生错误调用 - filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
- shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
- run:过滤器的具体业务逻辑。
执行流程:
需求:通过编写过滤器实现用户是否登录的检查。
实现:通过判断请求中是否有token,如果有认为就是已经登录的,如果没有就认为是非法请求,响应401。
过滤器实现:
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@Component
public class LoginZuulFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre"; // 设置过滤器类型为:pre
}
@Override
public int filterOrder() {
return 0;// 设置执行顺序为0
}
@Override
public boolean shouldFilter() {
return true; // 该过滤器需要执行
}
// //编写业务逻辑
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if (accessToken == null) {
log.warn("token is empty");
// 过滤该请求,不对其进行路由
ctx.setSendZuulResponse(false);
// 设置响应状态码
ctx.setResponseStatusCode(401);
ctx.setResponseBody(" token is empty!!");
return null;
}
log.info("ok");
return null;
}
}
不带token访问提示token不能为空:
带token正常访问:
默认开启Ribbon
Zuul网关默认开启了 Ribbon 负载均衡,当启动多个服务提供者进行测试,不断刷新浏览器请求,发现多个服务会被轮询访问。