SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Eureka、Ribbon)

微服务技术栈导学

微服务技术是分布式架构(把服务做拆分)的一种

而springcloud仅仅是解决了拆分时的微服务治理的问题,其他更复杂的问题并没有给出解决方案

一个完整的微服务技术要包含的不仅仅是springcloud

微服务技术栈

包括什么
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

认识微服务

(一)服务架构演变

1、单体架构

在这里插入图片描述

2、分布式架构

在这里插入图片描述

3、服务治理

在拆分的过程中也会有一些问题
在这里插入图片描述

4、微服务

在这里插入图片描述

5、总结

在这里插入图片描述

(二)微服务技术对比

1、微服务结构

在这里插入图片描述

2、微服务技术对比

在这里插入图片描述
SpringCloudAlibaba兼容了前面两种

3、企业需求

在这里插入图片描述

(三)SpringCloud

在这里插入图片描述
在这里插入图片描述

服务拆分

(一)案例Demo

1、服务拆分注意事项

在这里插入图片描述

2、导入服务拆分Demo

在这里插入图片描述
在这里插入图片描述
order表user_id虽然和user表进行关联,但是因为是跨database的,因此无法进行关联查询

在这里插入图片描述
项目中所有的微服务:
在这里插入图片描述
以下是两个分别的application.yml

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS

将两个都启动:
在这里插入图片描述
在浏览器中(下载Chrome插件Json Viewer)
在这里插入图片描述
在这里插入图片描述

(二)服务远程调用

1、根据订单id查询订单功能

在这里插入图片描述

2、远程调用方式分析

那么问题就转变成了:如何在java代码中(像浏览器一样)发起http请求,这样就能实现远程调用了
在这里插入图片描述
Spring提供了一个工具——RestTemplate,用来发http请求
在这里插入图片描述

通过Bean的方式把RestTemplate注册为其中的一个对象,然后将来可以在任何地方注入这个对象来使用

写在哪里呢?Bean的注入只能放在配置类中,而启动类(OrderApplication)(带有@SpringBootApplication)本身也是配置类,所以完全可以在这里写Bean的注入

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    /**
     * 创建RestTemplate并注入Spring容器
     * @return
     */
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

接下来就可以利用它来发http请求了
在这里插入图片描述

修改OrderService

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    
    // 0.注入RestTemplate
    @Autowired
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.利用RestTemplate发送http请求,查询用户
        // 2.1.url路径
        String url = "http://localhost:8081/user/" + order.getUserId();
        // 2.2.发送http请求,实现远程调用(getForObject默认返回json,加上User.class参数g告诉它返回值的类型,自动转化成User对象)
        User user = restTemplate.getForObject(url, User.class);
        // 3.封装user到Order
        order.setUser(user);
        // 4.返回
        return order;
    }
}

然后重启Order服务(User服务就不需要重启了)
在这里插入图片描述

3、总结

在这里插入图片描述

Eureka注册中心

(一)提供者与消费者

在这里插入图片描述

(二)eureka原理分析

1、服务调用出现的问题

在这里插入图片描述

刚才将user-service服务的ip和端口硬编码在代码中的,有一定问题
所以不能用硬编码方式

在这里插入图片描述

2、Eureka的作用

在这里插入图片描述

每一个服务启动时都会把自己的信息注册给eureka

如果某个心脏不跳动了,eureka会将这个从列表中删除
在这里插入图片描述

3、总结

在这里插入图片描述

(三)搭建eureka服务

1、动手实践

在这里插入图片描述

2、搭建EurekaServer

在这里插入图片描述

搭建EurekaServer需要创建一个独立的微服务

starter是springboot中的自动装配,也就是说在这个依赖中已经帮我们把springeureka的所有的配置都做好了,也就是说我们可以零配置直接拿来用了

当然,自动装配是需要有开关的,第二步这个注解就是eurekaserver自动装配的开关

第三步需要编写一些配置信息,端口信息、服务名称、eureka的地址信息

接下来开始写:
1、创建一个新的module
在这里插入图片描述
引入依赖:

<dependencies>
    <!--eureka服务端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

注意到我们引入的时候并没有指定版本信息,以前学习springboot时也遇到过这种情况,原因是在我们的父工程中,已经把依赖的版本都管理好了,所以可以进入cloud-demo的父工程的pom文件看,可以看到spring-boot-starter-parent的版本为2.3.9.RELEASE,以及spring-cloud版本和其他,并且有spring-cloud-dependencies依赖库,里面有大量的springcloud的组件及其版本信息,全都定义好了,所以在我们引入springcloud组件时,我们无需指定任何版本信息

2、编写main函数并添加注解
新建cn.itcast.eureka.EurekaApplication类

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

3、编写一个配置文件
resources下新建application.yml

server:
  port: 10086 # 服务端口
spring:
  application:
    name: eurekaserver # eureka的服务名称
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

注意由于eureka自己也是一个微服务,会将自己也注册到eureka上(这是为了将来eureka集群去用的),所以它也需要一个名字,而且还需要再配一个eureka的地址eureka.client.service-url

也就是说“这里是为了做服务注册才配置这些信息”

然后点击EurekaApplication左边的三角形启动,就可以在下面的服务中看到多出来了EurekaApplication
在这里插入图片描述
点击这个蓝色的端口号,会自动跳转到浏览器

点击10086,就跳转到了eureka的管理界面
在这里插入图片描述

