首页 > 编程学习 > 01.SpringCloudAlibaba 项目

01.SpringCloudAlibaba 项目

发布时间:2022/9/7 22:43:48

SpringCloudAlibaba 项目

1. 简述

SpringCloudAlibaba 项目,采用的 SpringCloudAlibaba 相关组件:

Nacos:注册与发现、配置
Gateway:网关
Feign:远程调用
Sentinel:限流、熔断
Seata:分布式事务

2. 创建项目

2.1 通用配置

  1. 使用IDEA创建一个Empty Project,再创建4个module:common、producer、consumer、gateway;
  2. 拷贝一个pom.xml文件作为项目的总pom文件,起到聚合作用;
  3. 对4个模块添加通用配置:
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.8.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR3</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>
  1. common模块,添加基础依赖:
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--nacos注册中心-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>
  1. 其他的三个模块,添加common模块依赖:
<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

2.2 producer 生产者模块

  1. 修改启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Producer {
    public static void main(String[] args) {
        SpringApplication.run(Producer.class, args);
    }
}
  1. 创建配置文件 application.yml
server:
  port: 10000
spring:
  application:
    name: producer
  cloud:
    nacos:
      discovery:
        server-addr: 120.48.96.228:8848
management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 服务producer正常注册到Nacos中,服务正常启动;

2.3 consumer 消费者模块

  1. 修改启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class Consumer {
    public static void main(String[] args) {
        SpringApplication.run(Consumer.class, args);
    }
}
  1. 创建配置文件:
server:
  port: 11000
spring:
  application:
    name: consumer
  cloud:
    nacos:
      discovery:
        server-addr: 120.48.96.228:8848
  1. 服务consumer 正常注册到Nacos中,服务正常启动;

2.4 gateway 网关模块

  1. 修改依赖:
<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>common</artifactId>
        <version>1.0-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>
  1. 修改启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Gateway {
    public static void main(String[] args) {
        SpringApplication.run(Gateway.class, args);
    }
}
  1. 创建配置文件:端口为8080
server:
  port: 8080
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 120.48.96.228:8848
    gateway:
      routes:
        - id: producer_route
          uri: lb://producer
          predicates:
            - Path=/api/producer/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
        - id: consumer_route
          uri: lb://consumer
          predicates:
            - Path=/api/consumer/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
  1. 服务gateway 正常注册到Nacos中,服务正常启动;

3. 创建接口,服务调用

3.1 创建接口

  1. producer 生产者模块
@RestController
@RequestMapping("/producer")
public class ProducerController {
    //访问:http://localhost:10000/producer/add
    @GetMapping(value = "/add")
    public String add() {
        System.out.println("producer success!");
        return "producer add success!";
    }
}
  1. consumer 消费者模块
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
    @Value("${server.port}")
    private String port;

    //访问:http://localhost:11000/consumer/add
    @RequestMapping("/add")
    public String add() {
        System.out.println("consumer add success!");
        return "consumer add success!";
    }

    //访问:http://localhost:11000/consumer/sub
    @RequestMapping("/sub")
    public String sub() {
        System.out.println("consumer sub success!");
        return "consumer sub success! ------ port is " + port;
    }
}
  1. 经过 gateway 网关进行访问:
http://localhost:8080/api/producer/add
http://localhost:8080/api/consumer/add
http://localhost:8080/api/consumer/sub

3.2 服务调用

以上是通过浏览器访问服务的接口,而服务间通常需要相互调用,如:producer去消费consumer;以下操作都是生产者producer上进行;

3.2.1 RestTemplate

  1. 创建一个配置类 RestTemplateConfig 支持负载均衡
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Configuration
@Component
public class RestTemplateConfig {
    @Bean
    @LoadBalanced //使RestTemplate请求支持负载均衡
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}
  1. 修改类 ProducerController,添加接口:
@Autowired
private RestTemplate restTemplate;

