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

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目

程序员文章站 2024-01-11 18:47:10
本章节,我们讲解springcloud重要组件:微服务网关Zuul。如果有同学从第一章看到本章的,会发现我们已经讲解了大部分微服务常用的基本组件。 已经讲解过的: 一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目 一起来学Spring Cloud | 第 ......

本章节,我们讲解springcloud重要组件:微服务网关zuul。如果有同学从第一章看到本章的,会发现我们已经讲解了大部分微服务常用的基本组件。

已经讲解过的:

一起来学spring cloud | 第一章 :如何搭建一个多模块的springcloud项目

一起来学spring cloud | 第二章:服务注册和发现组件 (eureka)

一起来学spring cloud | 第三章:服务消费者 (负载均衡ribbon)

一起来学spring cloud | 第四章:服务消费者 ( feign )

一起来学spring cloud | 第五章:熔断器 ( hystrix)

本章正在讲解的:一起来学spring cloud | 第六章:服务网关 ( zuul)

下章即将讲解的: 一起来学spring cloud | 第七章:分布式配置中心(spring cloud config)

刚入门的同学,如果把前面这七章都理解清楚,并且自己搭建一遍,在工作中,我们已经可以搭建一个最简单的微服务项目了,我曾经看过一个创业公司,他们使用微服务框架时,就用以上的组件在生产上运行着简单的后台业务系统。

一、zuul简介:

zuul是netflix开源的微服务网关,它可以和eureka、feign、hystrix等组件配合使用,zuul的核心是一系列过滤器,它主要功能是路由转发和过滤器。

在实际项目中,一个复杂的业务系统后台,少则几十个服务模块,多则成百上千,随着业务场景的不断变更,我们的系统也会不断在演变,就会遇到如下的几个问题:

1.  如果存在跨域请求,多个微服务在一定的场景下处理相对复杂。

2.  客户端多次请求不同的微服务,增加了客户端的复杂性。

3.  认证复杂,每个微服务都需要独立认证。

4.  难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个微服务合并成一个或者将一个微服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很能实施。

5.  某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定困难。

zuul提供的作用:

1. 提供统一服务入口,微服务对前台透明

2. 聚合后台服务,节省流量,提升性能

3. 安全,过滤,流控等api管理功能

4. 提供统一服务出口,解耦

二、zuul实现路由功能:

1. 在前面2章讲解的两个服务模块上,新增两个方法,模拟前端请求,做为本次zuul的测试接口
springcloud-ribbon-client模块的ribboncontroller类,增加/testzuul接口,具体模块信息参考:一起来学spring cloud | 第三章:服务消费者 (负载均衡ribbon)

package com.haly.controller;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;

import com.haly.service.ribbonservice;


@restcontroller
public class ribboncontroller {
    @autowired
    ribbonservice ribbonservice;
	
    @getmapping(value = "/gethello")
    public string gethello(@requestparam string name) {
        return ribbonservice.gethello(name);
    }
	
    @getmapping(value = "/testzuul")
    public string testzuul(@requestparam string name) {
        return name +"这是springcloud-ribbon-clientd的服务接口";
    }

}

springcloud-feign-client模块的feigncontroller类,增加/testzuul接口,具体模块信息参考:一起来学spring cloud | 第四章:服务消费者 ( feign )

package com.haly.controller;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;

import com.haly.romote.feignremoteservice;


@restcontroller
public class feigncontroller {
	
    @autowired
    feignremoteservice feignremoteservice;

    @getmapping(value = "/gethello")
    public string gethello(@requestparam string name) {
        return feignremoteservice.hello(name);
    }

