远程调用流程

Spring Cloud 在接口调用上,大致会经过如下几个组件配合:
1、Nacos 服务注册
2、Feign 服务调用
3、Hystrix 熔断器
4、Ribbon 负载均衡
5、Http Client
6、GateWay网关用于请求转发

Spring Cloud相关的基础服务组件
服务发现——Netflix Eureka (Nacos
服务调用——Netflix Feign
熔断器——Netflix Hystrix
服务网关——Spring Cloud GateWay (这里主要是请求转发)
分布式配置——Spring Cloud Config (Nacos
消息总线 —— Spring Cloud Bus (Nacos

个人理解:网关解决从客户端(如8080端口)进入服务端时调用哪个微服务的问题(请求转发功能),Feign解决各微服务之间的相互调用问题


具体交互流程上,如下图所示:

(1)接口化请求调用当调用被@FeignClient注解修饰的接口时,在框架内部,将请求转换成Feign的请求实例feign.Request,交由Feign框架处理。

(2)Feign :服务调用。转化请求Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,封装了Http调用流程。

(3)Hystrix:熔断不能调用到的Feign请求。熔断处理机制 Feign的调用关系,会被Hystrix代理拦截,对每一个Feign调用请求,Hystrix都会将其包装成HystrixCommand,参与Hystrix的流控和熔断规则。如果请求判断需要熔断,则Hystrix直接熔断,抛出异常或者使用FallbackFactory返回熔断Fallback结果;如果通过,则将调用请求传递给Ribbon组件。

(4)Ribbon:负载均衡进行请求平均分发。服务地址选择当请求传递到Ribbon之后,Ribbon会根据自身维护的服务列表,根据服务的服务质量,如平均响应时间,Load等,结合特定的规则,从列表中挑选合适的服务实例,选择好机器之后,然后将机器实例的信息请求传递给Http Client客户端,HttpClient客户端来执行真正的Http接口调用;

(5)HttpClient :Http客户端,真正执行Http调用根据上层Ribbon传递过来的请求,已经指定了服务地址,则HttpClient开始执行真正的Http请求

一、Nacos注册中心

Nacos官方文档:https://nacos.io/zh-cn/docs/what-is-nacos.html

介绍安装

1.注册中心介绍

  1. Eureka(原生,2.0遇到性能瓶颈,停止维护)
  2. Zookeeper(支持,专业的独立产品。例如:dubbo)
  3. Consul(原生,GO语言开发)
  4. Nacos
    相对于 Spring Cloud Eureka 来说,Nacos 更强大。
    Nacos = Spring Cloud Eureka + Spring Cloud Config
    Nacos 可以与 Spring,Spring Boot,Spring Cloud 集成,并能代替 Spring Cloud Eureka,Spring Cloud Config
    通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。

Nacos是以服务为主要服务对象的中间件,Nacos支持所有主流的服务发现、配置和管理。

Nacos主要提供以下四大功能:
1.服务发现和服务健康监测
2.动态配置服务
3.动态DNS服务
4.服务及其元数据管理

Nacos结构图

2.Nacos安装

下载地址:https://github.com/alibaba/nacos/releases

Windows系统
下载版本:nacos-server-1.1.4.tar.gz或nacos-server-1.1.4.zip(不限制,非test测试版本即可),解压任意目录即可

找到运行的文件startup.cmd双击即可运行
访问Nacos
访问:http://localhost:8848/nacos
用户名密码:nacos/nacos

项目整合

1.引入依赖

在生产者和消费者的父类的pom文件中导入依赖

<!--服务注册-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2.进行配置

在要注册的服务的配置文件中的application进行配置Nacos地址

# 服务名-会在注册中心中进行显示,-不能为——下划线
spring.application.name=service-edu
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

3.添加注解

在需要注册的启动类上面添加注解

@EnableDiscoveryClient//Nacos注册

4.注册的实例代码

R为返回的数据的统一格式,自行修改

package com.athly.vod.controller;import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.DeleteVideoRequest;
import com.aliyuncs.vod.model.v20170321.GetVideoPlayAuthRequest;
import com.aliyuncs.vod.model.v20170321.GetVideoPlayAuthResponse;
import com.athly.commonutils.R;
import com.athly.servicebase.exceptionhandler.ForestException;
import com.athly.vod.Utils.ConstantVodUtils;
import com.athly.vod.Utils.InitVodCilent;
import com.athly.vod.service.VodService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.util.List;
@RestController
@RequestMapping("/eduvod/video")
//@CrossOrigin
public class VodController {@Autowiredprivate VodService vodService;//根据视频id删除阿里云视频@DeleteMapping("removeAlyVideo/{id}")public R removeAlyVideo(@PathVariable String id) {try {//初始化对象DefaultAcsClient client = InitVodCilent.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET);//创建删除视频request对象DeleteVideoRequest request = new DeleteVideoRequest();//向request设置视频idrequest.setVideoIds(id);//调用初始化对象的方法实现删除client.getAcsResponse(request);return R.ok();}catch(Exception e) {e.printStackTrace();throw new ForestException(20001,"删除视频失败");}}
}

5.启动服务

1.启动注册中心
2.启动已注册的微服务,可以在Nacos服务列表中看到被注册的微服务

二、Feign服务调用

Feign基本概念

  • Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
  • Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
  • Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
  • Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
  • Spring Cloud Feign帮助我们定义和实现依赖服务接口的定义。在Spring Cloud feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。

项目整合

1.引入依赖

在生产者和消费者的父类的pom文件中导入依赖

<!--服务调用-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.添加注解

在调用端服务启动类添加注解

@EnableFeignClients //服务调用

3.创建包和interface 接口

在服务端创建interface,使用注解指定调用服务名称,定义调用的方法路径

创建client包
@FeignClient注解用于指定从哪个服务中调用功能 ,名称与被调用的服务名保持一致。
@GetMapping注解用于对被调用的微服务进行地址映射。
@PathVariable注解一定要指定参数名称,否则出错
@Component注解防止,在其他位置注入CodClient时idea报错

package com.guli.edu.client;@FeignClient("service-vod")//指定从哪个服务中调用功能,service-vod为被调用者在application配置文件中的名字
@Component//交给Spring管理
public interface VodClient {//定义方法的路径,需要为完全路径(包括类路径)@DeleteMapping(value = "/eduvod/vod/video/{videoId}")public R removeVideo(@PathVariable("videoId") String videoId);//@PathVariable注解一定要指定参数名称,否则出错//R为返回的数据的统一格式,自行修改
}

4.进行调用

 //注入Client@Autowiredprivate VodClient vodClient;//删除小节@DeleteMapping("{id}")public R deleteVideo(@PathVariable String id) {EduVideo eduVideo = videoService.getById(id);String videoSourceId = eduVideo.getVideoSourceId();if(!StringUtils.isEmpty(videoSourceId)) {//根据视频id,远程调用实现视频删除//R为返回的数据的统一格式,自行修改R result = vodClient.removeAlyVideo(videoSourceId);if(result.getCode() == 20001) {throw new ForestException(20001,"删除视频失败,熔断器...");}}videoService.removeById(id);return R.ok();}

三、Hystrix熔断器

Hystrix基本概念

Hystrix 是一个供分布式系统使用,提供延迟和容错功能,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。

比如系统中有很多服务,当某些服务不稳定的时候,使用这些服务的用户线程将会阻塞,如果没有隔离机制,系统随时就有可能会挂掉,从而带来很大的风险。SpringCloud使用Hystrix组件提供断路器、资源隔离与自我修复功能。下图表示服务B触发了断路器,阻止了级联失败

项目整合

1.添加依赖

     <!--ribbon负载均衡依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency><!--hystrix依赖,主要是用  @HystrixCommand --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>

2.进行配置

在调用端配置文件中添加hystrix配置

#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000

3.实现client接口

client包里面创建熔断器,实现client接口中的方法

@Component
public class VodFileDegradeFeignClient implements VodClient {//出错之后会执行的方法@Overridepublic R removeVideo(String videoId) {//输出随便写return R.error().message("time out");}@Overridepublic R removeVideoList(List videoIdList) {return R.error().message("time out");}
}

4.修改Client接口的注解

修改Client接口的注解,添加fallback =实现类

//fallback 里面加上实现类的class,表示熔断之后执行哪里的方法
@FeignClient(name = "service-vod", fallback = VodFileDegradeFeignClient.class)

四、GateWay网关

1.网关基本概念

客户端和服务端中间的一堵墙,可以起到的作用有:请求转发、负载均衡、权限控制等等

个人理解:网关解决从客户端(如8080端口)进入服务端时调用哪个微服务的问题(请求转发功能),Feign解决各微服务之间的相互调用问题

API网关介绍
API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  1. 客户端会多次请求不同的微服务,增加了客户端的复杂性。
  2. 存在跨域请求,在一定场景下处理相对复杂。
  3. 认证复杂,每个服务都需要独立认证。
  4. 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
  5. 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。

以上这些问题可以借助 API 网关解决。

API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。
也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性。

2.什么是Gateway网关

Spring Cloud Gateway核心概念
网关提供API全托管服务,丰富的API管理功能,辅助企业管理大规模的API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等功能。

一般来说网关对外暴露的URL或者接口信息,我们统称为路由信息

如果研发过网关中间件或者使用过Zuul的人,会知道网关的核心是Filter以及Filter Chain(Filter责任链)。Sprig Cloud Gateway也具有路由和Filter的概念。

Spring Cloud Gateway中几个重要的概念

  1. 路由:路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配
  2. 断言:匹配的规则。Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于httprequest中的任何信息,比如请求头和参数等。
  3. 过滤器:一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理

3.网关实现流程

  1. 客户端发送请求先到网关
  2. 将网关服务和其它要访问的服务在注册中心进行注册
  3. 通过网关访问到注册的其它服务


    GateWay Handler Mapping:访问之后做映射(路径)匹配
    GateWay Web Handler:处理匹配
    Filter:过滤器,实现权限管理、跨域等

项目整合

1.Gateway网关使用

1.引入依赖
在api_gateway中引入依赖

<!--nacos注册中心-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency><!--Gateway网关依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency><!--gson-->
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId>
</dependency><!--服务调用-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.编写配置文件
properties写法

# nacos中注册的服务名
spring.application.name=service-gateway# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848#使用服务发现路由,服务调用
spring.cloud.gateway.discovery.locator.enabled=true
#服务路由名小写
#spring.cloud.gateway.discovery.locator.lower-case-service-id=true#设置路由id,下标从[0]开始
#理论随便写,建议写服务的名字
spring.cloud.gateway.routes[0].id=service-acl
#设置路由的url
#格式lb://+nacos中注册的服务名
spring.cloud.gateway.routes[0].uri=lb://service-acl
#设置路由断言(匹配规则),代理servicerId为auth-service的/auth/路径
#格式Path=
spring.cloud.gateway.routes[0].predicates= Path=/*/acl/**spring.cloud.gateway.routes[1].id=service-edu
spring.cloud.gateway.routes[1].uri=lb://service-edu
spring.cloud.gateway.routes[1].predicates= Path=/eduservice/**

yml写法

server:port: 8222spring:application:cloud:gateway:discovery:locator:enabled: trueroutes:- id: service-acluri: lb://service-aclpredicates:- Path=/*/acl/** # 路径匹配- id: service-eduuri: lb://service-edupredicates:- Path=/eduservice/** # 路径匹配nacos:discovery:server-addr: 127.0.0.1:8848

3.启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(ApiGatewayApplication.class, args);}
}

4.测试

  1. 启动nacos,启动Gateway,启动需要调用的服务
  2. 打开naocs,地址:http://localhost:8848/nacos,默认账号密码都为nacos
  3. 点开服务列表检查Gateway等服务是否注册到nacos
  4. 先通过原服务端口号访问,然后通过网关端口号访问

2.工具类

1.跨域配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;@Configuration
public class CorsConfig {@Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedMethod("*");config.addAllowedOrigin("*");config.addAllowedHeader("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**", config);return new CorsWebFilter(source);}
}

2.全局Filter
统一处理会员登录与外部不允许访问的服务

import com.google.gson.JsonObject;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.nio.charset.StandardCharsets;
import java.util.List;@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {private AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();String path = request.getURI().getPath();//api接口,校验用户必须登录if(antPathMatcher.match("/api/**/auth/**", path)) {List<String> tokenList = request.getHeaders().get("token");if(null == tokenList) {ServerHttpResponse response = exchange.getResponse();return out(response);} else {//                Boolean isCheck = JwtUtils.checkToken(tokenList.get(0));
//                if(!isCheck) {ServerHttpResponse response = exchange.getResponse();return out(response);
//                }}}//内部服务接口,不允许外部访问if(antPathMatcher.match("/**/inner/**", path)) {ServerHttpResponse response = exchange.getResponse();return out(response);}return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}private Mono<Void> out(ServerHttpResponse response) {JsonObject message = new JsonObject();message.addProperty("success", false);message.addProperty("code", 28004);message.addProperty("data", "鉴权失败");byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);DataBuffer buffer = response.bufferFactory().wrap(bits);//response.setStatusCode(HttpStatus.UNAUTHORIZED);//指定编码,否则在浏览器中会中文乱码response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return response.writeWith(Mono.just(buffer));}
}

3.异常处理

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;import java.util.Collections;
import java.util.List;@Configuration
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ErrorHandlerConfig {private final ServerProperties serverProperties;private final ApplicationContext applicationContext;private final ResourceProperties resourceProperties;private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public ErrorHandlerConfig(ServerProperties serverProperties,ResourceProperties resourceProperties,ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer,ApplicationContext applicationContext) {this.serverProperties = serverProperties;this.applicationContext = applicationContext;this.resourceProperties = resourceProperties;this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes,this.resourceProperties,this.serverProperties.getError(),this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());return exceptionHandler;}
}

8.返回

package com.athly.gateway.handler;import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.web.reactive.function.server.*;import java.util.HashMap;
import java.util.Map;/*** 自定义异常处理* <p>异常时用JSON代替HTML异常信息<p>*/
public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,ErrorProperties errorProperties, ApplicationContext applicationContext) {super(errorAttributes, resourceProperties, errorProperties, applicationContext);}/*** 获取异常属性*/@Overrideprotected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {Map<String, Object> map = new HashMap<>();map.put("success", false);map.put("code", 20005);map.put("message", "网关失败");map.put("data", null);return map;}/*** 指定响应处理方法为JSON处理的方法* @param errorAttributes*/@Overrideprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);}/*** 根据code获取对应的HttpStatus* @param errorAttributes*/@Overrideprotected int getHttpStatus(Map<String, Object> errorAttributes) {return 200;}
}