@RequestMapping("/add2")
public String add2() {
    System.out.println("producer2 success!");
    String apiReqResult = restTemplate.getForObject("http://consumer/consumer/add", String.class);
    return "producer2 add success! return val is : " + apiReqResult;
}
  1. 访问:http://localhost:8080/api/producer/add2 正常访问;

3.2.2 Feign

Feign组件,声明式服务调用,可进行远程调用;

  1. 服务间会进行互相调用,所以在common模块中添加(已添加:openfeign);
  2. 生产者去调用消费者,所以在producer 模块中,创建目录feign,专用于远程调用;
  3. 创建一个接口类,与远程调用的类保持一致:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("consumer") //要调用的服务名
public interface ConsumerService {
    //要远程调用方法的完整签名
    @RequestMapping("/consumer/add")
    String add();
    
    @RequestMapping("/consumer/sub")
    String sub();
}
  1. 启动类处,添加注解:
@EnableFeignClients(basePackages = {"org.example.producer.feign"})
  1. 修改类 ProducerController,添加接口:
@Autowired
private ConsumerService consumerService;

@GetMapping(value = "/add3")
public String add3() {
    String add = consumerService.add();
    System.out.println("producer feign : " + add);
    return "producer feign : " + add;
}
  1. 访问:http://localhost:8080/api/producer/add3 返回值正常;

4. 配置中心Nacos Server

Nacos的功能:注册中心、配置中心;

4.1 Nacos 配置功能

  1. 在common模块中,添加依赖:
<!--nacos配置中心-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
  1. 为3个模块添加配置文件:bootstrap.properties
spring.cloud.nacos.config.server-addr=120.48.96.228:8848
  1. 在含有变量的类上,添加注解:@RefreshScope ,开启动态刷新功能;(事实上,配置文件中添加变量,这种方式很少使用)
  2. 配置中心实现隔离、分组功能:命名空间、GROUP、抽离服务配置;

4.2 抽离服务配置

  1. 将配置文件application.yml 里面的内容进行分类,如(也可按服务分类):
datasource.yml
mybatisplus.yml
other.yml
nacos-discovery.yml
...
  1. 服务加载Nacos中的配置集信息
1. 即application.yml 配置文件不再写配置内容,配置内容在Nacos配置中心的多个yml文件中,而配置信息在bootstrap.properties文件中;
2. 即相同的配置内容,可重复使用;
  1. 在 bootstrap.properties 文件中加载配置信息
spring.application.name=consumer
spring.cloud.nacos.config.server-addr=120.48.96.228:8848
#指定配置文件的命名空间,默认 public
spring.cloud.nacos.config.namespace=public
#指定配置文件的分组,默认 DEFAULT_GROUP
spring.cloud.nacos.config.group=DEFAULT_GROUP

#数据源扩展配置的配置集id
spring.cloud.nacos.config.ext-config[0].data-id=nacos-discovery.yml
#加载dev分组的配置集
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
#开启自动刷新
spring.cloud.nacos.config.ext-config[0].refresh=true

spring.cloud.nacos.config.ext-config[1].data-id=port-11000.yml
spring.cloud.nacos.config.ext-config[1].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[1].refresh=true
  1. 说明:
1. 需要在Nacos中添加配置文件:nacos-discovery.yml、port-11000.yml
2. 文件内容就是之前的配置内容,使用配置扩展功能,启动时将配置信息读取出来;
3. 同上,将生产者、网关服务,配置信息配置到Nacos的配置中心去;

5. 熔断限流 Sentinel

高并发情况下,大量用户去访问服务,以及服务间的互相调用,所以需要对各个服务进行限流设置;

  1. 在common模块中添加公共依赖:
<!-- sentinel 启动器 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  1. 在Nacos配置服务端,创建sentinel.yml 配置文件:
spring:
  cloud:
    sentinel:
      eager: true     #true表示取消Sentinel控制台懒加载,默认情况下 Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包
      transport:
        dashboard: 101.43.52.64:8858
