2019-10-15Spring Cloud 筆記

單體應(yīng)用存在的問(wèn)題

  • 隨著業(yè)務(wù)的發(fā)展,開(kāi)發(fā)變得越來(lái)越復(fù)雜悉患。
  • 修改残家、新增某個(gè)功能,需要對(duì)整個(gè)系統(tǒng)進(jìn)行測(cè)試购撼、重新部署跪削。
  • 一個(gè)模塊出現(xiàn)問(wèn)題,很可能導(dǎo)致整個(gè)系統(tǒng)崩潰迂求。
  • 多個(gè)開(kāi)發(fā)團(tuán)隊(duì)同時(shí)對(duì)數(shù)據(jù)進(jìn)行管理碾盐,容易產(chǎn)生安全漏洞。
  • 各個(gè)模塊使用同一種技術(shù)進(jìn)行開(kāi)發(fā)揩局,各個(gè)模塊很難根據(jù)實(shí)際情況選擇更合適的技術(shù)框架毫玖,局限性很大。
  • 模塊內(nèi)容過(guò)于復(fù)雜,如果員工離職付枫,可能需要很長(zhǎng)時(shí)間才能完成工作交接烹玉。

分布式、集群

集群:一臺(tái)服務(wù)器無(wú)法負(fù)荷高并發(fā)的數(shù)據(jù)訪問(wèn)量阐滩,那么就設(shè)置十臺(tái)服務(wù)器一起分擔(dān)壓力二打,十臺(tái)不行就設(shè)置一百臺(tái)(物理層面)。很多人干同一件事情掂榔,來(lái)分?jǐn)倝毫Α?/p>

分布式:將一個(gè)復(fù)雜問(wèn)題拆分成若干個(gè)簡(jiǎn)單的小問(wèn)題继效,將一個(gè)大型的項(xiàng)目架構(gòu)拆分成若干個(gè)微服務(wù)來(lái)協(xié)同完成。(軟件設(shè)計(jì)層面)装获。將一個(gè)龐大的工作拆分成若干個(gè)小步驟瑞信,分別由不同的人完成這些小步驟,最終將所有的結(jié)果進(jìn)行整合實(shí)現(xiàn)大的需求穴豫。

服務(wù)治理的核心又三部分組成:服務(wù)提供者凡简、服務(wù)消費(fèi)者、注冊(cè)中心精肃。

在分布式系統(tǒng)架構(gòu)中秤涩,每個(gè)微服務(wù)在啟動(dòng)時(shí),將自己的信息存儲(chǔ)在注冊(cè)中心肋杖,叫做服務(wù)注冊(cè)溉仑。

服務(wù)消費(fèi)者從注冊(cè)中心獲取服務(wù)提供者的網(wǎng)絡(luò)信息,通過(guò)該信息調(diào)用服務(wù)状植,叫做服務(wù)發(fā)現(xiàn)。

Spring Cloud 的服務(wù)治理使用 Eureka 來(lái)實(shí)現(xiàn)怨喘,Eureka 是 Netflix 開(kāi)源的基于 REST 的服務(wù)治理解決方案津畸,Spring Cloud 集成了 Eureka,提供服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)的功能必怜,可以和基于 Spring Boot 搭建的微服務(wù)應(yīng)用輕松完成整合肉拓,開(kāi)箱即用,Spring Cloud Eureka梳庆。

Spring Cloud Eureka

  • Eureka Server暖途,注冊(cè)中心
  • Eureka Client,所有要進(jìn)行注冊(cè)的微服務(wù)通過(guò) Eureka Client 連接到 Eureka Server膏执,完成注冊(cè)驻售。

Eureka Server代碼實(shí)現(xiàn)

  • 創(chuàng)建父工程,pom.xml
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.7.RELEASE</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!-- 解決 JDK 9 以上沒(méi)有 JAXB API 的問(wèn)題 -->
  <dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
  </dependency>

  <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.0</version>
  </dependency>

  <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.3.0</version>
  </dependency>

  <dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Finchley.SR2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
  • 在父工程下創(chuàng)建 Module更米,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml欺栗,添加 Eureka Server 相關(guān)配置。
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

