快速搭建SpringCloud脚手架

项目地址: https://gitee.com/GeorgeChan/spring-cloud-parent.git

项目概览 :

springcloud项目概览.png

模块分析 :

spring-cloud-parent : 父工程,管理各子模块,锁定springboot和springcloud版
本,添加maven插件。

common : 公共子模块,定义公共类和公用的jar包供其它模块使用。

eureka-server : 注册中心服务端(单节点),服务注册和发现。

producer1 : 注册中心客户端。

producer2 : 注册中心客户端,与producer1一样,为了演示Feign的负载均衡。

consumers : 注册中心客户端,使用Feign调用producer1和producer2的接口,当
发生调用异常时,通过Hystrix进行熔断和降级。

config-server : 配置中心服务端,同时作为一个eureka客户端注册到注册中心,配
置bus总线,从远程仓库读取配置文件,并进行广播分发,动态刷新配置信息。

config-client : 配置中心客户端,同时作为一个eureka客户端注册到注册中心,配
置bus总线,通过服务端实时获取刷新后的配置文件。事实上除了eureka服务端,每个模块都应当是配置中心的客户端,配置文件统一由配置中心进行管理。这里只用了这一个模块进行演示。

zuul : zuul网关,请求统一从网关进行过滤和分发。服务端限流、token鉴权都在这
里进行。

base : 这里没有作为微服务的一部分,只是springboot整合了mybatis-plus,添加了
mybatis代码生成器。只作为一个演示。

核心解读 :

搭建注册中心服务端

示例模块 : eureka-server

  • 引入pom依赖

    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka- server</artifactId>
    </dependency>
    
  • 配置文件

    eureka:
     server:
     # eureka缓存,true开启缓存,false关闭,生产环境建议为true
     enable-self-preservation: true
     client:
     register-with-eureka: false # 是否注册中心注册自己 true为是,可以在注册中心列表找到自己
     service-url:
     # Eureka客户端与Eureka服务端进行交互的地址
     defaultZone: http://localhost:${server.port}/eureka/
     # 是否从Eureka中获取服务信息
     fetch-registry: false
     # 多个注册中心集群
     # defaultZone: http://localhost:8761/eureka/,http://localhost:8080/eureka/
    
  • 启动类添加注解

    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServerApplication.class, args);
        }
    }
    
  • 启动项目

访问地址 :http://localhost:8761/

搭建注册中心客户端

示例模块 : producer1、producer2、consumers

  • 引入pom依赖

    <dependency>
     <groupId>org.springframework.cloud</groupId>
    
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    
    </dependency>
    
  • 配置文件

    spring:
    
      application:
    
        name: eureka-client-producer # 实例名称,唯一标识
    eureka:
      client:
        service-url: # 指向注册中心
    
          defaultZone: http://localhost:8761/eureka/
    

    配置文件只是示例,完整配置见代码。

  • 启动类添加注解

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

启动项目

访问注册中心,服务实例列表中出现则注册成功。

Feign远程调用与Hystrix熔断降级

示例模块 : producer1、producer2、consumers

  • 引入pom依赖

    <!--Eureka-client-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    
    </dependency>
    <!--feign-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    
    </dependency>
    
  • 配置文件

    eureka:
      client:
        service-url: # 注册中心地址
          defaultZone: http://localhost:8761/eureka/
    feign:
      hystrix:  #开启熔断
        enabled: true
    
  • 启动类添加注解

    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
  • 远程调用示例

    /**
     * <p>
     *  使用Feign进行远程调用
     *  name :调用的服务实例名称,如果是集群则进行轮询负载
     *  fallback :进行降级操作的类
     * </p>
     */
    @FeignClient(name = "eureka-client-producer", fallback = ProducerRemoteFallback.class)
    @Service
    public interface ProducerRemote {
        /**
         * 调用 eureka-client-producer 服务中,url为/test1 的接口
         * 接口地址、方法名,参数与远程服务接口一致
         * @param name 参数
         * @return 返回结果
         */
        @GetMapping("/test1")
        String test1(@RequestParam(value = "name") String name);
    }
    
  • 熔断降级示例

@Component
public class ProducerRemoteFallback implements ProducerRemote {
    @Override
    public String test1(String name) {
        return "操作异常,进行降级。。。。";
    }
}

搭建配置中心服务端

示例模块 : config-server

  • 引入pom文件

    <!--Eureka-client-->
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    
    </dependency>
    <!--config-server-->
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-config-server</artifactId>
    
    </dependency>
    <!--消息总线-->
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    
    </dependency>
    
  • 配置文件

    server:
      port: 9000 # 端口
    spring:
      application:
        name: config-server # 实例名称
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/GeorgeChan/spring-cloud-parent.git # git仓库的地址
              search-paths: config-file/dev,config-file/pro,config-file/test  # git仓库地址下的相对地址,可以配置多个,用,分割。
              username: 码云用户名 #用户名
    
              password: 码云密码#密码
    
      # rabbitmq 配置
      rabbitmq:
        host: localhost
        port: 5672
        username: admin
        password: admin
    # 配置注册中心
    eureka:
      client:
        service-url: # 注册中心地址
          defaultZone: http://localhost:8761/eureka/
    
    #  springboot 2.x 默认只开启了info、health的访问,*代表开启所有访问
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
  • 启动类添加注解

    @SpringBootApplication
    @EnableEurekaClient
    @EnableConfigServer
    public class ConfigServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConfigServerApplication.class, args);
        }
    }
    
  • 刷新配置信息

    这里使用了bus总线,当远程配置文件改变,可以通过访问url

    curl -X POST http://127.0.0.1:9001/actuator/bus-refresh

     将所有关联的配置中心客户端都进行一次刷新。
    
      $注:127.0.0.1:9001是其中一个配置中心客户端的地址$
    