    @getmapping(value = "/testzuul")
    public string testzuul(@requestparam string name) {
        return name +",这是springcloud-feign-client的服务接口";
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     

2. 新建一个新的zuul服务工程,名称为:springcloud-zuul-server

①:修改pom.xml文件,parent标签引用的是父文件,具体父文件配置,参考:一起来学spring cloud | 第一章 :如何搭建一个多模块的springcloud项目

<?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>
	<parent>
		<groupid>com.haly</groupid>
		<artifactid>springcloud</artifactid>
		<version>0.0.1-snapshot</version>
	</parent>

	<groupid>com.haly</groupid>
	<artifactid>springcloud-zuul-server</artifactid>
	<version>0.0.1-snapshot</version>
	<name>springcloud-zuul-server</name>
	<description>新建一个zuuld项目</description>

	<dependencies>
		<dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-starter-netflix-eureka-client</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>
       <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-starter-netflix-zuul</artifactid>
        </dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupid>org.springframework.boot</groupid>
				<artifactid>spring-boot-maven-plugin</artifactid>
			</plugin>
		</plugins>
	</build>
</project>

②:新增模块启动类springcloudzuulserverapplication

注解@enablezuulproxy,表示开启zuul的功能,它默认也具有@enablecircuitbreaker和@enablediscoveryclient两个注解的功能

package com.haly;

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.cloud.netflix.zuul.enablezuulproxy;

@enablezuulproxy
@springbootapplication
public class springcloudzuulserverapplication {

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

}

③:application.properties加上以下的配置代码:

server.port=9700
spring.application.name=springcloud-zuul-server
eureka.client.serviceurl.defaultzone=http://localhost:8761/eureka/

zuul.ignored-services: "*"

zuul.routes.a.path = /api/a/**
zuul.routes.a.serviceid = springcloud-feign-client

zuul.routes.b.path =  /api/b/**
zuul.routes.b.serviceid = springcloud-feign-client

先解释下配置含义

zuul.ignored-services: "*"  : 之前我们说过可以用服务名直接访问接口,如果我们不想向外界暴露除了application.properties配置映射的服务接口,配置这个属性,只能通过zuul映射的路径访问。

zuul.routes.a.path = /api/a/**
zuul.routes.a.serviceid = springcloud-feign-client

当我们访问zuul服务模块时,只要包含 /api/a/ 路径的服务请求,默认请求到springcloud-ribbon-client模块上的接口

zuul.routes.b.path =  /api/b/**
zuul.routes.b.serviceid = springcloud-feign-client

同理,当我们访问zuul服务模块时,只要包含 /api/b/ 路径的服务请求,默认请求到springcloud-feign-client模块上的接口

3. 运行项目

启动 注册中心 springcloud-eureka-server,启动springcloud-ribbon-client服务模块,启动springcloud-feign-client服务模块,启动springcloud-zuul-server模块

在这里首先我要表达歉意,在第一章搭建多模块的微服务项目时,我使用的springcloud和springboot的版本会有问题,所以本章节启动springcloud-zuul-server模块时报错,具体报错如下:

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目

原因是springboot与springcloud的版本不一致导致的,以后有同学遇到同样问题,记得将对应的版本号改成一致

在实际开发过程中,我们详细的版本对应关系:

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目

现在我们将父pom中springcloud的版本号修改为:greenwich.sr1 ,再启动springcloud-zuul-server服务模块,可以启动成功了,eureka上服务信息如下:

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目

 打开浏览器访问访问zuul服务的端口9700:http://localhost:9700/api/a/testzuul?name=young码农,我们发现/api/b/*的请求路由到 springcloud-ribbon-client模块

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目

打开浏览器访问zuul服务的端口9700:http://localhost:9700/api/b/testzuul?name=young码农,我们发现/api/b/*的请求路由到 springcloud-feign-client模块

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目

三、zuul实现服务过滤:

zuul不仅只是路由,并且还能过滤,可以用来做一些安全验证和日志记录,我写一个简单的接口执行时间记录的功能

新建一个类:basezuulfilter

package com.haly.filter;

import com.netflix.zuul.zuulfilter;
import com.netflix.zuul.context.requestcontext;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.stereotype.component;

@component
public class basezuulfilter extends zuulfilter {
protected final logger logger = loggerfactory.getlogger(getclass());
// 单例多线程 开始时间绑定在线程上 private threadlocal<long> starttimethreadlocal = new threadlocal<>();
   @override public string filtertype() { // 在请求被处理之后,会进入该过滤器 return "post"; }
   @override public int filterorder() { return 0; } @override public boolean shouldfilter() { // 请求开始计时 long starttime = system.currenttimemillis(); starttimethreadlocal.set(starttime); return true; } @override public object run() { requestcontext context = requestcontext.getcurrentcontext(); string requesturi = string.valueof(context.get("requesturi")); // 请求结束时间 long starttime = starttimethreadlocal.get(); long endtime = system.currenttimemillis(); logger.info("[进入zuul日志记录功能] requesturi:{}, {}:ms", requesturi, endtime - starttime); return null; } }
 filtertype:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
 pre:路由之前
 routing:路由之时
 post: 路由之后
 error:发送错误调用
 filterorder:过滤的顺序
 shouldfilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
 run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
 
浏览器分别请求zuul服务模块:http://localhost:9700/api/b/testzuul?name=young码农,http://localhost:9700/api/b/testzuul?name=young码农,会打印如下日志:
2019-05-25 16:41:07.228  info 20984 --- [io-9700-exec-10] com.haly.filter.basezuulfilter           : [进入zuul日志记录功能]请求地址:/testzuul, 耗时0:ms
有兴趣的可以自己参考上面代码,做一个简单接口权限验证的功能。

四、总结:

当前为止,项目结构:

一起来学Spring Cloud | 第一章 :如何搭建一个多模块的springcloud项目