屬性說(shuō)明

server.port:當(dāng)前 Eureka Server 服務(wù)端口。

eureka.client.register-with-eureka:是否將當(dāng)前的 Eureka Server 服務(wù)作為客戶端進(jìn)行注冊(cè)迟几。

eureka.client.fetch-fegistry:是否獲取其他 Eureka Server 服務(wù)的數(shù)據(jù)消请。

eureka.client.service-url.defaultZone:注冊(cè)中心的訪問(wèn)地址。

  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

注解說(shuō)明:

@SpringBootApplication:聲明該類(lèi)是 Spring Boot 服務(wù)的入口类腮。

@EnableEurekaServer:聲明該類(lèi)是一個(gè) Eureka Server 微服務(wù)臊泰,提供服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)功能,即注冊(cè)中心蚜枢。

Eureka Client 代碼實(shí)現(xiàn)

  • 創(chuàng)建 Module 缸逃,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml,添加 Eureka Client 相關(guān)配置
server:
  port: 8010
spring:
  application:
    name: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

屬性說(shuō)明:

spring.application.name:當(dāng)前服務(wù)注冊(cè)在 Eureka Server 上的名稱祟偷。

eureka.client.service-url.defaultZone:注冊(cè)中心的訪問(wèn)地址察滑。

eureka.instance.prefer-ip-address:是否將當(dāng)前服務(wù)的 IP 注冊(cè)到 Eureka Server。

  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}
  • 實(shí)體類(lèi)
package com.southwind.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private long id;
    private String name;
    private int age;
}
  • Repository
package com.southwind.repository;

import com.southwind.entity.Student;

import java.util.Collection;

public interface StudentRepository {
    public Collection<Student> findAll();
    public Student findById(long id);
    public void saveOrUpdate(Student student);
    public void deleteById(long id);
}
  • RepositoryImpl
package com.southwind.repository.impl;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class StudentRepositoryImpl implements StudentRepository {

    private static Map<Long,Student> studentMap;

    static {
        studentMap = new HashMap<>();
        studentMap.put(1L,new Student(1L,"張三",22));
        studentMap.put(2L,new Student(2L,"李四",23));
        studentMap.put(3L,new Student(3L,"王五",24));
    }

    @Override
    public Collection<Student> findAll() {
        return studentMap.values();
    }

    @Override
    public Student findById(long id) {
        return studentMap.get(id);
    }

    @Override
    public void saveOrUpdate(Student student) {
        studentMap.put(student.getId(),student);
    }

    @Override
    public void deleteById(long id) {
        studentMap.remove(id);
    }
}
  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/student")
public class StudentHandler {
    @Autowired
    private StudentRepository studentRepository;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return studentRepository.findById(id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        studentRepository.deleteById(id);
    }
}

RestTemplate 的使用

  • 什么是 RestTemplate修肠?

RestTemplate 是 Spring 框架提供的基于 REST 的服務(wù)組件贺辰,底層是對(duì) HTTP 請(qǐng)求及響應(yīng)進(jìn)行了封裝,提供了很多訪問(wèn) RETS 服務(wù)的方法嵌施,可以簡(jiǎn)化代碼開(kāi)發(fā)饲化。

  • 如何使用 RestTemplate?

1吗伤、創(chuàng)建 Maven 工程吃靠,pom.xml。

2足淆、創(chuàng)建實(shí)體類(lèi)

package com.southwind.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private long id;
    private String name;
    private int age;
}

3巢块、Handler

package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/rest")
public class RestHandler {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
    }

    @GetMapping("/findAll2")
    public Collection<Student> findAll2(){
        return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
    }

    @GetMapping("/findById2/{id}")
    public Student findById2(@PathVariable("id") long id){
        return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
    }

    @PostMapping("/save2")
    public void save2(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/student/save",student,null);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/student/update",student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
    }
}

