Spring Cloud (三) zuul 动态路由+过滤器

**

Spring Cloud (三) zuul 动态路由+过滤器

**
路由在微服务体系结构的一个组成部分。例如,/可以映射到您的Web应用程序,/api/users映射到用户服务,并将/api/shop映射到商店服务。Zuul是Netflix的基于JVM的路由器和服务器端负载均衡器。

Netflix使用Zuul进行以下操作:

认证
洞察
压力测试
金丝雀测试
动态路由
服务迁移
负载脱落
安全
静态响应处理
主动/主动流量管理

在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。
在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Ngnix),再到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群(eureka, consul),服务的所有的配置文件由配置服务管理,配置服务的配置文件放在git仓库,方便开发人员随时改配置。

**

zuul实现动态路由+过滤拦截

**

1. 创建注册中心 cloud-server
创建spring boot项目cloud-server
(1. pom.xml文件依赖

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</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-devtools</artifactId>
		<scope>runtime</scope>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

(2. application.yml文件配置

#配置服务端的端口号
server:
  port: 7771 

#eureka本身即是服务端又是客户端,只做服务需要把科户端关掉
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
#配置注册中心的注册地址
    service-url: 
        defaultZone: http://localhost:7771/eureka
#应用名称
spring:
  application:
    name: server

(3. 启动类添加注解

@SpringBootApplication
@EnableEurekaServer
public class CloudServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(CloudServerApplication.class, args);
	}
}

(4. 启动项目,浏览器访问 http://localhost:7771/ 看到如下界面
在这里插入图片描述
2. 创建服务提供者 cloud-service-provider1、cloud-service-provider2
创建spring boot项目cloud-service-provider1
(1. pom.xml依赖

<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<scope>runtime</scope>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

(2. application.yml配置

#配置端口号
server:
  port: 8771
#引入注册中心
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7771/eureka

#配置应用名称
spring:
  application:
    name: provider

(3. 启动类配置注解

@SpringBootApplication
@EnableEurekaClient
public class CloudServiceProviderApplication {
	public static void main(String[] args) {
		SpringApplication.run(CloudServiceProviderApplication.class, args);
	}
}    

(4. 创建Controller层

package org.lhj.pro.controller;

import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.lhj.pro.service.ProviderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProviderController {

@Autowired
private ProviderService aservice;

@RequestMapping("/hellofeign")
public String sayHello(HttpServletRequest request) {
	String uri = request.getRequestURI();
	int port = request.getLocalPort();
	String ip = request.getRemoteAddr();
	return aservice.hello() + ip + ":" + port + uri;
}
}

(5. 创建Service层和实现类
service接口

package org.lhj.pro.service;

public interface ProviderService {
    String hello();
}

service实现类

package org.lhj.pro.service;

import org.springframework.stereotype.Service;

@Service
public class ProviderServiceImpl implements ProviderService{

@Override
public String hello() {
	return "feign跑通了";
}
}

3. 将创建的项目cloud-service-provider1复制一份,修改项目名称为cloud-service-provider2
并且将application.yml的端口号改为8772,应用名称不用改,和provider1项目的一样即可。
启动注册中心cloud-server和两个服务提供者cloud-service-provider1、cloud-service-provider2,会发现 注册中心多了一个应用,并且有两个服务可用8771和8772
在这里插入图片描述
4. 创建项目cloud-consumer-zuul
(1. 导入pom.xml文件依赖 (注意spring boot的版本要和zuul的版本一致才兼容,不然会报错)

dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.3.5.RELEASE</version>
    </dependency>
  <!--   导入zuul的依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
        <version>1.3.5.RELEASE</version>
    </dependency>

(2. 配置yml文件

#定义端口号和服务名称
server:
  port: 6771
spring:
  application:
    name: service-zuul
#zuul的相关配置
zuul:
  routes:
#标识你服务的名字,可以自己定义,一般方便和规范来讲和自己应用的名称一样
    myzuul:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不暴露你机器的IP,面向服务的路由了,给你选一个可用的出来。
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
      path: /provider/**
#这里一定要是服务提供者名称,所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,纳闷就必须写自己机器的Ip了
      service-id: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7771/eureka

(3. 启动类添加注解

package org.lhj.pro;

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
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

(4. 配置过滤器

package org.lhj.pro.filter;

import com.netflix.zuul.ZuulFilter;  
import com.netflix.zuul.context.RequestContext;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * Created by lhj on 2019/11/01.
 */
@Component
public class TokenFilter extends ZuulFilter {
	private static Logger log = LoggerFactory.getLogger(ZuulFilter.class);
	
    //四种类型:pre,routing,error,post
    //pre:主要用在路由映射的阶段是寻找路由映射表的
    //routing:具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用
    //error:一旦前面的过滤器出错了,会调用error过滤器。
    //post:当routing,error运行完后才会调用该过滤器,是在最后阶段的
    @Override
    public String filterType() {
        return "pre";
    }

    //自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行
    @Override
    public int filterOrder() {
        return 0;
    }

    //控制过滤器生效不生效,可以在里面写一串逻辑来控制
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //执行过滤逻辑
    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        log.info("{} >>> {}", request.getMethod(), request.getRequestURL().toString());
        
        String token = request.getParameter("token");
        if (StringUtils.isBlank(token) ){
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(401);
            context.setResponseBody("You request is unAuthrized,please remark your token !");
            return null;
        }else {
			log.info("the request {} is ok", request.getRequestURL().toString());
		}
        return null;
    }
}

启动注册中心、服务提供者(2个)和当前项目cloud-consumer-zuul,登录注册中心,页面如下
在这里插入图片描述
请求cloud-consumer-zuul 中application.yml配置的路径

  1. 不带token响应页面如下

在这里插入图片描述
2. 带token响应页面如下(重复刷新发现同时实现了负载均衡)
在这里插入图片描述
在这里插入图片描述
到此为止zuul的动态路由和过滤拦截就实现了。

发布了68 篇原创文章 · 获赞 5 · 访问量 9837

猜你喜欢

转载自blog.csdn.net/weixin_44407691/article/details/102852107