status中的up表示正常状态,down表示挂掉了,up后面的是ip

(四)服务注册

1、注册user-service

在这里插入图片描述
可以看到,除了依赖不一样(刚才时eureka的服务端,现在是eureka的客户端),这个配置和刚才在eureka中做的配置文件长得非常像。为什么?因为eureka启动时会把自己注册到eureka,所以它也需要配服务名称和地址。所以服务名称和地址的配置实际上是服务注册的配置,只要配了它,就可以做注册

<!--eureka客户端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

然后配置yml文件

server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: userservice # user服务的服务名称
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

然后重启UserApplication

接下来把Order服务也注册到Eureka,同上,然后重启
在这里插入图片描述
这里每个服务都只有一个实例,我们可以每个服务启动多个实例

在这里插入图片描述
在这里插入图片描述
(在这里配置端口,是为了覆盖yml文件的端口的)在这里插入图片描述
然后把它也启动,
在这里插入图片描述

(五)服务发现

我们希望orderservice可以基于服务名称拉取到userservice的两个实例信息,然后实现负载均衡
在这里插入图片描述
用服务名称代替ip、端口:在eureka中可以看到userservice这个服务名代指的就是这两个端口

要在多个实例中负载均衡,要给之前用到的RestTemplate这个Bean加一个注解@LoadBalanced

都弄完之后,我们把两个UserApplication的都清空,因为我们想知道OrderApplication究竟使用的是哪一个UserApplication,因为在OrderService中url中只是userservice,没有加任何ip地址

(六)总结

在这里插入图片描述

Ribbon负载均衡

(一)负载均衡原理

在这里插入图片描述
直接在浏览器中访问userservice/user/1是无法访问的

在这里插入图片描述

(二)负载均衡策略

IRule接口决定了负载均衡的策略
在这里插入图片描述
在这里插入图片描述
ZoneAvoidanceRule是默认

在这里插入图片描述
注意第一种代码方式是全局的,也就是说我一旦配了上面这种方案,在orderservice中不管你是调用哪一个微服务,都是randomrule;而第二种配置文件方式会先指定服务名称,再指定负载均衡的规则,只针对某个服务而言。

(三)饥饿加载

重启OrderApplication,
在这里插入图片描述
达到了非常恐怖的311毫秒,然后再刷新一次,
在这里插入图片描述
时长就只有19毫秒了

在这里插入图片描述

创建LoadBalanceClient的过程中还要做服务的拉取,因此时间长

(这个配置是在orderservice的application.yml文件)

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice # order服务的服务名称
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
ribbon:
  eager-load: 
    enabled: true # 开启饥饿加载
    clients: # 指定饥饿加载的服务名称
      - userservice
      - xxservice

这个ribbon与上面userservice下的ribbon不冲突

(四)总结

在这里插入图片描述

代码

在这里插入图片描述

(一)pom.xml

<?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>cn.itcast.demo</groupId>
    <artifactId>cloud-demo</artifactId>
    <version>1.0</version>
    <modules>
        <module>user-service</module>
        <module>order-service</module>
        <module>eureka-server</module>
    </modules>

    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
        <mysql.version>5.1.47</mysql.version>
        <mybatis.version>2.1.1</mybatis.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- springCloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!--mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

(二)eureka-server

在这里插入图片描述

1、pom.xml

<?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">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--eureka服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>

2、application.yml

server:
  port: 10086 # 服务端口
spring:
  application:
    name: eurekaserver # eureka的服务名称
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

3、EurekaApplication.java

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

(三)user-service

在这里插入图片描述

1、pom.xml

<?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">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>user-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--eureka客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2、application.yml

server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: userservice # user服务的服务名称
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

3、UserApplication.java

@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

4、UserController.java

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

5、UserService.java

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) {
        return userMapper.findById(id);
    }
}

6、User.java

@Data
public class User {
    private Long id;
    private String username;
    private String address;
}

7、UserMapper.java(接口)

@Mapper
public interface UserMapper {
    
    @Select("select * from tb_user where id = #{id}")
    User findById(@Param("id") Long id);
}

(四)order-service

在这里插入图片描述

1、pom.xml

<?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">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--eureka客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2、application.yml

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice # order服务的服务名称
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients: # 指定饥饿加载的服务名称
      - userservice

3、OrderApplication.java

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    /**
     * 创建RestTemplate并注入Spring容器
     * @return
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

4、OrderController.java

@RestController
@RequestMapping("order")
public class OrderController {

   @Autowired
   private OrderService orderService;

    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }
}

5、OrderService.java

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    // 0.注入RestTemplate
    @Autowired
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.利用RestTemplate发送http请求,查询用户
        // 2.1.url路径
        String url = "http://userservice/user/" + order.getUserId();
        // 2.2.发送http请求,实现远程调用(getForObject默认返回json,加上User.class参数自动转化成User对象)
        User user = restTemplate.getForObject(url, User.class);
        // 3.封装user到Order
        order.setUser(user);
        // 4.返回
        return order;
    }
}

6、User.java

@Data
public class User {
    private Long id;
    private String username;
    private String address;
}

7、Order.java

@Data
public class Order {
    private Long id;
    private Long price;
    private String name;
    private Integer num;
    private Long userId;
    private User user;
}

8、OrderMapper.java(接口)

@Mapper
public interface OrderMapper {

    @Select("select * from tb_order where id = #{id}")
    Order findById(Long id);
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值