4、啟動(dòng)類(lèi)

package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

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

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

服務(wù)消費(fèi)者 consumer

  • 創(chuàng)建 Maven 工程巧号,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8020
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

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

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/consumer")
public class ConsumerHandler {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
    }

    @GetMapping("/findAll2")
    public Collection<Student> findAll2(){
        return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
    }

    @GetMapping("/findById2/{id}")
    public Student findById2(@PathVariable("id") long id){
        return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
    }

    @PostMapping("/save2")
    public void save2(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/student/save",student,null);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/student/update",student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
    }
}

服務(wù)網(wǎng)關(guān)

Spring Cloud 集成了 Zuul 組件族奢,實(shí)現(xiàn)服務(wù)網(wǎng)關(guān)。

  • 什么是 Zuul丹鸿?

Zuul 是 Netflix 提供的一個(gè)開(kāi)源的 API 網(wǎng)關(guān)服務(wù)器越走,是客戶端和網(wǎng)站后端所有請(qǐng)求的中間層,對(duì)外開(kāi)放一個(gè) API靠欢,將所有請(qǐng)求導(dǎo)入統(tǒng)一的入口廊敌,屏蔽了服務(wù)端的具體實(shí)現(xiàn)邏輯,Zuul 可以實(shí)現(xiàn)反向代理的功能门怪,在網(wǎng)關(guān)內(nèi)部實(shí)現(xiàn)動(dòng)態(tài)路由骡澈、身份認(rèn)證、IP 過(guò)濾薪缆、數(shù)據(jù)監(jiān)控等秧廉。

  • 創(chuàng)建 Maven 工程伞广,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8030