#        client-ip:   #如果有多套网络,又无法正确获取本机IP,则需要使用下面的参数设置当前机器可被外部访问的IP地址,供admin控制台使用
  1. 在三个服务的配置文件bootstrap.properties 中添加配置:
spring.cloud.nacos.config.ext-config[3].data-id=sentinel.yml
spring.cloud.nacos.config.ext-config[3].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[3].refresh=true
  1. 启动三个服务,访问Sentinel控制台:会发现3个服务均注册到Sentinel中;
  2. 可以操作的有:
1. 实时监控,可用于查看接口访问情况
2. 簇点链路,可以对对应的资源流控降级
3. QPS流量控制、线程流量控制、关联限流、熔断降级
4. Sentinel支持多种保护规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则、热点参数规则
  1. 持久化规则,在Sentinel中的配置会因服务重启而消失,所以需要持久化,common模块中添加依赖:
<!--sentinel持久化存储-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
  1. 在Nacos中添加配置sentinel-durable 文件
[
	{
		"resource": "/producer/add",
		"controlBehavior": 0,
		"count": 2,
		"grade": 1,
		"limitApp": "default",
		"strategy": 0
	}
]
  1. 修改配置文件 sentinel.yml
spring:
  cloud:
    sentinel:
      eager: true     #true表示取消Sentinel控制台懒加载,默认情况下 Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包
      transport:
        dashboard: 101.43.52.64:8858
        port: 8719    #默认为8719 ,假如被占用会自动从8719开始依次+1扫描,直到未被占用的端口,线上部署的ip  -> ip必须打开8719的端口
#        client-ip:   #如果有多套网络,又无法正确获取本机IP,则需要使用下面的参数设置当前机器可被外部访问的IP地址,供admin控制台使用
      datasource:
        ds:
          nacos:
            serverAddr: 120.48.96.228:8848    #nacos的服务注册中心
            dataId: sentinel-durable          #Nacos配置中心的命名(不加.json)
            dataType: json
            groupId: DEFAULT_GROUP            #nacos配置中心的组id
            ruleType: flow                    #规则为限流

6. 事务 Seata

  1. Seata-Server端,注册和配置中心采用Nacos,数据库采用MySQL;
  2. common模块中引入依赖:
<!-- seata 分布式事务 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
  1. 对各微服务对应的数据库中添加undo_log表
CREATE TABLE `undo_log`(
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `branch_id` bigint(20) NOT NULL,
    `xid` varchar(100) NOT NULL,
    `context` varchar(128) NOT NULL,
    `rollback_info` longblob NOT NULL,
    `log_status` int(11) NOT NULL,
    `log_created` datetime NOT NULL,
    `log_modified` datetime NOT NULL,
    PRIMARY KEY(`id`),
    UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
  1. 对各个服务添加配置:
#配置seata的注册中心
seata.enabled=true
seata.application-id=${spring.application.name}
#配置事务分组
seata.tx-service-group=default_tx_group
seata.registry.type=nacos
seata.registry.nacos.server-addr=127.0.0.1:8848
seata.registry.nacos.application=seata-server
seata.registry.nacos.namespace=
seata.registry.nacos.username=nacos
seata.registry.nacos.password=nacos
seata.registry.nacos.group=SEATA_GROUP
#配置seata的配置中心
seata.config.type=nacos
seata.config.nacos.server-addr=127.0.0.1:8848
seata.config.nacos.namespace=
seata.config.nacos.username=nacos
seata.config.nacos.password=nacos
seata.config.nacos.group=SEATA_GROUP
  1. 在业务代码上添加注解:
@GlobalTransactional //分布式事务注解
public String addOrder(){
    Order order = new Order("袜子");
    int id = orderService.addOrder(order);
    System.out.println("订单新增成功-id:" + id);
    //调用库存扣减
    String result = stockOpenFeignService.subStock(id);
    return new Result(200,"订单服务-订单新增成功",result).toString();
}
Copyright © 2010-2022 mfbz.cn 版权所有 |关于我们| 联系方式|豫ICP备15888888号