Spring Cloud远程服务调用相关推荐

  1. Spring Cloud Feign调用令牌携带问题

    Spring Cloud Feign调用令牌携带问题 微服务项目中模块之间的调用,检测令牌的合法性问题不可避免.使用feign拦截器可以解决. 1:在公用模块中添加maven依赖 [外链图片转存失败, ...

  2. Dubbo:Spring Cloud 服务调用的新选择

    无论是Dubbo,还是Spring Cloud,大家可能都不会感到陌生. 那什么是Dubbo Spring Cloud呢?使用Dubbo Spring Cloud可以实现什么目的?基于其实现的路由和负 ...

  3. 【Spring Cloud】OpenFeign和Spring Cloud Loadbalancer调用失败后的重试机制比较

    1 概述 搭建一个微服务系统,有两个服务,Client和Server,Server有三个实例A.B.C,我让Client调用Server,Loadbalancer负载分担默认采用轮询机制,当Serve ...

  4. Spring Cloud - Feign调用问题

    2019独角兽企业重金招聘Python工程师标准>>> 这两天在改造微服务远程调用方法时,由之前的'RestTemplate'方式,改为'FeignClient'方式. 遇到一个及其 ...

  5. Dubbo 3.0 前瞻:重塑 Spring Cloud 服务治理

    作者 | 小马哥 **导读:**Dubbo 社区策划了[Dubbo 云原生之路]系列文章,和大家一起回顾 Apache Dubbo 产品和社区的发展,并展望未来发展.系列文章主要涵盖 Dubbo 技术 ...

  6. Spring Cloud(四):Spring Cloud Alibaba Feign Dubbo

    扩展点 RequestInterceptor#apply 扩展点 feign.Client#execute spring cloud dubbo 调用 RPC RPC 全称是 Remote Proce ...

  7. Dubbo的疑难解答:Spring Cloud Alibaba系列之分布式服务组件

    1.分布式理论 1.1.分布式基本定义 <分布式系统原理与范型>定义: "分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统" 分布式系统(dis ...

  8. Spring Cloud Alibaba 发布第一个正式版本,顺利完成孵化!

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 相信大家对上周的 <来自 Spring Cloud 官方的消息,Spring Clou ...

  9. 厉害了,Spring Cloud Alibaba 发布 GA 版本!

    小马哥 & Josh Long 喜欢写一首诗一般的代码,更喜欢和你共同 code review,英雄的相惜,犹如时间沉淀下来的对话,历久方弥新. 相见如故,@杭州. 4 月 18 日,Josh ...

最新文章

  1. 计算机组成微程序设计,计算机组成原理微程序设计.doc
  2. [转摘] JSP连接SQL SERVER问题总结
  3. python开发测试岗_作为测试开发岗的面试官,我都是怎么选人的?
  4. 基于多线程的TCP局域网通信,客户端向服务端上传 文件简单实现源码
  5. [Vue.js] 深入 -- 案例 - 购物车
  6. 深度学习技术在社会化推荐场景中的总结(附数据集)
  7. hadoop-mapreduce在maptask执行分析
  8. 从0开始学习 GitHub 系列之「05.Git 进阶」
  9. SU Demos-03T-F Analysis-01Sugabor
  10. 华硕幻16、酷睿12代、windows11、vmware折腾总结
  11. RPG多人回合制游戏战斗框架设计《一:基本战斗流程》
  12. 计算机屏幕颜色变黄色,win10系统电脑屏幕颜色偏黄如何调节
  13. 前端大牛工程师Nicholas C. Zakas:我得到的最佳职业生涯建议
  14. python 豆瓣源_使用豆瓣源来安装python中的第三方库方法
  15. P2123皇后游戏+P1080国王游戏
  16. JavaScript随手笔记之--html拼接语句传递json数据
  17. C++机器学习库整理
  18. 北美CS求学找工指南
  19. RDD编程初级实践(期末大作业)
  20. Spring整合JPA

热门文章

  1. Hololens黑科技101
  2. python实现猜数字游戏_python如何实现猜数字游戏
  3. 《你好,放大器》----学习记录(四)
  4. python挖矿木马_kworkerds 挖矿木马简单分析及清理
  5. 基辛格带领英特尔发起大反攻,以开源生态驱动异构计算
  6. 新版掩日免杀——搭配CS使用测试
  7. VOLO: Vision Outlooker for Visual Recognition 阅读笔记
  8. yii2 打开GII 的配置
  9. 联想电脑摄像头打不开解决方案看到最后!!!(相信xdm都找了好久的方法)
  10. 【嵌入式Linux】基于orangepi的官方外设开发