spring:
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
zuul:
  routes:
    provider: /p/**

屬性說(shuō)明:

zuul.routes.provider:給服務(wù)提供者 provider 設(shè)置映射

  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

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

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

注解說(shuō)明:

@EnableZuulProxy:包含了 @EnableZuulServer,設(shè)置該類(lèi)是網(wǎng)關(guān)的啟動(dòng)類(lèi)疼电。

@EnableAutoConfiguration:可以幫助 Spring Boot 應(yīng)用將所有符合條件的 @Configuration 配置加載到當(dāng)前 Spring Boot 創(chuàng)建并使用的 IoC 容器中嚼锄。

  • Zuul 自帶了負(fù)載均衡功能,修改 provider 的代碼蔽豺。
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/student")
public class StudentHandler {
    @Autowired
    private StudentRepository studentRepository;

    @Value("${server.port}")
    private String port;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return studentRepository.findById(id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        studentRepository.deleteById(id);
    }

    @GetMapping("/index")
    public String index(){
        return "當(dāng)前端口:"+this.port;
    }
}

Ribbon 負(fù)載均衡

  • 什么是 Ribbon区丑?

Spring Cloud Ribbon 是一個(gè)負(fù)載均衡解決方案,Ribbon 是 Netflix 發(fā)布的負(fù)載均衡器修陡,Spring Cloud Ribbon 是基于 Netflix Ribbon 實(shí)現(xiàn)的沧侥,是一個(gè)用于對(duì) HTTP 請(qǐng)求進(jìn)行控制的負(fù)載均衡客戶端。

在注冊(cè)中心對(duì) Ribbon 進(jìn)行注冊(cè)之后魄鸦,Ribbon 就可以基于某種負(fù)載均衡算法宴杀,如輪詢、隨機(jī)拾因、加權(quán)輪詢旺罢、加權(quán)隨機(jī)等自動(dòng)幫助服務(wù)消費(fèi)者調(diào)用接口,開(kāi)發(fā)者也可以根據(jù)具體需求自定義 Ribbon 負(fù)載均衡算法绢记。實(shí)際開(kāi)發(fā)中扁达,Spring Cloud Ribbon 需要結(jié)合 Spring Cloud Eureka 來(lái)使用,Eureka Server 提供所有可以調(diào)用的服務(wù)提供者列表蠢熄,Ribbon 基于特定的負(fù)載均衡算法從這些服務(wù)提供者中選擇要調(diào)用的具體實(shí)例跪解。

  • 創(chuàng)建 Module,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8040
spring:
  application:
    name: ribbon
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

@LoadBalanced:聲明一個(gè)基于 Ribbon 的負(fù)載均衡签孔。

  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/ribbon")
public class RibbonHandler {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForObject("http://provider/student/findAll",Collection.class);
    }

    @GetMapping("/index")
    public String index(){
        return restTemplate.getForObject("http://provider/student/index",String.class);
    }
}

Feign

  • 什么是 Feign叉讥?

與 Ribbon 一樣,F(xiàn)eign 也是由 Netflix 提供的饥追,F(xiàn)eign 是一個(gè)聲明式节吮、模版化的 Web Service 客戶端,它簡(jiǎn)化了開(kāi)發(fā)者編寫(xiě) Web 服務(wù)客戶端的操作判耕,開(kāi)發(fā)者可以通過(guò)簡(jiǎn)單的接口和注解來(lái)調(diào)用 HTTP API,Spring Cloud Feign翘骂,它整合了 Ribbon 和 Hystrix壁熄,具有可插拔、基于注解碳竟、負(fù)載均衡草丧、服務(wù)熔斷等一系列便捷功能。

相比較于 Ribbon + RestTemplate 的方式莹桅,F(xiàn)eign 大大簡(jiǎn)化了代碼的開(kāi)發(fā)昌执,F(xiàn)eign 支持多種注解烛亦,包括 Feign 注解、JAX-RS 注解懂拾、Spring MVC 注解等煤禽,Spring Cloud 對(duì) Feing 進(jìn)行了優(yōu)化,整合了 Ribbon 和 Eureka岖赋,從而讓 Feign 的使用更加方便檬果。

  • Ribbon 和 Feign 的區(qū)別

Ribbon 是一個(gè)通用的 HTTP 客戶端工具,F(xiàn)eign 是基于 Ribbon 實(shí)現(xiàn)的唐断。

  • Feign 的tedian

1选脊、Feign 是一個(gè)聲明式的 Web Service 客戶端。

2脸甘、支持 Feign 注解恳啥、Spring MVC 注解、JAX-RS 注解丹诀。

3钝的、Feign 基于 Ribbon 實(shí)現(xiàn),使用起來(lái)更加簡(jiǎn)單忿墅。

4扁藕、Feign 集成了 Hystrix,具備服務(wù)熔斷的功能疚脐。

  • 創(chuàng)建 Module亿柑,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8050
spring:
  application:
    name: feign
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class,args);
    }
}
  • 創(chuàng)建聲明式接口
package com.southwind.feign;

import com.southwind.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Collection;

@FeignClient(value = "provider")
public interface FeignProviderClient {
    @GetMapping("/student/findAll")
    public Collection<Student> findAll();

    @GetMapping("/student/index")
    public String index();
}
  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

@RestController
@RequestMapping("/feign")
public class FeignHandler {

    @Autowired
    private FeignProviderClient feignProviderClient;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return feignProviderClient.findAll();
    }

    @GetMapping("/index")
    public String index(){
        return feignProviderClient.index();
    }
}
  • 服務(wù)熔斷,application.yml 添加熔斷機(jī)制棍弄。
server:
  port: 8050
spring:
  application:
    name: feign
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true

feign.hystrix.enabled:是否開(kāi)啟熔斷器望薄。

  • 創(chuàng)建 FeignProviderClient 接口的實(shí)現(xiàn)類(lèi) FeignError,定義容錯(cuò)處理邏輯呼畸,通過(guò) @Component 注解將 FeignError 實(shí)例注入 IoC 容器中痕支。
package com.southwind.feign.impl;

import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.stereotype.Component;

import java.util.Collection;

@Component
public class FeignError implements FeignProviderClient {
    @Override
    public Collection<Student> findAll() {
        return null;
    }

    @Override
    public String index() {
        return "服務(wù)器維護(hù)中......";
    }
}
  • 在 FeignProviderClient 定義處通過(guò) @FeignClient 的 fallback 屬性設(shè)置映射。
package com.southwind.feign;

import com.southwind.entity.Student;
import com.southwind.feign.impl.FeignError;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Collection;

@FeignClient(value = "provider",fallback = FeignError.class)
public interface FeignProviderClient {
    @GetMapping("/student/findAll")
    public Collection<Student> findAll();

    @GetMapping("/student/index")
    public String index();
}

Hystrix 容錯(cuò)機(jī)制

在不改變各個(gè)微服務(wù)調(diào)用關(guān)系的前提下蛮原,針對(duì)錯(cuò)誤情況進(jìn)行預(yù)先處理卧须。

  • 設(shè)計(jì)原則

1、服務(wù)隔離機(jī)制

2儒陨、服務(wù)降級(jí)機(jī)制

3花嘶、熔斷機(jī)制

4、提供實(shí)時(shí)的監(jiān)控和報(bào)警功能

5蹦漠、提供實(shí)時(shí)的配置修改功能

Hystrix 數(shù)據(jù)監(jiān)控需要結(jié)合 Spring Boot Actuator 來(lái)使用椭员,Actuator 提供了對(duì)服務(wù)的健康健康、數(shù)據(jù)統(tǒng)計(jì)笛园,可以通過(guò) hystrix.stream 節(jié)點(diǎn)獲取監(jiān)控的請(qǐng)求數(shù)據(jù)隘击,提供了可視化的監(jiān)控界面侍芝。

  • 創(chuàng)建 Maven,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.0.7.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8060
spring:
  application:
    name: hystrix
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true
management:
  endpoints:
    web:
      exposure:
        include: 'hystrix.stream'
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
public class HystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixApplication.class,args);
    }
}

注解說(shuō)明:

@EnableCircuitBreaker:聲明啟用數(shù)據(jù)監(jiān)控

@EnableHystrixDashboard:聲明啟用可視化數(shù)據(jù)監(jiān)控

  • Handler
package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.feign.FeignProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

@RestController
@RequestMapping("/hystrix")
public class HystrixHandler {
    @Autowired
    private FeignProviderClient feignProviderClient;

    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return feignProviderClient.findAll();
    }

    @GetMapping("/index")
    public String index(){
        return feignProviderClient.index();
    }
}
  • 啟動(dòng)成功之后埋同,訪問(wèn) http://localhost:8060/actuator/hystrix.stream 可以監(jiān)控到請(qǐng)求數(shù)據(jù)州叠,
  • 訪問(wèn) http://localhost:8060/hystrix,可以看到可視化的監(jiān)控界面莺禁,輸入要監(jiān)控的地址節(jié)點(diǎn)即可看到該節(jié)點(diǎn)的可視化數(shù)據(jù)監(jiān)控留量。

Spring Cloud 配置中心

Spring Cloud Config,通過(guò)服務(wù)端可以為多個(gè)客戶端提供配置服務(wù)哟冬。Spring Cloud Config 可以將配置文件存儲(chǔ)在本地楼熄,也可以將配置文件存儲(chǔ)在遠(yuǎn)程 Git 倉(cāng)庫(kù),創(chuàng)建 Config Server浩峡,通過(guò)它管理所有的配置文件可岂。

本地文件系統(tǒng)

  • 創(chuàng)建 Maven 工程,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建 application.yml
server:
  port: 8762
spring:
  application:
    name: nativeconfigserver
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared

注解說(shuō)明

profiles.active:配置文件的獲取方式

cloud.config.server.native.search-locations:本地配置文件存放的路徑

  • resources 路徑下創(chuàng)建 shared 文件夾翰灾,并在此路徑下創(chuàng)建 configclient-dev.yml缕粹。
server:
  port: 8070
foo: foo version 1
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

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

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

注解說(shuō)明

@EnableConfigServer:聲明配置中心。

創(chuàng)建客戶端讀取本地配置中心的配置文件

  • 創(chuàng)建 Maven 工程纸淮,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建 bootstrap.yml平斩,配置讀取本地配置中心的相關(guān)信息。
spring:
  application:
    name: configclient
  profiles:
    active: dev
  cloud:
    config:
      uri: http://localhost:8762
      fail-fast: true

注解說(shuō)明

cloud.config.uri:本地 Config Server 的訪問(wèn)路徑

cloud.config.fail-fase:設(shè)置客戶端優(yōu)先判斷 Config Server 獲取是否正常咽块。

通過(guò)spring.application.name 結(jié)合spring.profiles.active拼接目標(biāo)配置文件名绘面,configclient-dev.yml,去 Config Server 中查找該文件侈沪。

  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class NativeConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(NativeConfigClientApplication.class,args);
    }
}
  • Handler
package com.southwind.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/native")
public class NativeConfigHandler {

    @Value("${server.port}")
    private String port;

    @Value("${foo}")
    private String foo;

    @GetMapping("/index")
    public String index(){
        return this.port+"-"+this.foo;
    }
}

Spring Cloud Config 遠(yuǎn)程配置

  • 創(chuàng)建配置文件揭璃,上傳至 GitHub
server:
  port: 8070
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: configclient
  • 創(chuàng)建 Config Server,新建 Maven 工程亭罪,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8888
spring:
  application:
    name: configserver
  cloud:
    config:
      server:
        git:
          uri: https://github.com/southwind9801/aispringcloud.git
          searchPaths: config
          username: root
          password: root
      label: master
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

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

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

創(chuàng)建 Config Client

  • 創(chuàng)建 Maven 工程瘦馍,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建 bootstrap.yml
spring:
  cloud:
    config:
      name: configclient
      label: master
      discovery:
        enabled: true
        service-id: configserver
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

注解說(shuō)明

spring.cloud.config.name:當(dāng)前服務(wù)注冊(cè)在 Eureka Server 上的名稱,與遠(yuǎn)程倉(cāng)庫(kù)的配置文件名對(duì)應(yīng)应役。

spring.cloud.config.label:Git Repository 的分支情组。

spring.cloud.config.discovery.enabled:是否開(kāi)啟 Config 服務(wù)發(fā)現(xiàn)支持。

spring.cloud.config.discovery.service-id:配置中心在 Eureka Server 上注冊(cè)的名稱箩祥。

  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class,args);
    }
}
  • Handler
package com.southwind.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloHandler {

    @Value("${server.port}")
    private String port;

    @GetMapping("/index")
    public String index(){
        return this.port;
    }
}

服務(wù)跟蹤

Spring Cloud Zipkin

Zipkin 是一個(gè)可以采集并且跟蹤分布式系統(tǒng)中請(qǐng)求數(shù)據(jù)的組件呻惕,讓開(kāi)發(fā)者可以更加直觀的監(jiān)控到請(qǐng)求在各個(gè)微服務(wù)所耗費(fèi)的時(shí)間等,Zipkin:Zipkin Server滥比、Zipkin Client。

創(chuàng)建 Zipkin Server

  • 創(chuàng)建 Maven 工程做院,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
    <version>2.9.4</version>
  </dependency>
  <dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
    <version>2.9.4</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 9090
  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;

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

注解說(shuō)明

@EnableZipkinServer:聲明啟動(dòng) Zipkin Server

創(chuàng)建 Zipkin Client

  • 創(chuàng)建 Maven 工程盲泛,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 創(chuàng)建配置文件 application.yml
server:
  port: 8090
spring:
  application:
    name: zipkinclient
  sleuth:
    web:
      client:
        enabled: true
    sampler:
      probability: 1.0
  zipkin:
    base-url: http://localhost:9090/
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

屬性說(shuō)明

spring.sleuth.web.client.enabled:設(shè)置開(kāi)啟請(qǐng)求跟蹤

spring.sleuth.sampler.probability:設(shè)置采樣比例濒持,默認(rèn)是 1.0

srping.zipkin.base-url:Zipkin Server 地址

  • 創(chuàng)建啟動(dòng)類(lèi)
package com.southwind;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ZipkinClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZipkinClientApplication.class,args);
    }
}
  • Handler
package com.southwind.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/zipkin")
public class ZipkinHandler {

    @Value("${server.port}")
    private String port;

    @GetMapping("/index")
    public String index(){
        return this.port;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市寺滚,隨后出現(xiàn)的幾起案子柑营,更是在濱河造成了極大的恐慌,老刑警劉巖村视,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件官套,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蚁孔,警方通過(guò)查閱死者的電腦和手機(jī)奶赔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)杠氢,“玉大人站刑,你說(shuō)我怎么就攤上這事”前伲” “怎么了绞旅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)温艇。 經(jīng)常有香客問(wèn)我因悲,道長(zhǎng),這世上最難降的妖魔是什么勺爱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任晃琳,我火速辦了婚禮,結(jié)果婚禮上邻寿,老公的妹妹穿的比我還像新娘蝎土。我一直安慰自己,他們只是感情好绣否,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布誊涯。 她就那樣靜靜地躺著,像睡著了一般蒜撮。 火紅的嫁衣襯著肌膚如雪暴构。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天段磨,我揣著相機(jī)與錄音取逾,去河邊找鬼。 笑死苹支,一個(gè)胖子當(dāng)著我的面吹牛砾隅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播债蜜,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晴埂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼究反!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起儒洛,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤精耐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后琅锻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體卦停,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年恼蓬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惊完。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滚秩,死狀恐怖专执,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情郁油,我是刑警寧澤本股,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站桐腌,受9級(jí)特大地震影響拄显,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜案站,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一躬审、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蟆盐,春花似錦承边、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至痹愚,卻和暖如春富岳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拯腮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工窖式, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人动壤。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓萝喘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜒灰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 單體應(yīng)用存在的問(wèn)題 隨著業(yè)務(wù)的發(fā)展弦蹂,開(kāi)發(fā)變得越來(lái)越復(fù)雜。 修改强窖、新增某個(gè)功能,需要對(duì)整個(gè)系統(tǒng)進(jìn)行測(cè)試削祈、重新部署翅溺。 ...
    Juntech閱讀 269評(píng)論 0 0
  • 微服務(wù)架構(gòu)模式的核心在于如何識(shí)別服務(wù)的邊界,設(shè)計(jì)出合理的微服務(wù)髓抑。但如果要將微服務(wù)架構(gòu)運(yùn)用到生產(chǎn)項(xiàng)目上咙崎,并且能夠發(fā)揮...
    java菜閱讀 2,958評(píng)論 0 6
  • 1 為什么需要服務(wù)發(fā)現(xiàn) 簡(jiǎn)單來(lái)說(shuō),服務(wù)化的核心就是將傳統(tǒng)的一站式應(yīng)用根據(jù)業(yè)務(wù)拆分成一個(gè)一個(gè)的服務(wù)吨拍,而微服務(wù)在這個(gè)基...
    謙小易閱讀 25,109評(píng)論 4 93
  • 1.感恩孩子一直陪伴在我身邊褪猛! 2.感恩我現(xiàn)在有一份值得奮斗的工作! 3.感恩現(xiàn)在有一位非常值得跟隨學(xué)習(xí)的領(lǐng)導(dǎo)羹饰!
    心理咨詢師邱燕燕閱讀 128評(píng)論 0 0
  • 積極主動(dòng)做好自己 90天踐行目標(biāo): ?1.每周跑步四次伊滋,每次30分鐘以上。8 ?2.每天晨讀晨講輸出一次队秩。 9 ?...
    張道武閱讀 228評(píng)論 2 2