目的:

    微服务调用Ribbon

    Ribbon负载均衡

    Feign简介及应用


微服务调用Ribbon

  Ribbon简介

  1. 负载均衡框架,支持可插拔式的负载均衡规则

  2. 支持多种协议,如HTTP、UDP等

  3. 提供负载均衡客户端

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。

在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。展示了Ribbon与Eureka配合使用时的架构。

初步应用

Ribbon是客户端负载均衡,所以肯定集成再消费端,也就是consumer端

我们修改microservice-student-consumer-80(工程我是在上一篇博客中玩集成建成https://www.cnblogs.com/huangting/p/11902121.html

首先,引入依赖,pom.xml 加入 ribbon相关依赖

  1. <!--ribbon相关依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-eureka</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.cloud</groupId>
  8. <artifactId>spring-cloud-starter-ribbon</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.cloud</groupId>
  12. <artifactId>spring-cloud-starter-config</artifactId>
  13. </dependency>

给application.yml配置

  1. server:
  2. port: 80
  3. context-path: /
  4. eureka:
  5. client:
  6. service-url:
  7. defaultZone: http://eureka2001.ht.com:2001/eureka/,http://eureka2002.ht.com:2002/eureka/,http://eureka2003.ht.com:2003/eureka/
  8. register-with-eureka: false

ribbon结合eureka来调用服务提供者;

SpringCloudConfig也改成 要加个负载均衡配置 @LoadBalanced

因为和eureka整合,所以启动类StudentConsumerApplication_80 加个注解 @EnableEurekaClient

在提供者microservice-student-provider-1001的yml文件中添加配置:

  1. application:
  2. name: microservice-student

上面配置好后,我们可以测试下

先启动三个eureka,然后再启动服务提供者,再启动服务消费者;

访问http://localhost/student/list


Ribbon负载均衡

按照它microservice-student-provider-1001建立一个microservice-student-provider子项目,然后将microservice-student-provider-1001这个子项目干掉;

前面搭建了初步例子,但是还没实现真正负载均衡,我们这里要先搞三个服务提供者集群,然后才能演示负载均衡,以及负载均衡策略;

新建项目microservice-student-provider-1002,microservice-student-provider-1003

pom.xml,application.yml,以及java类都复制一份,启动类名称对应的改下;

yml配置文件有两处要对应的改下,port端口改下,以及服务实例名称改下;

pom依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>com.ht</groupId>
  7. <artifactId>htSpringCloud</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <groupId>com.ht</groupId>
  11. <artifactId>microservice-student-provider</artifactId>
  12.  
  13. <properties>
  14. <java.version>1.8</java.version>
  15. </properties>
  16.  
  17. <dependencies>
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-web</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-test</artifactId>
  25. <scope>test</scope>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-starter-data-jpa</artifactId>
  30. </dependency>
  31. <dependency>
  32. <groupId>mysql</groupId>
  33. <artifactId>mysql-connector-java</artifactId>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-tomcat</artifactId>
  38. </dependency>
  39. <dependency>
  40. <groupId>com.alibaba</groupId>
  41. <artifactId>druid-spring-boot-starter</artifactId>
  42. </dependency>
  43. <!-- 修改后立即生效,热部署 -->
  44. <dependency>
  45. <groupId>org.springframework</groupId>
  46. <artifactId>springloaded</artifactId>
  47. </dependency>
  48. <dependency>
  49. <groupId>org.springframework.boot</groupId>
  50. <artifactId>spring-boot-devtools</artifactId>
  51. </dependency>
  52.  
  53. <!--添加注册中心Eureka相关配置-->
  54. <dependency>
  55. <groupId>org.springframework.cloud</groupId>
  56. <artifactId>spring-cloud-starter-eureka</artifactId>
  57. </dependency>
  58. <dependency>
  59. <groupId>org.springframework.cloud</groupId>
  60. <artifactId>spring-cloud-starter-config</artifactId>
  61. </dependency>
  62.  
  63. <!-- actuator监控引入 -->
  64. <dependency>
  65. <groupId>org.springframework.boot</groupId>
  66. <artifactId>spring-boot-starter-actuator</artifactId>
  67. </dependency>
  68. </dependencies>
  69.  
  70. <build>
  71. <plugins>
  72. <plugin>
  73. <groupId>org.springframework.boot</groupId>
  74. <artifactId>spring-boot-maven-plugin</artifactId>
  75. </plugin>
  76. </plugins>
  77. </build>
  78.  
  79. </project>

配置Yml文件

  1. ---
  2. server:
  3. port: 1001
  4. context-path: /
  5. spring:
  6. datasource:
  7. type: com.alibaba.druid.pool.DruidDataSource
  8. driver-class-name: com.mysql.jdbc.Driver
  9. url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
  10. username: root
  11. password: root
  12. jpa:
  13. hibernate:
  14. ddl-auto: update
  15. show-sql: true
  16. application:
  17. name: microservice-student
  18. profiles: provider-1001
  19.  
  20. eureka:
  21. instance:
  22. hostname: localhost
  23. appname: microservice-student
  24. instance-id: microservice-student:1001
  25. prefer-ip-address: true
  26. client:
  27. service-url:
  28. defaultZone: http://eureka2001.ht.com:2001/eureka/,http://eureka2002.ht.com:2002/eureka/,http://eureka2003.ht.com:2003/eureka/
  29.  
  30. info:
  31. groupId: com.ht.htSpringCloud
  32. artifactId: microservice-student-provider-1001
  33. version: 1.0-SNAPSHOT
  34. userName: http://ht.com
  35. phone: 123456
  36.  
  37. ---
  38. server:
  39. port: 1002
  40. context-path: /
  41. spring:
  42. datasource:
  43. type: com.alibaba.druid.pool.DruidDataSource
  44. driver-class-name: com.mysql.jdbc.Driver
  45. url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
  46. username: root
  47. password: root
  48. jpa:
  49. hibernate:
  50. ddl-auto: update
  51. show-sql: true
  52. application:
  53. name: microservice-student
  54. profiles: provider-1002
  55.  
  56. eureka:
  57. instance:
  58. hostname: localhost
  59. appname: microservice-student
  60. instance-id: microservice-student:1002
  61. prefer-ip-address: true
  62. client:
  63. service-url:
  64. defaultZone: http://eureka2001.ht.com:2001/eureka/,http://eureka2002.ht.com:2002/eureka/,http://eureka2003.ht.com:2003/eureka/
  65.  
  66. info:
  67. groupId: com.ht.htSpringCloud
  68. artifactId: microservice-student-provider-1002
  69. version: 1.0-SNAPSHOT
  70. userName: http://ht.com
  71. phone: 123456
  72.  
  73. ---
  74. server:
  75. port: 1003
  76. context-path: /
  77. spring:
  78. datasource:
  79. type: com.alibaba.druid.pool.DruidDataSource
  80. driver-class-name: com.mysql.jdbc.Driver
  81. url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
  82. username: root
  83. password: root
  84. jpa:
  85. hibernate:
  86. ddl-auto: update
  87. show-sql: true
  88. application:
  89. name: microservice-student
  90. profiles: provider-1003
  91.  
  92. eureka:
  93. instance:
  94. hostname: localhost
  95. appname: microservice-student
  96. instance-id: microservice-student:1003
  97. prefer-ip-address: true
  98. client:
  99. service-url:
  100. defaultZone: http://eureka2001.ht.com:2001/eureka/,http://eureka2002.ht.com:2002/eureka/,http://eureka2003.ht.com:2003/eureka/
  101.  
  102. info:
  103. groupId: com.ht.htSpringCloud
  104. artifactId: microservice-student-provider-1003
  105. version: 1.0-SNAPSHOT
  106. userName: http://ht.com
  107. phone: 123456

启动类中添加注解

  1. package com.ht.microservicestudentprovider;
  2.  
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.autoconfigure.domain.EntityScan;
  6. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
  7.  
  8. @EntityScan("com.ht.*.*")
  9. @EnableEurekaClient
  10. @SpringBootApplication
  11. public class MicroserviceStudentProviderApplication {
  12.  
  13. public static void main(String[] args) {
  14. SpringApplication.run(MicroserviceStudentProviderApplication.class, args);
  15. }
  16.  
  17. }

在消费者microservice-student-provider-80的controller中加:

  1. @RequestMapping("/ribbon")
  2. public String ribbon(){
  3. return restTemplate.getForObject(SERVER_IP_PORT+"/student/ribbon/", String.class);
  4. }

生产者microservice-student-providerd controller中加:

  1. @Value("${server.port}")
  2. private String port;
  3.  
  4. @RequestMapping("/ribbon")
  5. public String ribbon(){
  6. return "工号【"+port+"】正在为您服务";
  7. }

我们启动服务后在浏览器中刷新地址

每刷新一次后台就会更改一次服务工号

假如有3个服务提供者,突然挂了一个,那么就会产生1/3的概率访问失败; 所以ribbon给我们提供了一个很好的插件。

在microservicestudentconsumer80的

SpringCloudConfig中 加:

  1. /**
  2. * 自定义调用规则(服务提供者掉线后不再调用,解决轮询问题)
  3. * @return
  4. */
  5. @Bean
  6. public IRule myRule(){
  7. return new RetryRule();
  8. // return new RandomRule();
  9. }

Feign简介及应用

  • 简介

  Feign是一个声明式的Web Service客户端,它使得编写Web Serivce客户端变得更加简单。我们只需要使用Feign来创建一个接口并用注解来配置它既可完成。它具备可插拔的注解支持,包括Feign注解和JAX-RS注解。Feign也支持可插拔的编码器和解码器。Spring Cloud为Feign增加了对Spring MVC注解的支持,还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。

这段话看起来比较懵逼,这里说下实际使用,前面Ribbon调用服务提供者,我们通过restTemplate调用,缺点是,多个地方调用,同一个请求要写多次,不方便统一维护,这时候Feign来了,就直接把请求统一搞一个service作为FeignClient,然后其他调用Controller需要用到的,直接注入service,直接调用service方法即可;同时Feign整合了Ribbon和Eureka,所以要配置负载均衡的话,直接配置Ribbon即可,无其他特殊地方;当然Fiegn也整合了服务容错保护,断路器Hystrix,后面再说。

  • 应用

  在common项目里建一个service(实际项目肯定是多个service)作为Feign客户端,用Feign客户端来调用服务器提供者,当然可以配置负载均衡;Feign客户端定义的目的,就是为了方便给其他项目调用;

修改 microservice-common

pom.xml引入Feign依赖:

  1. <!--引入Feign依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-feign</artifactId>
  5. </dependency>

创建StudentClientService接口:

  1. package com.ht.microservicecommon;
  2.  
  3. import com.ht.microservicecommon.entity.Student;
  4. import org.springframework.cloud.netflix.feign.FeignClient;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.PostMapping;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9.  
  10. import java.util.List;
  11.  
  12. /**
  13. * Student Feign接口客户端
  14. * @author Administrator
  15. *
  16. */
  17. @FeignClient(value="MICROSERVICE-STUDENT")
  18. public interface StudentClientService {
  19.  
  20. /**
  21. * 根据id查询学生信息
  22. * @param id
  23. * @return
  24. */
  25. @GetMapping(value="/student/get/{id}")
  26. public Student get(@PathVariable("id") Integer id);
  27.  
  28. /**
  29. * 查询学生信息
  30. * @return
  31. */
  32. @GetMapping(value="/student/list")
  33. public List<Student> list();
  34.  
  35. /**
  36. * 添加或者修改学生信息
  37. * @param student
  38. * @return
  39. */
  40. @PostMapping(value="/student/save")
  41. public boolean save(Student student);
  42.  
  43. /**
  44. * 根据id删除学生信息
  45. * @return
  46. */
  47. @GetMapping(value="/student/delete/{id}")
  48. public boolean delete(@PathVariable("id") Integer id);
  49.  
  50. @RequestMapping("/student/ribbon")
  51. public String ribbon();
  52. }

  新建一个Feign消费者项目;

参考microservice-student-consumer-80建一个microservice-student-consumer-feign-80

代码都复制一份,包括pom.xml

新项目中需要添加新pom依赖

  1. <!--ribbon相关依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-eureka</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.cloud</groupId>
  8. <artifactId>spring-cloud-starter-ribbon</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.cloud</groupId>
  12. <artifactId>spring-cloud-starter-config</artifactId>
  13. </dependency>
  14.  
  15. <!--引入Feign依赖-->
  16. <dependency>
  17. <groupId>org.springframework.cloud</groupId>
  18. <artifactId>spring-cloud-starter-feign</artifactId>
  19. </dependency>
  20. </dependencies>

SpringCloudconig

  1. package com.ht.microservicestudentconsumerfeign80.config;
  2.  
  3. import com.netflix.loadbalancer.IRule;
  4. import com.netflix.loadbalancer.RandomRule;
  5. import com.netflix.loadbalancer.RetryRule;
  6. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.web.client.RestTemplate;
  10.  
  11. @Configuration
  12. public class SpringCloudConfig {
  13. @LoadBalanced // 引入ribbon负载均衡
  14. @Bean
  15. public RestTemplate getRestTemplate(){
  16. return new RestTemplate();
  17. }
  18. /**
  19. * 自定义调用规则(服务提供者掉线后不再调用,解决轮询问题)
  20. * @return
  21. */
  22. @Bean
  23. public IRule myRule(){
  24. return new RetryRule();
  25. // return new RandomRule();
  26. }
  27. }

Yml文件

  1. server:
  2. port: 80
  3. context-path: /
  4. eureka:
  5. client:
  6. service-url:
  7. defaultZone: http://eureka2001.ht.com:2001/eureka/,http://eureka2002.ht.com:2002/eureka/,http://eureka2003.ht.com:2003/eureka/
  8. register-with-eureka: false

启动类中添加注释

  1. package com.ht.microservicestudentconsumerfeign80;
  2.  
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  6. import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
  7. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
  8. import org.springframework.cloud.netflix.feign.EnableFeignClients;
  9.  
  10. @EnableEurekaClient
  11. @EnableFeignClients(value = "com.ht.*.*")
  12. @SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
  13. public class MicroserviceStudentConsumerFeign80Application {
  14.  
  15. public static void main(String[] args) {
  16. SpringApplication.run(MicroserviceStudentConsumerFeign80Application.class, args);
  17. }
  18.  
  19. }

StudnetConsumerController

  1. package com.javaxl.microservicestudentconsumerfeign80.controller;
  2.  
  3. import com.ht.microservicecommon.StudentClientService;
  4. import com.ht.microservicecommon.entity.Student;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.*;
  7. import org.springframework.web.client.RestTemplate;
  8.  
  9. import java.util.List;
  10.  
  11. @RestController
  12. @RequestMapping("/student")
  13. public class StudentConsumerController {
  14.  
  15. @Autowired
  16. private StudentClientService studentClientService;
  17.  
  18. @Autowired
  19. private RestTemplate restTemplate;
  20.  
  21. @PostMapping(value = "/save")
  22. private boolean save(Student student) {
  23. return studentClientService.save(student);
  24. }
  25.  
  26. @GetMapping(value = "/list")
  27. public List<Student> list() {
  28. return studentClientService.list();
  29. }
  30.  
  31. @GetMapping(value = "/get/{id}")
  32. public Student get(@PathVariable("id") Integer id) {
  33. return studentClientService.get(id);
  34. }
  35.  
  36. @GetMapping(value = "/delete/{id}")
  37. public boolean delete(@PathVariable("id") Integer id) {
  38. try {
  39. studentClientService.delete(id);
  40. return true;
  41. } catch (Exception e) {
  42. return false;
  43. }
  44. }
  45.  
  46. @RequestMapping("/ribbon")
  47. public String ribbon(){
  48. return studentClientService.ribbon();
  49. }
  50. }

因为现在用Fiegn,所以把restTemplate去掉,改成注入service,调用service方法来实现服务的调用;

谢谢观看!!

SpringCloud之Ribbon负载均衡及Feign消费者调用服务的更多相关文章

  1. Ribbon负载均衡及Feign消费者调用服务

    微服务调用Ribbon 简介 前面讲了eureka服务注册与发现,但是结合eureka集群的服务调用没讲. 这里的话 就要用到Ribbon,结合eureka,来实现服务的调用: Ribbon是Netf ...

  2. spring-cloud配置ribbon负载均衡

    spring-cloud配置ribbon负载均衡 ribbon提供的负载均衡就是开箱即用的,简单的不能再简单了 为了顺利演示此demo,你需要如下 需要提前配置eureka服务端,具体看 https: ...

  3. SpringCloud系列——Ribbon 负载均衡

    前言 Ribbon是一个客户端负载均衡器,它提供了对HTTP和TCP客户端的行为的大量控制.我们在上篇(猛戳:SpringCloud系列——Feign 服务调用)已经实现了多个服务之间的Feign调用 ...

  4. 浅谈SpringCloud (三) Ribbon负载均衡

    什么是负载均衡 当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃.为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力. 我们 ...

  5. SpringCloud:Ribbon负载均衡

    1.概述 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端       负载均衡的工具. 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客 ...

  6. 四(2)、springcloud之Ribbon负载均衡

    2.Ribbon负载均衡 ​ Ribbon在工作时分成两步第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server. 第二步再根据用户指定的策略,在从server取到的 ...

  7. Spring-cloud之Ribbon负载均衡的使用及负载均衡策略配置(与Eurka配合使用)

    什么是Ribbon,ribbon有什么用,个人先总结一下(不正确请提出讨论):Ribbon是基于客户端的负载均衡器,为我们提供了多样的负载均衡的方案,比如轮询,最小的并发请求的server,随机ser ...

  8. SpringCloud之Ribbon负载均衡配置

    一.负载均衡解决方案分类及特征 业界主流的负载均衡解决方案有: 1.1 集中式负载均衡 即在客户端和服务端之间使用独立的负载均衡设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责 ...

  9. Spring-Cloud之Ribbon负载均衡-3

    一.负载均衡是指将负载分摊到多个执行单元上,常见的负载均衡有两种方式.一种是独立进程单元,通过负载均衡策略,将请求转发到不同的执行单元上,例如 Ngnix .另一种是将负载均衡逻辑以代码的形式封装到服 ...

随机推荐

  1. pyqt5 + pyinstaller 制作爬虫小程序

    环境:mac python3.7 pyqt5 pyinstaller ps: 主要是熟悉pyqt5, 加入了单选框 输入框 文本框 文件夹选择框及日历下拉框 效果图: pyqt5 主程序文件 # -* ...

  2. js MD5加密与 java MD5加密不一致

    因为该项目会部署到多台机器,所以需要用字符生成唯一的MD5,但是js生成的MD5和java生成的MD5不一致.经过博主查阅资料发现java生成MD5用的是utf-8的编码,而且js用的是2进制.那我就 ...

  3. 最近公司遇到了APR攻击,顺便了解一下知识

    原因及背景 最近公司遇到了APR攻击导致整个公司研发部.测试部.客服部.工程部等几个部门统一无法上网,TV(team viewer)无法使用,部署在公网的B/S架构系统系统无法访问,开发代码上传和下载 ...

  4. OpenFOAM——高空腔内的湍流自然对流

    本算例来自<ANSYS Fluid Dynamics Verification Manual>中的VMFL052: Turbulent Natural Convection Inside ...

  5. Git bash Error: Could not fork child process: There are no available terminals (-1)

    错误信息:Error: Could not fork child process: There are no available terminals (-1) 截图如下: 解决办法: (1)使用cmd ...

  6. 各种系统性能优化技术,采用vilocity实现商品页面静态化

    1.大型门户网站系统:>10万的访问量   行业网站(当当网,卓越网):20万-30万,一个小时内会跟数据库的交互至少20万-30万,会产生数据库瓶颈,每个数据库都有一个最大连接数(socket ...

  7. node.js使用cluster实现多进程

    首先郑重声明: nodeJS 是一门单线程!异步!非阻塞语言! nodeJS 是一门单线程!异步!非阻塞语言! nodeJS 是一门单线程!异步!非阻塞语言! 重要的事情说3遍. 因为nodeJS天生 ...

  8. 关于证书如何完成身份验证(SSL证书)

    一.写在前面 SSL和IPsec是现在VPN技术中最为常见的,在云计算的应用环境中,SSL更受企业青睐,至于原因的话简单的说就是SSL更为简洁,不需要像IPsec那样需要额外安装客户端,这会带来软件维 ...

  9. PHP系列 | ThinkPHP5数据库迁移工具 migration

    了解更多,请关注微信公众号 ThinkPHP5数据库迁移工具 migration 什么是Migration? migration用谷歌翻译是移民的意思,在PHP中我们将它理解为迁移,将Migratio ...

  10. null undefined NaN

    数据类型 6大基本 Number  String Boolean Undefined Null.  Symbol (ES6)   3大引用类型 object array Function Regexp ...