搭建配置中心客户端

示例模块 : config-client

  • 引入pom依赖

    <!--配置中心客户端依赖-->
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-config</artifactId>
    
    </dependency>
    
    <!--动态刷新配置中心-->
    
    <dependency>
    
      <groupId>org.springframework.boot</groupId>
    
      <artifactId>spring-boot-starter-actuator</artifactId>
    
    </dependency>
    
    <!--消息总线-->
    
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    
    </dependency>
    
    <!--Eureka-client-->
    
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    
    </dependency>
    
  • 配置文件

    # 客户端配置文件必须命名为bootstrap.yml(.yaml、properties)
    spring:
      application:
        name: config-client # 实例名称,唯一标识
      cloud:
        config:
          name: config-server # 配置文件的前缀
          profile: dev # 配置文件环境标识
          label: master # 分支
          discovery:
            enabled: true # 开启config服务发现支持
            service-id: config-server # 配置中心server端的name (service-id存在就把uri删掉)
    #   消息总现----开启消息跟踪
        bus:
          trace:
            enabled: true
    #  消息总线----消息队列配置
      rabbitmq:
        host: localhost
        port: 5672
        username: admin
        password: admin
    # 配置注册中心
    eureka:
      client:
        service-url: # 注册中心地址
          defaultZone: http://localhost:8761/eureka/
    # springboot 2.x 默认只开启了info、health的访问,*代表开启所有访问
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
    
  • 添加核心注解
    在需要从配置中心获取配置文件内容的java类上添加注解 @RefreshScope

/**
 * <p>
 *  @RefreshScope 使用该注解的类,会在接到SpringCloud配置中心配置刷新的时候,自动将新的配置更新到该类对应的字段中。
 *                  手动刷新配置:当配置文件发生改动的时候,需要访问接口  curl -X POST http://localhost:9001/actuator/refresh
 *                  [
 *                      "config.client.version",
 *                      "test.env"
 *                  ]
 *                  表示刷新成功!
 *                  localhost:9001 客户端ip和端口
 *
 *  如果使用bus总线刷新配置,请求:curl -X POST http://127.0.0.1:9001/actuator/bus-refresh

 *  所有配置都会刷新
 * </p>
 */
@RefreshScope
@RestController
public class ConfigClientController {

    @Value("${test.env}")
    private String hello;

    @GetMapping("/name")
    public String test() {
        return this.hello;
    }
}

搭建Zuul网关

  • 引入pom依赖

    <!--Eureka-client-->
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    
    </dependency>
    
    <!--zuul-->
    
    <dependency>
    
      <groupId>org.springframework.cloud</groupId>
    
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    
    </dependency>
    
  • 配置文件

    spring:
      application:
        name: zuul # 实例名称 唯一标识
      # springboot解决中文乱码问题
      http:
        encoding:
          charset: UTF-8
          enabled: true
          force: true
    eureka:
      client:
        service-url: # 注册中心地址
          defaultZone: http://localhost:8761/eureka/
    
    zuul:
      routes: #自定义路由映射 (路由不能重复,下面会把上面的覆盖)
        eureka-client-producer: /api/producer/**
        eureka-client-consumers: /api/consumer/**
      # 忽略的服务
      ignored-patterns: /*-producer/**
    #  敏感的头信息 默认Cookie是不能通过网关头信息传递的
    #  sensitive-headers:
    
  • 启动类添加注解

    @SpringBootApplication
    @EnableEurekaClient
    @EnableZuulProxy
    public class ZuulApplication {
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication.class, args);
        }
    }
    
  • 自定义过滤器,模拟token鉴权

@Component
public class MyFilter extends ZuulFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyFilter.class);
    /**
     * 过滤器类型,前置过滤器
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 过滤器顺序,越小越先执行
     * @return
     */
    @Override
    public int filterOrder() {
        return 4;
    }

    /**
     * 过滤器是否生效
     * RequestContext 请求的全局对象
     * @return boolean 是否过滤
     */
    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String cookie = request.getHeader("Cookie");
        String authorization = request.getHeader("Authorization");
        LOGGER.info("Cookie ====》 {}", cookie);
        LOGGER.info("Authorization ====》 {}", authorization);
        return true;
    }

    /**
     * 业务逻辑
     * 模拟token鉴权,如果Authorization为空,表示没有权限
     * @return 
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String cookie = request.getHeader("Cookie");
        String authorization = request.getHeader("Authorization");

        // 这里模拟权限检验,失败返回401
        if (StringUtils.isEmpty(authorization)) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            requestContext.setResponseBody("权限不足!");
        }
        return null;
    }
}

其它

启动顺序

当项目包含注册中心、配置中心以及网关时,启动顺序为

  1. 注册中心服务端

  2. 配置中心服务端

  3. 注册(配置)中心客户端

  4. 网关

注意 :以上代码只是示例,并不完整,详细请见 ====> 码云仓库

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容