欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringCloud分布式微服务搭建(二)

程序员文章站 2022-04-28 15:13:18
这个例子主要是将zuul和eureka结合起来使用,zuul作为反向代理,同时起到负载均衡的作用,同时网关后面的消费者也作为服务提供者,同时提供负载均衡。 ......

这个例子主要是将zuul和eureka结合起来使用,zuul作为反向代理,同时起到负载均衡的作用,同时网关后面的消费者也作为服务提供者,同时提供负载均衡。

一.api网关(摘自百度)

api网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。api网关封装了系统内部架构,为每个客户端提供一个定制的api。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
api网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供rest/http的访问api。服务端通过api-gw注册和管理服务。

二. 整体架构

SpringCloud分布式微服务搭建(二)

 

    (1)http://localhost:40000/provider/hello?name=ljq3经过zuul网关之后,由于zuul对路径映射

zuul.routes.api-a.path=/provider/**
zuul.routes.api-a.serviceid=ribbon-consumer
(2)把provider映射到ribbon-cunsumer这个服务上,zuul利用负载均衡的方式选一个服务地址,然后将路径替换,得到
http://localhost:40001/hello?name=ljq3
(3)ribbon-consummer再利用ribbon负载均衡选择一个provider,但是因为我在代码中只把地址传递,而没有传递参数,所以得到的url是
http://localhost:20003/

(4)github地址:https://github.com/linjiaqin/scdemo

三. zuul代码结构

这里把zuul的服务作为一个服务提供者去注册到eureka中,要使用这个注解表名是一个服务提供者@enableeurekaclient

1.引导类

package com.ljq;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
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;
import org.springframework.context.annotation.bean;

@enablezuulproxy
@springbootapplication
@enableeurekaclient
//把zuul作为服务提供者到eureka注册
public class gatewayapplication {

private static final logger logger = loggerfactory.getlogger(gatewayapplication.class);
gatewayapplication(){
logger.info("app init");
}
public static void main(string[] args) {
logger.info("app start");
springapplication.run(gatewayapplication.class, args);
}

}

2.配置文件

这里把的路径匹配规则是当访问的符合provider这个路径时,自动映射到serviceid上,去eureka找到serviceid的所有可用地址,负载均衡选取一个后替换成这个地址

spring.application.name=gateway-service-zuul
server.port=40000
eureka.client.serviceurl.defaultzone=http://mu01:8761/eureka,http://cu01:8762/eureka,http://cu02:8763/eureka
zuul.routes.api-a.path=/provider/**
zuul.routes.api-a.serviceid=eureka-client-service-provider

3. beanconfig

package com.ljq;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.stereotype.service;

@service
public class mybaenconfig {
    private static final logger logger = loggerfactory.getlogger(mybaenconfig.class);
    mybaenconfig(){
        logger.info("service init");
    }
    @bean
    public myfilter myfilter() {
        logger.info("bean init");
        return new myfilter();
    }
}

 

4. zuul的核心filter类,用来过滤请求

package com.ljq;


import com.netflix.zuul.zuulfilter;
import com.netflix.zuul.context.requestcontext;
import org.apache.commons.lang.stringutils;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import javax.servlet.http.httpservletrequest;

public class myfilter extends zuulfilter {

    private final logger logger = loggerfactory.getlogger(myfilter.class);

    myfilter(){
        logger.info("filter init");
    }
    @override
    public string filtertype() {
        return "pre"; // 可以在请求被路由之前调用
    }

    @override
    public int filterorder() {
        return 0; // filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低
    }

    @override
    public boolean shouldfilter() {
        return true;// 是否执行该过滤器,此处为true,说明需要过滤
    }

    @override
    public object run() {
        requestcontext ctx = requestcontext.getcurrentcontext();
        httpservletrequest request = ctx.getrequest();

        logger.info("--->>> myfilter {},{}", request.getmethod(), request.getrequesturl().tostring());

        string token = request.getparameter("name");// 获取请求的参数

        if (stringutils.isnotblank(token)) {
            ctx.setsendzuulresponse(true); //对请求进行路由
            ctx.setresponsestatuscode(200);
            ctx.set("issuccess", true);
            return null;
        } else {
            ctx.setsendzuulresponse(false); //不对其进行路由
            ctx.setresponsestatuscode(400);
            ctx.setresponsebody("parameter name is empty");
            ctx.set("issuccess", false);
            return null;
        }
    }

}

 

5.mvn spring-boot:run起来之后,就可以看到网关服务在eureka上注册了

curl http://localhost:40000/provider  可以看到负载均衡的效果

SpringCloud分布式微服务搭建(二)

 

6.网关的默认路由规则

但是如果后端服务多达十几个的时候,每一个都这样配置也挺麻烦的,spring cloud zuul已经帮我们做了默认配置。

默认情况下,zuul会代理所有注册到eureka server的微服务,

并且zuul的路由规则如下:http://zuul_host:zuul_port/微服务在eureka上的serviceid/**会被转发到serviceid对应的微服务。

 

二 .ribbon consumer

这里的consummer不仅是服务消费者去后面拿取provider的内容,同时也作为一个服务提供者对外提供服务

1.引导类

@springbootapplication
@enablediscoveryclient
@enableeurekaclient
public class consumerapplication {

    public static void main(string[] args) {
        springapplication.run(consumerapplication.class, args);
    }

}

2.beanconfig类

package com.ljq;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.cloud.client.loadbalancer.loadbalanced;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.web.client.resttemplate;

@configuration
public class ljqconfig {
    private static final logger logger = loggerfactory.getlogger(ljqconfig.class);
    ljqconfig(){
        logger.info("config init");
    }
    @bean
    @loadbalanced
    public resttemplate resttemplate(){
        logger.info("resttemplate function");
        return new resttemplate();
    }
}

3.controller

package com.ljq;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;
import org.springframework.web.client.resttemplate;

import javax.servlet.http.httpservletrequest;

@restcontroller
public class ljqcontroller {
    private static final logger logger = loggerfactory.getlogger(ljqcontroller.class);
    ljqcontroller(){
        logger.info("controller init");
    }
    @autowired
    private resttemplate resttemplate;

    //这里不写eureka的注册中心,而是写服务提供者的应用名
    @getmapping(value = "/hello")
    public string hello(httpservletrequest request){
        logger.info("hello function");
        logger.info(request.getpathinfo());
        logger.info("--->>> consumer contorller {},{}", request.getmethod(), request.getrequesturl().tostring());

        string token = request.getparameter("name");// 获取请求的参数
        logger.info(token);

        return resttemplate.getforentity("http://eureka-client-service-provider/", string.class).getbody();
    }
}

配置与上篇文章一致

spring.application.name=ribbon-consumer
server.port=30001
eureka.client.serviceurl.defaultzone=http://mu01:8761/eureka,http://cu01:8762/eureka,http://cu02:8763/eureka

 

 springboot的执行顺序

注解

三. provider

代码与上篇文章基本一直

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.value;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;

import javax.servlet.http.httpservletrequest;

@restcontroller
public class ljqcontroller {
    private final logger logger = loggerfactory.getlogger(ljqcontroller.class);
    @value("${server.port}")
    string port;

    @requestmapping("/")
    public string home(httpservletrequest request){
        logger.info(request.getpathinfo());
        logger.info("--->>> consumer contorller {},{}", request.getmethod(), request.getrequesturl().tostring());

        string token = request.getparameter("name");// 获取请求的参数
        logger.info(token);
        return "hello world, port is:" + port;
    }
}

 

一键启动脚本

#首先开启eureka,上篇文章中我们把eureka放在集群上,并单独写了一个脚本了,这里不在赘述
#然后开启zuul
cd /home/linjiaqin/log_stream_platform/source/scdemo/gateway;
nohup mvn spring-boot:run > /dev/null 2>&1  &
#开两个ribbon-consumer
cd /home/linjiaqin/log_stream_platform/source/scdemo/consumer
nohup mvn spring-boot:run -dserver.port=30001 > /dev/null 2>&1  &
nohup mvn spring-boot:run -dserver.port=30002 > /dev/null 2>&1  &
#开启三个provider
cd /home/linjiaqin/log_stream_platform/source/scdemo/provider
nohup mvn spring-boot:run -dserver.port=20001 > /dev/null 2>&1  &
nohup mvn spring-boot:run -dserver.port=20002 > /dev/null 2>&1  &
nohup mvn spring-boot:run -dserver.port=20003 > /dev/null 2>&1  &

  

测试结果

linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq2
hello world, port is:20003
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq3 hello world, port is:20003
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq4 hello world, port is:20003
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq5 hello world, port is:20002
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq6 hello world, port is:20002