Springcloud是一款微服务框架,它基于Springboot,可以使用它用来管理纵向拆分的项目,将一个个的小项目变成微服务。下面简单的搭建一个微服务,使用eureka组件实现注册中心,使用ribbon组件实现微服务调用,使用zuul网关实现真实服务地址和访问地址的分离,其他技术后续补充。
springcloud和nginx
前面学习过nginx,它除了可以实现动静分离,还可以实现负载均衡,即可以将项目做成分布式tomcat集群,前端访问可以随机或者按照权重值访问后端服务。但是nginx有一个小缺点,如果单台服务器出现问题、或者需要添加服务器,需要修改conf.xml配置文件,或某台服务器出现问题如何容错等,ngnix是无法实现。简单来说它缺少管理者的因子,需要人为''介入'',在这种情况下,springcloud就可以弥补nginx的不足,它不仅仅可以实现分布式,负载均衡,并且对微服务有管理、容错、监听的能力。
springcloud
springcloud是spring家族的一员,它是一个微服务框架,用在大型分布式应用的开发,官网:https://spring.io/projects/spring-cloud,除了springcloud外,其他比较出名的微服务框架还有dubbo。
如果一个项目比较小,直接使用springboot,或者ssm做成单体项目就可以,但是如果一个项目比较大,就需要考虑到拆分,比较常见的就是横向拆分和纵向拆分。
(1)纵向拆分:大项目分成很多小项目,如电商网站的登录注册系统、商品系统、秒杀系统、搜索系统、购物车系统等,都是拆分后的小项目,这就是纵向拆分。
(2)横向拆分:一个纵向拆分后的项目,也可以继续拆分,如有人专门做控制层,有人做业务层,这就是横向拆分。
springcloud是如何对拆分后的项目进行管理的呢,这就需要用到它的关键组件,这里暂时先记录eureka、ribbon和zuul三种组件,其他组件如config、feign和hystrix后续单独补充。
(1)eureka:服务治理组件,利用它的注册和发现机制,实现整体微服务的管理,提供其他服务注册,并可以发现其他服务,springcloud只提供了一种这种治理组件。
(2)ribbon:通过eureka发现机制,可以负载均衡、随机或者根据权重来调用其他提供服务的组件。
(3)zuul:网关组件,唯一对外暴露接口地址的组件,实现外界访问地址和内部请求地址的分离,对外影藏了真实的地址。
下面使用一下这几个组件。
eureka
整个springcloud的核心组件之一,它就像一个''管理者'',利用自己的注册和发现的能力,来管理着一批注册在它身上的微服务。即其他服务可以注册在eureka注册中心,它管理着一批这样的已经注册的微服务,并对外提供服务,同时注册中心会将其他服务注册的信息保存到本地,通过定时更新来维护和其他服务的关系。简单来说注册中心就像''工商局'',各种公司之类的服务提供者都在这里注册,完了就可以对外提供服务了。
a.搭建eureka注册中心
使用IDEA,搭建一个eureka注册中心,搭建是基于springboot,需要利用springboot的自动配置和'约定大于配置'的特点,来配合springcloud简化搭建过程,注意两者版本的兼容,可以参考文末博客。
(1)pom文件导入springboot父pom、以及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> <groupId>com.boe</groupId> <artifactId>Eureka-server01</artifactId> <version>1.0-SNAPSHOT</version> <name>Eureka-server01</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <!--使用springboot的资源,结构特性。另外使用springcloud的所有依赖环境--> <!-- 基于springboot,继承springboot-parent,引入springboot的父pom文件 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!--1.5.9是稳定版本--> <version>1.5.9.RELEASE</version> </parent> <!--导入springcloud的父pom资源,声明式依赖,子工程手动导入时就导包,不导入就不导入包--> <dependencyManagement> <dependencies> <!--导入springcloud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <!--注意通过坐标找到的spring-cloud-dependencies-Edgware.RELEASE.pom文件中,打包方式为pom,因此需要这里type为pom--> <type>pom</type> <!--maven scope方式常用有很多种,默认为compile,还有test、provided、system等--> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!--以上两步,完成继承父springboot pom依赖,并导入springcloud的依赖管理--> <dependencies> <!--引入eureka注册中心的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <!--建议使用下面的artifactId--> <!--<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>--> </dependency> <!-- spring-boot-starter-web 已经在eureka-server中传递,因此这里不需要配置springboot的starter-web--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!--springboot运行jar包的插件,可以直接使用java -jar jar包名来运行springboot--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!--指定jar包运行的main class--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <!--<configuration>--> <!--<archive>--> <!--<manifest>--> <!--<addClasspath>true</addClasspath>--> <!--<mainClass>com.StarterEurekaServer</mainClass> <!– 此处为主入口–>--> <!--</manifest>--> <!--</archive>--> <!--</configuration>--> </plugin> </plugins> </build> </project>
(2)资源目录下添加application.properties文件,添加服务端口、服务名、注册eureka中心地址等信息。
# 端口
server.port=8088
# 客户端通过ip底层注册
# eureka.client.prefer-ip-address=true
eureka.client.preferIpAddress=true
#暂时先关闭,当前注册中心作为客户端
# 在注册中心本身,使得具有注册和发现的能力,如果要实现HA,需要改成true,这样就会访问注册中心的接口
eureka.client.regist-with-eureka=false
# 关闭发现抓取注册信息的能力
eureka.client.fetch-registry=false
# 注册中心的地址,http请求的接口
eureka.client.serviceUrl.defaultZone=http://localhost:8088/eureka
# 当前工程提供一个服务名称,相同功能的工程创建集群,都是一个名称,以当前服务名为key保存在当前服务的所有节点信息的map对象中
# 如果是同一个name,就可以创建HA高可用
spring.application.name=eureka-server
# 可以关闭自我保护,没有收到续约,就从注册中心剔除服务
# eureka.server.enable-self-preservation=false
(3)写一个启动类,来启动注册中心,需要使用@EnableEurekaServer注解,来表名启动的是一个注册中心服务类。
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * eureka server启动类 */ @SpringBootApplication @EnableEurekaServer public class StarterEurekaServer { public static void main(String[] args) { SpringApplication.run(StarterEurekaServer.class,args); System.out.println("I am eureka server01"); } }
(4)启动后,访问注册中心地址localhost:8088,就可以查看注册中心注册的实例,这里有一个就是eureka服务自己本身,以后如果有注册的服务,都能在这里查看。
b.搭建一个微服务并注册
Eureka注册中心搭建起来后,接下里搭建一个微服务并注册在Eureka注册中心,并使用它提供的服务。
(1)pom文件与上面类似,这次搭建的是服务提供者,因此引入eureka客户端依赖(spring-cloud-starter-eureka)就可以。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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> <groupId>com.boe</groupId> <artifactId>Client01</artifactId> <version>1.0-SNAPSHOT</version> <name>Client01</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <!--使用springboot的资源,结构特性。另外使用springcloud的所有依赖环境--> <!-- 基于springboot,继承springboot-parent,引入springboot的父pom文件 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <!--导入springcloud的父pom资源--> <dependencyManagement> <dependencies> <!--导入springcloud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.RELEASE</version> <!--注意通过坐标找到的spring-cloud-dependencies-Edgware.RELEASE.pom文件中,打包方式为pom,因此需要这里type为pom--> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!--以上两步,完成继承父springboot pom依赖,并导入springcloud的依赖--> <dependencies> <!--引入eureka客户端依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!-- spring-boot-starter-web 已经在eureka-server中传递,因此这里不需要配置springboot的starter-web--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!--springboot运行jar包的插件--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
(2)application.properties文件指定服务的端口号、服务名以及注册的中心地址url等信息。
# 客户端端口
server.port=9088
# 客户端通过ip底层注册
# eureka.client.prefer-ip-address=true
eureka.client.preferIpAddress=true
# eureka-client的注册,和发现功能需设置为true,默认为true,也可以不用设置
eureka.client.regist-with-eureka=true
# 发现抓取注册信息的内容
eureka.client.fetch-registry=true
# 定义服务名称
spring.application.name=service-hi
# 注册中心的地址
eureka.client.serviceUrl.defaultZone=http://localhost:8088/eureka
(3)写一个启动类,类似注册中心的启动类,只是注解需要修改成@EnableEurekaClient,这样的服务只有注册和发现的能力,不具备管理的能力。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * Eureka client服务提供者启动类 */ @SpringBootApplication @EnableEurekaClient public class StarterEurekaClient { public static void main(String[] args) { SpringApplication.run(StarterEurekaClient.class,args); System.out.println("I am client01"); } }
(4)写个controller层的测试类,访问这个地址可以返回信息,如果能正常访问到,说明注册后的服务能正常使用。
package com.boe.Controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { //可以通过@Value注解,获取application.properties里的参数 @Value("${server.port}") private String port; //写一个测试方法 @RequestMapping("hello") public String test(String name){ return "I am "+name+", and I come form "+port; } }
(5)访问发现可以正常返回测试信息,并且注册中心页面也增添了一条注册信息,这样就实现了微服务的注册并提供服务的功能。
c.高可用eureka注册中心
高可用是分布式集群必不可少的一个特点,当其中一个节点宕机后,不影响整体的功能。eureka注册中心不仅对外可以提供服务注册,同时自己也作为注册微服务,可以注册在另外一台eureka注册中心,利用这个特点可以配置eureka高可用集群,这里配置3台eureka注册中心,实现集群HA服务。
eureka01注册到eureka02和eureka03,其他依次类推,这样完成注册后,每个eureka服务中心从对方抓得到的服务map信息就一致了,因为服务名一致,会纳入一个服务来管理,实现HA高可用。
想实现如上高可用,在IDEA当前工程下再添加两个Module,再修改application.properties文件 ,就可以实现,以eureka server01为例,需修改eureka.client.regist-with-eureka=true,使其具备注册的能力,同时修改eureka.client.fetch-registry=true,使其具备发现抓取注册的能力。另外eureka.client.serviceUrl.defaultZone写另外两台注册中心的地址,这样三台启动后就可以实现高可用。
# 端口
server.port=8088
# 客户端通过ip底层注册
# eureka.client.prefer-ip-address=true
eureka.client.preferIpAddress=true
#暂时先关闭,当前注册中心作为客户端
# 在注册中心本身,使得具有注册和发现的能力,如果要实现HA,需要改成true,这样就会访问注册中心的接口
eureka.client.regist-with-eureka=true
# 关闭发现抓取注册信息的内容
eureka.client.fetch-registry=true
# 注册中心的地址,http请求的接口,发现另外一个server的端口,实现HA高可用
eureka.client.serviceUrl.defaultZone=http://localhost:8089/eureka,http://localhost:8090/eureka
# 当前工程提供一个服务名称,相同功能的工程创建集群,都是一个名称,以当前服务名为key保存在当前服务的所有节点信息的map对象中
# 如果是同一个name,就可以创建HA高可用
spring.application.name=eureka-server
# 可以关闭自我保护,没有收到续约,就剔除服务
# eureka.server.enable-self-preservation=false
刚开始启动由于先后顺序,控制台会报错,这是正常的,因为先启动的服务可能找不到另外两台的(还在启动中),导致连接拒绝,以及找不到server的报错。
修改客户端的application.properties,添加另外两台注册中心的地址后,测试也可以访问到服务,停掉其中一台注册中心,发现依然可以使用client提供的服务,这样就实现了eureka注册中心的HA高可用。
d.eureka注册信息的结构和相关机制
eureka注册信息的结构为一个双层map,上面注册中心的UI界面展示了部分map的内容,它由如下几部分组成。
(1)第一层key为服务名,即上面的eureka-server或者service-hi,这是在application.properties文件中通过spring.application.name定义的。第一层value为一个map,记录注册的实例信息。
(2)第二层key为固定结构,即上面的youngchaolinmac:eureka-server:8090等,由系统用户名:服务名:端口号组成,第二层value为注册的实例对象,包含它的详细信息,如ip地址、端口、注册和续约的事件戳等信息。
相关的机制,有注册、续约、服务剔除和保护机制等。
(1)注册:服务提供者,如上面的client,启动服务后会根据注册中心的地址,携带自己的信息,通过http协议访问注册中心,注册中心接收到服务提供者的信息后保存在注册中心。
(2)续约:服务提供者每隔30s,会给注册中心发送一个''心跳'',告知自己的实例对象是存活的,否则注册中心会剔除死亡或不活跃的服务节点。
(3)剔除:注册中心每隔60s,会检查一次实例对象中的续约时间戳(保存在双层map中的第二层,在value中),如果超过90s没有续约,会将当前实例对象从第二层map中剔除,这样UI的Status下就会少一个实例对象。
(4)保护:集群的服务是很多的,会出现某个服务尽管续约了,但是由于网络或者通信的问题导致续约判断的失误从注册中心被剔除掉,如果大面积的出现这种情况会导致集群服务的瘫痪。为了避免这种情况的发生,springcloud提供了保护机制,即如果同一时间如果因为超时剔除的服务超过整体服务的15%以上,会被认为是非正常剔除,这样剔除不会实现,会保持集群服务原有的的状态。这种保护机制默认是开启的,也可以在application.properties中设置为关闭,即将eureka.server.enable-self-presevation=false来关闭。
ribbon
ribbon组件可以实现服务调服务, 需要引入RestTemplate来支持,它是一个客户端组件,会抓取在注册中心注册的服务信息,将其整理并保存,然后访问后端服务(上文的client)时会进行拦截,通过从spring容器中获取的负载均衡规则IRule对象,来实现对后端服务的访问逻辑。
为了实现ribbon的功能,需要提前准备2个client,上面已经准备了一个client,再需准备一个。另外还需要准备一个配置了ribbon的组件。
(1)准备一个新的client,当前工程下增添一个Module,修改端口号即可,其他无需修改,这里修改成了9089。
# 客户端端口
server.port=9089
# 客户端通过ip底层注册
# eureka.client.prefer-ip-address=true
eureka.client.preferIpAddress=true
# eureka-client的注册,和发现功能需设置为true,默认为true,也可以不用设置
eureka.client.regist-with-eureka=true
# 发现抓取注册信息的内容
eureka.client.fetch-registry=true
# 定义服务名称
spring.application.name=service-hi
# 注册中心的地址
eureka.client.serviceUrl.defaultZone=http://localhost:8088/eureka,http://localhost:8089/eureka,http://localhost:8090/eureka
(2)准备一个具有ribbon的服务组件,新建一个Module,注意pom文件需要添加ribbon的依赖,其他跟client的配置类似,另外ribbon服务组件的端口在application.properties文件中修改为8105,其他参考client的设置。
<!--引入ribbon依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency>
(3)ribbon服务组件,添加启动类,启动类中使用@Bean返回一个RestTemplate对象,交给spring来管理,因为启动类注解@SpringBootApplication底层有@SpringBootConfiguration,这个配置类的下面又是@Configuration,因此启动类也可以作为配置类来使用,在其中配置一个bean。
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /** * 具有ribbon组件的服务启动类 */ @SpringBootApplication @EnableEurekaClient public class StarterEurekaRibbon { public static void main(String[] args) { SpringApplication.run(StarterEurekaRibbon.class,args); } //使用restTemplate实现ribbon对客户端的拦截逻辑 @Bean("restTemplate") @LoadBalanced //不加会访问不到其他微服务,提示找不到服务名,尽管有这个服务名的服务在运行着 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
(4)ribbon服务组件添加controller层和service层,在service层实现对请求的拦截,service层方法访问的是一个服务名,而不是具体的请求地址。因为这个服务能获取到注册中心其他服务的信息,将client对应的注册信息抓取过来,通过service-hi,就能获取到对应的双层map的第二层map的value,通过value里保存的ip、端口等信息,实现对真实服务的访问。
controller层
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.boe.Controller; import com.boe.Service.RibbonService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class RibbonController { @Autowired RibbonService ribbonService=null; //访问ribbon服务的地址 @RequestMapping("helloribbon") public String test(String name){ return "Ribbon work, "+ribbonService.hello(name); } }
service层
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.boe.Service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class RibbonService { @Autowired RestTemplate restTemplate=null; //需要调用RestTemplate,通过服务名来实现对服务的访问,默认轮询 public String hello(String name) { return restTemplate.getForObject("http://service-hi/hello?name="+name,String.class); } }
(5)最后启动新添的client服务和有ribbon组件的服务,启动后正常均在注册中心注册。
(6)通过有ribbon组件的服务来访问client的服务,实现服务调服务,默认情况下是轮询的方式,当我多次访问如下地址后,会轮流出现9088和9089,说明访问的服务是轮流来的,也可以根据需求修改成其他的策略,需要在启动类中再添加如下代码。
//自定义负载均衡-随机,还有其他的选择 //需要配置bean,交给spring管理,如果ribbon组件在启动时会检测这个bean是否存在 //如果不存在,就默认轮询 @Bean public IRule initRandom(){ return new RandomRule();//返回随机 //return new RoundRobinRule();//返回负载轮询方式 //return WeightedResponseTimeRule();//根据响应时间,返回对应大小权重值的方式,响应快权重值高,响应慢则权重值低 }
访问有ribbon组件的服务,通过访问localhost:8105/helloribbon?name=messi,内部调用服务实际访问localhost:9089/hello?name=messi,实现了访问地址和真实服务地址的分离,向用户隐藏了真实的访问地址,这样显然更加的安全。
zuul
前面的ribbon可以实现服务调用服务, 其实springcloud已经提供了一个服务组件来完成上述的功能,那就是zuul网关,它底层就是基于ribbon和RestTemplate来实现,外界是不能直接访问后端提供的服务,需要通过zuul网关暴露的接口来实现访问,通过zuul的路由规则,通过访问的地址匹配到真实的地址后,再实现内部转发从而实现访问。
zuul网关一般配置在nginx,首先先通过nginx先过滤了一次地址,通过proxy_pass先转发到网关,网关再过滤一次,最后达到真的访问地址,如下图所示,下面按照下图的地址来实际配置一下。
(1)新增一个zuul服务,在IDEA中添加一个Module,pom文件参考前面的client,在此基础上增加zuul的依赖。
<!--引入zull依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
(2)配置application.properties文件,需添加zuul网关服务端口8108,并配置zuul.routes.test.path=/zuul-hi/**,以及zuul.routes.test.service-id=service-hi,这俩个配置是根据上图的地址来的,后续再分析。
# 网关端口
server.port=8108
# 客户端通过ip底层注册
# eureka.client.prefer-ip-address=true
eureka.client.preferIpAddress=true
# eureka-client的注册,和发现功能需设置为true,默认为true,也可以不用设置
eureka.client.regist-with-eureka=true
# 发现抓取注册信息的内容
eureka.client.fetch-registry=true
# 定义服务名称
spring.application.name=service-zull
# 注册中心的地址,两个server都需要配,用逗号隔开
eureka.client.serviceUrl.defaultZone=http://localhost:8088/eureka,http://localhost:8089/eureka,http://localhost:8090/eureka
# 配置zull网关
# 配置网关地址,**代表可以匹配多级目录
# 提供路由服务,通过不同的地址可以访问不同的服务
# 网关只会暴露使用的地址,具体的真实地址是隐藏的,因此网关如果宕机,外界将不能访问资源
# 因此网关可以通过nginx配置负载均衡
# zuul.routes.test.path里的test是路由名称
zuul.routes.test.path=/zuul-hi/**
# 匹配application name
zuul.routes.test.service-id=service-hi
(3)添加zuul网关启动类,注意需要添加@EnableZuulProxy的注解。
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import javax.swing.*; /** * zuul网关服务启动类 */ @SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class StarterEurekaZull { public static void main(String[] args) { SpringApplication.run(StarterEurekaZull.class,args); System.out.println("zuul网关启动"); } }
(4)查看是否在注册中心注册zull服务,ok。
(5)配置nginx,实现第一层过滤,让外界访问的地址转发到网关地址,在nginx.conf目录下添加如下内容,并使用nginx -t查看是否配置正确,ok后使用nginx -s reload加载配置文件。
# zuul网关测试新增server
server {
listen 8080;
# 需修改/etc/hosts文件,添加对www.test.com的本地解析
server_name www.test.com;
location /hellokitty {
proxy_pass http://127.0.0.1:8108/zuul-hi/hello/;
}
}
(6)测试通过www.test.com:8080/hellokitty?name=messi来访问,发现可以访问到前面类似ribbon的访问效果。
为啥通过如上配置就可以访问到了真实的地址,下面简单分析下。
a.首先访问www.test.com:8080/hellokitty?name=messi,会被nginx拦截,由于匹配到hellokitty,会转发到新的地址http://127.0.0.1/zuul-hi/hello?name=messi
b.zuul网关服务接受到http://127.0.0.1/zuul-hi/hello?name=messi地址后,匹配到zuul.routes.test.path=/zuul-hi/**里的zuul-hi(**代表多级任意字符串),会截取变成hello?name=messi
c.然后根据zuul.routes.test.service-id=service-hi,将访问地址变成http://service-hi/hello?name=messi,而service-hi就是服务名,真实地址最后匹配后变成http://localhost:9088/hello?name=messi或者http://localhost:9089/hello?name=messi。
这样就实现了对真实地址的访问了,通过zuul配置在nginx,实现对外访问地址和真实地址分开,zuul是唯一的访问服务的入口,单台挂掉就会出现后端无法访问的可能,因此其需要在nginx配置集群,上面只配置了一个zuul服务,可以多开启几个zuul服务,然后在nginx通过upstream来转发到多个zuul服务,就可以实现zuul网关的集群,这里不展示了。
另外,有了zuul网关后,如果想往集群添加服务,就会被zuul网关自动获取到,无需向nginx那样需要修改配置文件再重新加载才能识别,服务添加后通过访问zuul网关提供的接口,可以访问到新增的服务,这样可以做到动态扩容,同理也可以动态缩容,这里暂不展示了。
以上就是springcloud入门的整理,后续继续补充。
参考博文
(1)https://www.cnblogs.com/zhuwenjoyce/p/10261079.html springboot和springcloud版本对照
(2)https://segmentfault.com/a/1190000019294598 mac下nginx使用