一、Dubbo与SpringCloud的区别(面试高频问题)
1、定位不同,dubbo是一个开源的分布式架构框架,致力于解决内部或内网的RPC,是SOA(面向服务架构)时代的产物,它专注于服务的调用与治理;而SpringCloud是一个微服务全家桶,工功能远比dubbo丰富,如:网关、更完善的熔断器、分布式配置、服务跟踪、批量任务等
2、接口调用方式不同,dubbo默认是dubbo协议(也支持http协议),一般是以java接口的形式直接调用;SpringCloud是使用HTTP做接口调用,比较灵活不受开发语言限制;二者相比,dubbo接口调用的性能较好(采用Netty的NIO方式实现)
3、组件差异较多,Dubbo是阿里的开源框架,而SpringCloud是基于SpringBoot开发的框架,dubbo一般使用Zookeeper当注册中心,Springcloud一般使用Eureka或naocs
二、Zookeeper与Eureka注册中心的区别
1、Zookeeper使用需要安装,而Eureka是项目中的一个java服务
2、集群设计不同,Zookeeper是主从设计,而Eureka是各节点平等
3、服务订阅方式不同,Zookeeper中的消费者首次启动将订阅服务信息缓存到本地,之后服务的变更会推送给消费者,而Eureka是采用定时轮询的方式去主动拉取服务的更新
三、SpringCloud核心组件
1、zuul(网关):相当于网络服务架构的入口,所有请求必须通过网关转发到具体的服务,主要功能有统一管理微服务请求、负载均衡、动态路由、权限控制、监控、静态资源处理等
2、Eureka(注册中心):用来注册服务,其中包含Eureka Client、Eureka Server
Eureka Client:包含服务提供者,服务消费者,主要负责服务注册、心跳续约与健康状态查询
Eureka Server:提供注册服务,各个节点启动后都会在Eureka Server注册,可用的节点信息可在Eureka Server中的服务注册表中找到
3、Feign:一个HTTP请求的轻量级客户端框架,通过接口+注解的方式发起HTTP请求的调用
具体执行流程如下
a、在主程序上添加@EnableFeignClients注册开启对@FeignClient注解的扫描加载
b、调用接口中的方法时,基于JDK的动态代理,通过InvokeHandler分发远程调用,生成具体的RequestTemplate
c、RequestTemplate生成Request请求,结合Ribbon实现服务负载均衡策略
Feign最核心的就是动态代理,同时整合了Ribbon和Hystrix,具备负载均衡、隔离、熔断和降级功能
4、Ribbon:是一个客户端的负载均衡器,支持简单轮询、权重、随机、重试等多种策略
5、Hystrix:断路器,包含熔断、隔离、降级等功能
四、SpringCloud的使用(注意SpringBoot与SpringCloud的版本兼容性,官网说明)
1、创建一个项目,笔者这里的demo项目叫bryant(注意需要创建SpringBoot项目),pom文件配置如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kobe</groupId>
<artifactId>bryant</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modules>
<!-- 注册中心服务 -->
<module>eureka-server</module>
<!-- 服务提供者 -->
<module>user-api</module>
<!-- 消费者 -->
<module>user-client</module>
<!-- feign消费者 -->
<module>feign-client</module>
</modules>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<project.version>0.0.1-SNAPSHOT</project.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- java11中没有以下jar包 -->
<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>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<name>bryant</name>
<description>bryant</description>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、在父项目下创建Eureka服务项目,eureka-server,pom文件配置如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.kobe</groupId>
<artifactId>bryant</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.kobe</groupId>
<artifactId>eureka-server</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<description>eureka-server</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置注册中心服务的端口号及其他参数:
#tomcat
server:
port: 8888
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
application:
name: eureka-server
然后在启动类上加上@EnableEurekaServer注解:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
好了,以上就是注册中心服务创建和配置,启动成功后访问http://localhost:8888会出现如下界面:
3、在父项目下创建服务提供者项目,user-api,pom文件如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.kobe</groupId>
<artifactId>bryant</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.kobe</groupId>
<artifactId>user-api</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>user-api</name>
<description>user-api</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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>
</project>
配置服务端口并在配置文件中指定Eureka注册中心的地址:
#tomcat
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/
spring:
application:
name: user-api
然后在启动类中添加@EnableEurekaClient注解:
@SpringBootApplication
@EnableEurekaClient
public class UserApiApplication {
public static void main(String[] args) {
SpringApplication.run(UserApiApplication.class, args);
}
}
在服务提供者项目简单定义几个http接口:
@RestController
public class UserApiController {
@Value("${spring.application.name}")
private String serverName;
@Value("${server.port}")
private String port;
@GetMapping("user/token")
public String getUserToken() {
return UUID.randomUUID().toString();
}
@GetMapping("user/hi/{name}")
public String sayHi(@PathVariable String name) {
return "Hello, " + name + ", I am " + serverName + ", my port is " + port + ".";
}
}
写好启动服务,刷新注册中心管理页面(http://localhost:8888)能看到已经发现服务:
现在可以修改一下服务提供者的端口,再启动一个服务,方便模拟多节点场景:
4、在父项目下创建rest+ribbon消费者项目,user-client,pom文件如下:
<?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>
<parent>
<artifactId>bryant</artifactId>
<groupId>com.kobe</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.kobe</groupId>
<artifactId>user-client</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>user-api</name>
<description>user-api</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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>
</project>
同样是定义端口和配置Eureka地址:
#tomcat
server:
port: 7071
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/
spring:
application:
name: user-client
然后在启动类中添加@EnableEurekaClient、@EnableDiscoveryClient注解,还需要配置一个RestTemplate类,用来调用服务提供者的接口:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class UserClientApplication {
public static void main(String[] args) {
SpringApplication.run(UserClientApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
现在可以编写controller去调用服务提供者的接口,可以看到http协议后跟的是服务提供者的服务名,后面跟的是其http接口地址:
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("user/token")
public String getUserToken() {
return restTemplate.getForObject("http://user-api/user/token", String.class);
}
@GetMapping("user/hi/{name}")
public String sayHi(@PathVariable("name") String name) {
return restTemplate.getForObject("http://user-api/user/hi/" + name, String.class);
}
}
启动消费者项目注册中心后台能看到如下结果:
接下来多次访问一下http://localhost:7071/user/hi/SpringCloud接口试试:
能看到已经实现了负载均衡!
5、在父项目下创建feign消费者项目,pom文件如下:
说明:其中rest+ribbon和feign(轻量级的HTTP请求客户端)只是调用代码风格不同,实际开发中任选其一(推荐用feign)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.kobe</groupId>
<artifactId>bryant</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.kobe</groupId>
<artifactId>feign-client</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>feign-client</name>
<description>feign-client</description>
<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>
</project>
配置feign消费者服务端口号及Eureka注册中心的地址:
#tomcat
server:
port: 7072
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/
spring:
application:
name: feign-client
在启动类上添加@EnableEurekaClient、@EnableDiscoveryClient、@EnableFeignClient来启用feign功能:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class FeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(FeignClientApplication.class, args);
}
}
使用feign需要先定义接口,@FeignClient是关键所在,这实际上是对服务提供者的接口的描述,跟定义controller接口相似,具体示例如下:
@FeignClient(value = "user-api")
public interface IUserApiRemoteService {
@GetMapping("user/token")
String getToken();
@GetMapping("user/hi/{name}")
String sayHi(@PathVariable String name);
}
然后使用就跟平时注入一个普通的service一样,它底层是使用代理来实现的:
@RestController
public class UserController {
@Autowired
private IUserApiRemoteService userRemoteService;
@GetMapping("user/token")
public String getUserToken() {
return userRemoteService.getToken();
}
@GetMapping("user/hi/{name}")
public String sayHi(@PathVariable("name") String name) {
return userRemoteService.sayHi(name);
}
}
启动该服务后访问http://localhost:7072/user/hi/SpringCloud接口:
以上就是SpringCloud的简单使用,这里没有集成网关,可以根据项目的实际需求来评估是否需要使用网关技术。