一:Zuul介绍
Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
# 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求
# 审查与监控:
# 动态路由:动态将请求路由到不同后端集群
# 压力测试:逐渐增加指向集群的流量,以了解性能
# 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
# 静态响应处理:边缘位置进行响应,避免转发到内部集群
# 多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使用多样化
二:创建Zuul模块
我们基于上一篇的工程,在RediaMallCloud中新增一个模块Mall_ZuulCenter,新增的步骤请参考《Sping Boot多模块项目的创建和配置》。其中要注意的是我们在建立新模块其中一个勾选zuul网关依赖。
新建完成之后,我们得修改父工程的pom和子工程的pom文件
父工程里面的module变成了四个
<!--在父pom文件当中添加模块的名称,子模块pom中<name>标签当中的值--><modules><module>Mall_EurekaCenter</module><module>Mall_ManagerService</module><module>Mall_WechatService</module><module>Mall_ZuulCenter</module></modules>
zuul新模块的pom文件如下:
<?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.smartisan</groupId><artifactId>mallzuulcenter</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>Mall_ZuulCenter</name><description>Demo project for Spring Boot</description><!-- 把原有的parent的信息注释掉,继承我们的父工程--><parent><!--<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.3.RELEASE</version><relativePath/>--> <!-- lookup parent from repository --><groupId>com.smartisan</groupId><artifactId>RediaMallCloud</artifactId><version>0.0.1-SNAPSHOT</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- JSON Configuration --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.6</version></dependency><!--标签友好化--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>net.sourceforge.nekohtml</groupId><artifactId>nekohtml</artifactId><version>1.9.22</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>、
配置:application.yml文件
eureka:client:serviceUrl:defaultZone: http://admin:password@localhost:8761/eureka/
spring:application:name: zuul_centercloud:loadbalancer:retry:enabled: truethymeleaf:mode: LEGACYHTML5cache: falsehttp:encoding:charset: UTF-8force: trueenabled: trueserver:port: 8050tomcat:uri-encoding: UTF-8zuul:
# max:
# host:
# connections: 500host:socket-timeout-millis: 180000connect-timeout-millis: 180000routes:mall-wechatservice:path: /wechat/**sensitiveHeaders:mall-managerservice:path: /manager/**sensitiveHeaders:
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 180000
ribbon:ConnectTimeout: 60000ReadTimeout: 60000MaxAutoRetriesNextServer: 0MaxAutoRetries: 1
在zuul主类上加上注解:@EnableZuulProxy,开启zuul的功能。@EnableEurekaClient注解向注册中心注册。
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
@EnableZuulProxy
public class MallZuulCenterApplication {public static void main(String[] args) {SpringApplication.run(MallZuulCenterApplication.class, args);}
}
我们分别在mall-wechatservice和mall-managerservice编写两个接口对外提供服务。
mall-managerservice:
@Controller
public class ManagerController {private final Logger logger= LoggerFactory.getLogger(this.getClass());@Value("${server.port}")String port;//get请求@ResponseBody@RequestMapping("/helloA")public String sayHelloA(){Map<String,Object> map = new HashMap<String,Object>();map.put("name","king james");map.put("age",33);map.put("team","Cleveland Cavaliers");map.put("port",port);logger.info(JSON.toJSONString(map));return JSON.toJSONString(map);}}
@Controller
public class WechatController {private final Logger logger= LoggerFactory.getLogger(this.getClass());@Value("${server.port}")String port;//get请求@ResponseBody@RequestMapping("/helloA")public String sayHelloA(){Map<String,Object> map = new HashMap<String,Object>();map.put("name","kobe");map.put("age",36);map.put("team","Los Lakers");map.put("port",port);logger.info(JSON.toJSONString(map));return JSON.toJSONString(map);}}
现在整个工程目录如下:
启动顺序:先启动Mall_EurekaCenter,再启动Mall_ZuulCenter,然后再启动Mall_ManagerService/Mall_WechatService
分别请求http://localhost:8050/manager/helloA和http://localhost:8050/wechat/helloA,页面显示如下:
说明Zuul服务网关已经能够正确的路由到我们的微服务上面去了。
三:zuul服务过滤
编写服务过滤器
@Component
public class MyZuulFilter extends ZuulFilter {private final Logger logger= LoggerFactory.getLogger(this.getClass());/*** 前置过滤器。* 但是在 zuul 中定义了四种不同生命周期的过滤器类型:* 1、pre:可以在请求被路由之前调用;* 2、route:在路由请求时候被调用;* 3、post:在route和error过滤器之后被调用;* 4、error:处理请求时发生错误时被调用;*/@Overridepublic String filterType() {return "pre";}/*** 过滤的优先级,数字越大,优先级越低。*/@Overridepublic int filterOrder() {return 0;}/*** 是否执行该过滤器。* true:说明需要过滤;* false:说明不要过滤;*/@Overridepublic boolean shouldFilter() {return true;}/*** 过滤器的具体逻辑。*/@Overridepublic Object run() throws ZuulException {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();logger.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));Object accessToken = request.getParameter("token");if(accessToken == null) {logger.warn("token is empty");ctx.setSendZuulResponse(false);ctx.setResponseStatusCode(401);try {ctx.getResponse().getWriter().write("token is empty");}catch (Exception e){}return null;}logger.info("ok");return null;}
}
再次访问http://localhost:8050/manager/helloA,页面显示如下:已经能够正确的过滤信息了。