一、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会出现如下界面:

升级dubbo 对应spring版本 dubbo改spring cloud_springcloud实例

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)能看到已经发现服务:

升级dubbo 对应spring版本 dubbo改spring cloud_springcloud实例_02

现在可以修改一下服务提供者的端口,再启动一个服务,方便模拟多节点场景:

升级dubbo 对应spring版本 dubbo改spring cloud_spring cloud_03

 

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);
    }

}

启动消费者项目注册中心后台能看到如下结果:

升级dubbo 对应spring版本 dubbo改spring cloud_spring cloud_04

接下来多次访问一下http://localhost:7071/user/hi/SpringCloud接口试试:

升级dubbo 对应spring版本 dubbo改spring cloud_dubbo_05

 

升级dubbo 对应spring版本 dubbo改spring cloud_springcloud实战_06

能看到已经实现了负载均衡!

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接口:

升级dubbo 对应spring版本 dubbo改spring cloud_spring cloud_07

 

升级dubbo 对应spring版本 dubbo改spring cloud_dubbo_08

 以上就是SpringCloud的简单使用,这里没有集成网关,可以根据项目的实际需求来评估是否需要使用网关技术。