十次方後端筆記八:網關、配置中心和消息總線

微服務網關

Spring Cloud技術棧採用Zuul作爲微服務網關,在整個架構中,Zuul是所有其他微服務的統一入口,對所有請求進行路由。

管理後臺微服務網關

後臺網關微服務創建Module(省略)

引入依賴

<?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">
    <parent>
        <artifactId>tensquare_parent</artifactId>
        <groupId>com.tensquare</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tensquare_manager</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 9011
spring:
  application:
    name: tensquare‐manager #指定服務名
eureka:
  instance:
    prefer‐ip‐address: true
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka/
zuul:
  routes:
    tensquare‐gathering: #活動
      path: /gathering/**
      serviceId: tensquare‐gathering
    tensquare‐article: #文章
      path: /article/**
      serviceId: tensquare‐article
    tensquare‐base: #基礎
      path: /base/**
      serviceId: tensquare‐base
    tensquare‐friend: #交友
      path: /friend/**
      serviceId: tensquare‐friend
    tensquare‐qa: #問答
      path: /qa/**
      serviceId: tensquare‐qa
    tensquare‐recruit: #招聘
      path: /recruit/**
      serviceId: tensquare‐recruit
    tensquare‐spit: #吐槽
      path: /spit/**
      serviceId: tensquare‐spit
    tensquare‐user: #用戶
      path: /user/**
      serviceId: tensquare‐user

啓動類

package com.tensquare.manager;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

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

前臺微服務網關

前臺網關微服務創建Module(省略)

引入依賴

<?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">
    <parent>
        <artifactId>tensquare_parent</artifactId>
        <groupId>com.tensquare</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tensquare_web</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 9012
spring:
  application:
    name: tensquare‐web #指定服務名
eureka:
  instance:
    prefer‐ip‐address: true
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka/
zuul:
  routes:
    tensquare‐gathering: #活動
      path: /gathering/**
      serviceId: tensquare‐gathering
    tensquare‐article: #文章
      path: /article/**
      serviceId: tensquare‐article
    tensquare‐base: #基礎
      path: /base/**
      serviceId: tensquare‐base
    tensquare‐friend: #交友
      path: /friend/**
      serviceId: tensquare‐friend
    tensquare‐qa: #問答
      path: /qa/**
      serviceId: tensquare‐qa
    tensquare‐recruit: #招聘
      path: /recruit/**
      serviceId: tensquare‐recruit
    tensquare‐spit: #吐槽
      path: /spit/**
      serviceId: tensquare‐spit
    tensquare‐user: #用戶
      path: /user/**
      serviceId: tensquare‐user
    tensquare‐search: #用戶
      path: /user/**
      serviceId: tensquare‐search

啓動類

package com.tensquare.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

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

前臺網關轉發Token

編寫Zuul過濾器實現Token轉發

package com.tensquare.web.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class WebFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        System.out.println("zuul過濾器...");
        //向header中添加鑑權令牌
        RequestContext requestContext = RequestContext.getCurrentContext();
        //獲取header
        HttpServletRequest request = requestContext.getRequest();
        String authorization = request.getHeader("Authorization");
        if (authorization != null) {
            requestContext.addZuulRequestHeader("Authorization", authorization);
        }
        return null;
    }
}

我的另一篇文章有詳細介紹Zuul,文章鏈接:Zuul網關詳解

後臺網關轉發Token

引入依賴

<dependency>
    <groupId>com.tensquare</groupId>
    <artifactId>tensquare_common</artifactId>
    <version>${tensquare.version}</version>
</dependency>

配置Jwt相關常量

配置在application.yml即可

jwt:
  config:
    key: imxushuai

配置Bean

配置在ManagerApplication即可

    @Bean
    public JwtUtil jwtUtil(){
        return new JwtUtil();
    }

配置Zuul過濾器

package com.tensquare.manager.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import util.JwtUtil;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@Component
public class ManagerFilter extends ZuulFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        if (request.getMethod().equals("OPTIONS")) {// 跳過預請求
            return null;
        }
        String url = request.getRequestURL().toString();
        if (url.indexOf("/admin/login") > 0) {// 放行登錄
            log.info("登陸頁面: [{}]", url);
            return null;
        }
        String authHeader = request.getHeader("Authorization");//獲取頭信息
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            Claims claims = jwtUtil.parseJWT(token);
            if (claims != null) {
                if ("admin".equals(claims.get("roles"))) {
                    requestContext.addZuulRequestHeader("Authorization", authHeader);
                    log.info("Token驗證通過,頭信息 [{}]", authHeader);
                    return null;
                }
            }
        }
        requestContext.setSendZuulResponse(false);//終止運行
        requestContext.setResponseStatusCode(401);//http狀態碼
        requestContext.setResponseBody("無權訪問");
        requestContext.getResponse().setContentType("text/html;charset=UTF‐8");
        return null;
    }
}

配置中心

Spring Cloud Config

​ 在分佈式系統中,由於服務數量巨多,爲了方便服務配置文件統一管理,實時更新,所 以需要分佈式配置中心組件。在Spring Cloud中,有分佈式配置中心組件spring cloud config ,它支持配置服務放在配置服務的內存中(即本地),也支持放在遠程Git倉庫 中。在spring cloud config組件中,分兩個角色,一是config server,二是config client

  • Config Server是一個可橫向擴展、集中式的配置服務器,它用於集中管理應用程序各個環境下的配置,默認使用Git存儲配置文件內容,也可以使用SVN存儲,或者是本地文件存儲。
  • Config Client是Config Server的客戶端,用於操作存儲在Config Server中的配置內容。微服務在啓動時會請求Config Server獲取配置文件的內容,請求到後再啓動容器。

創建Git Repository(省略)

Git服務器上創建用於存放配置文件的倉庫。創建好後,將所有的配置文件上傳至Git服務器。

配置中心微服務

創建配置中心微服務Module(省略)

引入依賴

<?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">
    <parent>
        <artifactId>tensquare_parent</artifactId>
        <groupId>com.tensquare</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tensquare_config</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

spring:
  application:
    name: tensquare‐config
  cloud:
    config:
      server:
        git:
          uri: https://github.com/imxushuai/tensquare_config.git
server:
  port: 12000

啓動類

package com.tensquare.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

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

運行測試

成功拉取到配置文件!

Config Client配置

在需要從配置中心拉取配置的微服務中重複一下操作:

引入依賴

引入Spring Cloud Config依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

新增配置文件

resources目錄中新增配置文件:bootstrap.yml

spring:
  cloud:
    config:
      # 應用名
      name: base
      # 環境
      profile: dev
      # 分支
      label: master
      # 配置中心地址
      uri: http://127.0.0.1:12000

配置完畢後,即可刪除配置文件application.yml,測試是否能正常啓動。

Spring Cloud Bus更新配置文件

使用Spring Cloud Bus實現實時更新配置文件,當Git庫配置文件發送變動時,熱更新相應微服務的配置文件。

原理參考:?點擊我?

修改Config Server端

引入依賴

tensquare_config中引入依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>

application.yml新增配置

新增後的application.yml配置文件內容如下:

spring:
  application:
    name: tensquare‐config
  cloud:
    config:
      server:
        git:
          uri: https://github.com/imxushuai/tensquare_config.git
  rabbitmq:
    host: 192.168.136.104
server:
  port: 12000
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

修改Config Client端

在需要從配置中心拉取配置的微服務中重複一下操作:

引入依賴

引入Spring Cloud Bus依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yml新增配置

注意:這裏新增的配置需要在Git服務器中的每個配置文件中加入下面這段配置。

spring:
  rabbitmq:
    host: 192.168.136.104

熱更新配置文件說明

這樣配置文件熱更新的基本上算是完成了,以後在每一次配置文件有更新的時候,我們只需要調用一個接口,就可以完成配置文件的熱更新了。

接口:http://127.0.0.1:12000/actuator/bus-refresh

更新私有配置項

Spring Cloud Bus更新只會更新框架已有的配置項,而不會更新類似Jwt等用戶自定義的配置項。

需要更新自定義的配置項,需要在要更新配置項的Bean上使用@RefreshScope註解,這樣就可以完成配置的更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章