1.最近在学习SpringCloud分布式项目的知识,所以打算把自己学习到的知识也记录下来,为什么选择学习SpringCloud呢?因为分布式框架还有dubbo,如下图应该可以成为我为什么想学习SpringCloud而不是dubbo了。
那Dubbo和SpringCloud有什么区别呢?如下图给出了标准答案:
2.好了,上面的区别我们看到了,那么接下来就是想办法将SpringBoot和SpringCloud整合了,在整合之前有个问题要注意,就是SpringBoot版本的不同也需要整合不同的SpringCloud版本,下面官方网址查看对应的版本:https://start.spring.io/actuator/info,或者:https://blog.csdn.net/ZFD0510/article/details/92839001
"spring-cloud": { "Finchley.M2": "Spring Boot >=2.0.0.M3 and <2.0.0.M5", "Finchley.M3": "Spring Boot >=2.0.0.M5 and <=2.0.0.M5", "Finchley.M4": "Spring Boot >=2.0.0.M6 and <=2.0.0.M6", "Finchley.M5": "Spring Boot >=2.0.0.M7 and <=2.0.0.M7", "Finchley.M6": "Spring Boot >=2.0.0.RC1 and <=2.0.0.RC1", "Finchley.M7": "Spring Boot >=2.0.0.RC2 and <=2.0.0.RC2", "Finchley.M9": "Spring Boot >=2.0.0.RELEASE and <=2.0.0.RELEASE", "Finchley.RC1": "Spring Boot >=2.0.1.RELEASE and <2.0.2.RELEASE", "Finchley.RC2": "Spring Boot >=2.0.2.RELEASE and <2.0.3.RELEASE", "Finchley.SR4": "Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT", "Finchley.BUILD-SNAPSHOT": "Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3", "Greenwich.M1": "Spring Boot >=2.1.0.M3 and <2.1.0.RELEASE", "Greenwich.SR4": "Spring Boot >=2.1.0.RELEASE and <2.1.12.BUILD-SNAPSHOT", "Greenwich.BUILD-SNAPSHOT": "Spring Boot >=2.1.12.BUILD-SNAPSHOT and <2.2.0.M4", "Hoxton.SR1": "Spring Boot >=2.2.0.M4 and <2.2.3.BUILD-SNAPSHOT", "Hoxton.BUILD-SNAPSHOT": "Spring Boot >=2.2.3.BUILD-SNAPSHOT" }
3.下面创建一个dafu-spring-cloud父项目,pom文件为:
<!--父模块名称--> <modelVersion>4.0.0</modelVersion> <groupId>com.example.dafu</groupId> <artifactId>springcloud</artifactId> <version>1.0-SNAPSHOT</version> <name>maven-springcloud</name> <!--全局版本管理--> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <!--SpringCloud全局依赖管理--> <dependencyManagement> <dependencies> <!--cloud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
4.创建eureka服务端,在父项目下面创建一个子项目eureka-services,pom文件为:
<modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>eureka</artifactId> <version>0.0.1-SNAPSHOT</version> <name>maven-eureka</name><!--此name为maven中的模块名--> <description>eureka-services的描述</description> <!--引入父依赖,这里因为dafu-spring-cloud统一管理,所以引入了父依赖--> <parent> <groupId>com.example.dafu</groupId> <artifactId>springcloud</artifactId> <version>1.0-SNAPSHOT</version> </parent> <!--eureka的服务端 --> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
eureka的配置文件我这里使用application.properties(别人都用yml,我比较喜欢priperties):
server.port=8761 spring.application.name=eureka-server eureka.instance.hostname=127.0.0.1 # false代表不向注册中心注册自己 eureka.client.register-with-eureka=false # 是否需要从注册中心检索获取服务的注册信息。默认值为true # 单机版的可设置成false,集群版的由于需要同步其他节点的服务注册数据,故设成true。 eureka.client.fetch-registry=false # 是否开启自我保护模式,默认值true # eureka server默认在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%, # Eureka Server 会将这些实例保护起来,让这些实例不会过期, # 但是在保护期内如果服务刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,此时会调用失败
#设置为false可以确保注册中心中不可用的实例被及时的剔除。
eureka.server.enable-self-preservation=false
# 清理无效节点的时间间隔,缺省 (1000*60)ms
eureka.server.eviction-interval-timer-in-ms=6000
# 当获取不到对应实例时,需要等待的时间,缺省 (1000*60*5)ms
eureka.server.wait-time-in-ms-when-sync-empty=6000
# eureka监控平台地址 eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
eureka启动类添加@EnableEurekaServer即可:
然后启动eureka,访问localhost:8761,会看到eureka启动成功:
5.有了eureka的服务端,接下来我们创建两个客户端provider-services和practice-services,端口号分别是8081和8082,provider-services与practice-services配置文件相同,只区别于端口 然后启动类加@EnableEurekaClient注解即可:
server.port=8081 spring.application.name=provider-server eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka
server.port=8082
spring.application.name=provider-server
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka
pom文件(两个一样,这里写一个就好):
<modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>practice</artifactId> <version>0.0.1-SNAPSHOT</version> <name>maven-practice</name><!--此name为maven中的模块名--> <description>practice-services的描述</description> <!--引入父依赖--> <parent> <groupId>com.example.dafu</groupId> <artifactId>springcloud</artifactId> <version>1.0-SNAPSHOT</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
接下来启动这俩服务,我们看到了控制台信息显示两个服务注册到了eureka:
我们在访问localhost:8761会看到两个服务都注册到了eureka:
6.eureka整合完了,我们的服务注册和发现都可以实现了,这里有个问题就是我们分别去请求两个服务的接口,都可以请求到,并没有统一的访问api,所以我们需要整合gateway,整合gateway之前我们先了解下gateway。
pring Cloud Gateway是由spring官方基于Spring5.0、Spring Boot2.x、Project Reactor等技术开发的网关,目的是代替原先版本中的Spring Cloud Netfilx Zuul,目前Netfilx已经开源了Zuul2.0,但Spring没有考虑集成,而是推出了自己开发的Spring Cloud GateWay。该项目提供了一个构建在Spring Ecosystem之上的API网关,旨在提供一种简单而有效的途径来发送API,可提供请求路由、协议转换、安全认证、服务鉴权、流量控制、日志监控等服务(具体可以查看官网http://spring.io/projects/spring-cloud-gateway)
gateway网关处理流程图如下:
6.1:请求发送到网关,DispatcherHandler是Http请求的中央分发器,将请求匹配到相应的HandlerMapping;
6.2:请求和处理器之间有一个映射关系,网关将会对请求进行路由,handler会匹配 RoutePredicateHandlerMapping,以匹配到对应的Route;
6.3:经过RoutePredicateHandlerMapping处理后,请求会发送到Web处理器,该WebHandler代理了一系列网关过滤器和全局过滤,此时会对请求或者响应头进行处理;
6.4:最后转发到具体的代理服务;
DispatcherHandler--->RoutePredicateHandlerMapping
RoutePredicateHandlerMapping---->FilteringWebHandler
FilteringWebHandler----->DefaultGatewayFilterChain
6.5:Gateway与Zuul:
6.6:接下来创建gateway-services子项目,引入依赖:
<modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <name>maven-gateway</name><!--此name为maven中的模块名--> <description>gateway-services的描述</description> <!--引入父依赖--> <parent> <groupId>com.example.dafu</groupId> <artifactId>springcloud</artifactId> <version>1.0-SNAPSHOT</version> </parent> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
6.7配置文件添加,并且在启动类添加@EnableEurekaClient:
server.port=8765 spring.application.name=gateway-server # 当新加了服务时,不用去配置路由规则和重启网关gateway也能转发 #是否与服务注册于发现组件进行结合,通过 serviceId 转发到具体的服务实例。 # 默认为 false,设为 true 便开启通过服务中心的自动根据 serviceId 创建路由的功能。 spring.cloud.gateway.discovery.locator.enabled=false # 开启小写验证,默认feign根据服务名查找都是用的全大写 spring.cloud.gateway.discovery.locator.lower-case-service-id=true # 注册中心地址 eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka # true将IP注册到Eureka,false将机器的主机名注册到Eureka eureka.instance.prefer-ip-address=true # 设置spring.cloud.gateway.routes,需将spring.cloud.gateway.discovery.locator.enabled改为false # 如果不改的话,localhost:8765/provider-server/controller/index请求服务地址也能正常访问, # 因为这时为每个服务创建了2个router。 # 路由id:自定义。 # 路由uri:从eureka获取服务,且以lb(load-balance)负载均衡方式转发 # 路由断言:Path的predicates,将以/provider/**开头的请求都会转发到uri为lb://provider-server的地址上 # 路由filters:用StripPrefix的filter 在转发之前将/provider去掉 # provider服务 spring.cloud.gateway.routes[0].id=provider-server spring.cloud.gateway.routes[0].uri= lb://provider-server spring.cloud.gateway.routes[0].predicates[0]= Path=/provider/** spring.cloud.gateway.routes[0].filters[0]= StripPrefix=1 # practice服务 spring.cloud.gateway.routes[1].id=practice-server spring.cloud.gateway.routes[1].uri= lb://practice-server spring.cloud.gateway.routes[1].predicates[0]= Path=/practice/** spring.cloud.gateway.routes[1].filters[0]= StripPrefix=1