SpringCloud Alibaba组件

一、Nacos组件

        作用:Nacos 致力于帮助您发现、配置和管理微服务

        特性:

                服务发现和服务健康监测
                动态服务配置
                动态 DNS 服务
                服务及元数据管理

        下载地址:Releases · alibaba/nacos · GitHub

        安装:下载解压即可使用

        运行:以下均需切换到bin目录下

                windows:

                       startup.cmd -m standalone ---- 开启服务,默认为集群方式启动,启动报错,需改为单机版方式 standalone

                        shutdown.cmd ---- 关闭服务

                linux:

                        sh startup.sh -m standalone ---- 开启服务,standalone 单机运行模式;

                        sh shutdown.sh ---- 关闭服务;

        访问主页:http://127.0.0.1:8848/nacos/

        用户名/密码:nacos/nacos

        应用:在需要注册微服务的模块中导入

                pom:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

                application.properties:

spring.application.name=spring-cloud-alibaba-account
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

                启动类添加注解:@EnableDiscoveryClient 

在服务列表中能看到微服务的名称说明注册成功

 二、父子项目版本管理

        版本依赖关系:

                        Spring Boot 版本: 2.6.3

                        Spring Cloud 版本:Spring Cloud 2021.0.1

                        Spring Cloud Alibaba 版本:2021.0.1.0

三、配置中心

        Nacos 除了微服务的注册与发现之外,还将配置中心整合在了一起,我们可以将整个架构体系内的所有配置都集中在 Nacos 中存储;

        应用:

                pom:需要引入nacos和bootstrap

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

                bootstrap.properties:

# for spring
spring.application.name=spring-cloud-alibaba-test
spring.profiles.active=dev

# for nacos discovery
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# for config
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.file-extension=properties

# for bootstrap
spring.cloud.bootstrap.enabled=true

                去nacos的配置中心添加一个配置即可

 四、OpenFeign

        作用:实现微服务之间的接口互调

        pom:导入openfeign和负载均衡

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

        application.properties:无需配置

        启动类添加注解:@EnableFeignClients、@LoadBalancerClient

package com.hqyj.springCloudAlibabaAccount;

import com.hqyj.springCloudAlibabaAccount.config.CustomLoadBalancerConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@LoadBalancerClient(name = "spring-cloud-alibaba-test", configuration = CustomLoadBalancerConfiguration.class)
public class SpringCloudAlibabaAccountApplication {

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

}

                接口调用:在service层增加一个接口,用于调用其它微服务的接口

package com.hqyj.springCloudAlibabaAccount.service;

import com.hqyj.common.vo.Result;
import com.hqyj.test.City;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(name = "spring-cloud-alibaba-test")
public interface CityFeignClient {
    /**
     *  127.0.0.1:8761/api/test/city/1980 --- get
     */
    @GetMapping("/api/test/city/{cityId}")
    public City getCityByCityId(@PathVariable int cityId);

    /**
     *  127.0.0.1:8761/test/api/city  --- put
     * {"cityId":2261,"cityName":"zyw1","localCityName":"朱由万1","dateModified":"2022-9-9 16:55:30"}
     */
    @PutMapping(value = "/api/test/city",consumes = MediaType.APPLICATION_JSON_VALUE)
    Result<City> updateCity(@RequestBody City city);
}

                在其他需要调用该接口的地方,注入刚才新增的接口,直接调用即可

@Autowired
private CityFeignClient cityFeignClient;

City city = cityFeignClient.getCityByCityId(cityId);

五、负载均衡-Loadbalancer

        作用:访问多个实例的同一个接口

        pom:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

        application.properties:无需配置

        配置类:自定义负载均衡器

package com.hqyj.springCloudAlibabaAccount.config;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

/**
 * @ClassName CustomLoadBalancerConfiguration
 * @Author ZhuYouWan
 * @Date 2022/9/27 11:30
 **/
public class CustomLoadBalancerConfiguration {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

        启动类添加注解:@LoadBalancerClient

六、网关-Gateway

        作用:外部使用统一的端口地址访问接口,通过网关进行转发

        pom:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

        application.properties:

# for server
server.port=8888

# for application
spring.application.name=spring-cloud-alibaba-gateway

# for nacos discovery
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# for no web
spring.main.web-application-type=reactive

# for gateway route
spring.cloud.gateway.routes[0].id=testServer
spring.cloud.gateway.routes[0].uri=lb://spring-cloud-alibaba-test
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/test/**
spring.cloud.gateway.routes[1].id=accountServer
spring.cloud.gateway.routes[1].uri=lb://spring-cloud-alibaba-account
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/account/**

        启动类:

package com.hqyj.springCloudAlibabaGateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudAlibabaGatewayApplication {

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

}

        跨域:

package com.hqyj.springCloudAlibabaGateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * @ClassName CorsAutoConfiguration
 * @Author ZhuYouWan
 * @Date 2022/9/27 19:02
 **/
@Configuration
public class CorsAutoConfiguration {
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeaders().getOrigin());
                // 允许的 header
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                        "X-Token,Token,Authorization,x-requested-with,Content-Type");
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "PUT,POST, GET, OPTIONS, DELETE");
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

七、Sentinel

        作用:

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

         使用:下载到本地,CMD运行即可

                    默认 8080 端口运行,可能与其它软件冲突,故选择 9090 端口
        启动命令:java -jar sentinel-dashboard-1.8.3.jar --server.port=9090

        访问地址:127.0.0.1:9090

        登录用户名和密码均为:sentinel

出现以下界面代表安装成功

        pom:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

         application.properties:

# for sentinel
spring.cloud.sentinel.transport.dashboard=127.0.0.1:9090
spring.cloud.sentinel.transport.port=8719
management.endpoints.web.exposure.include=*

        实时监控:微服务加入了 Sentienl,在调用服务接口时,就会通过内部通信服务把日志信息发送给 Dashboard 服务,并在页面上展示

        簇点链路:微服务、Api 调用情况,提供流控、熔断、热点、授权等操作;

 

         流量控制:流量控制(Flow Control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性

        熔断降级:服务调用中,如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用方的响应时间也会变长,线程会产生堆积,最终可能耗尽线程池,服务本身也变得不可用,Sentinel 在服务出现不稳定情况时,会对让请求快速失败,避免影响到其他资源而导致级联错误,当资源被降级后,在接下来的时间窗口内,对该资源的调用都自动熔断

        实现:

@Override
@SentinelResource(value = "getCityByCityId", blockHandler = "blockHandler", fallback = "fallbackHandler")
public UserVo getUserVoById(int userId, int cityId) {
	UserVo userVo = new UserVo();
	User user = userDao.getUserById(userId);
	BeanUtils.copyProperties(user, userVo);
	City city = cityFeignClient.getCityByCityId(cityId);
	userVo.setCity(city);
	return userVo;
}

//限流
public UserVo blockHandler(int userId, int cityId, BlockException exception){
	if (exception instanceof FlowException){
		System.out.println("您被限流了.");
	} else if (exception instanceof DegradeException){
		System.out.println("您被降级了.");
	}else {
		System.out.println("City 接口不可用.");
	}
	return new UserVo();
}

//熔断
public UserVo fallbackHandler(int userId, int cityId){
	System.out.println("发生了非流控、降级异常,被熔断了.");
	return new UserVo();
}

 八、Seata

        作用:Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务

        下载:https://github.com/seata/seata/releases

        术语:

                XID(Transaction ID):全局唯一的事务 ID;

                TC (Transaction Coordinator):事务协调者,维护全局和分支事务的状态,驱动全局事务提交或回滚;

                TM (Transaction Manager):事务管理器,定义全局事务的范围,开始全局事务、提交或回滚全局事务;

                RM (Resource Manager):资源管理器,管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚;

        处理过程:

                TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID;

                XID 在微服务调用链路的上下文中传播;

                RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖;

                TM 向 TC 发起针 XID 的全局提交或回滚决议;

                TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求;

        Service端:

         配置:

                事务协调者(TC)的注册中心、配置文件、数据存储地址

                File 方式:是本地文件系统,无需修改配置;

                其他方式:根据实际情况配置;
        客户端配置应与服务端配置保持一致;

        运行:均需切换到bin目录下

               Windows:seata-server.bat

                Linux:sh ./seata-server.sh

        Client端:

                pom:

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

                application.properties:事务分组配置

# for server
server.port=8763

# for nacos discovery
spring.application.name=spring-cloud-alibaba-account
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# for data source
# mysql 5
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# mysql 6 +
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/main?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.jdbc-url=jdbc:mysql://127.0.0.1:3306/main?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=130720

# hikari pool
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=180000
spring.datasource.hikari.auto-commit=true

# for mybatis
mybatis.configuration.map-underscore-to-camel-case=true

# for sentinel
spring.cloud.sentinel.transport.dashboard=127.0.0.1:9090
spring.cloud.sentinel.transport.port=8719
management.endpoints.web.exposure.include=*

# for seata
spring.cloud.alibaba.seata.tx-service-group=account_tx_group

                 Seata 客户端配置文件 file.conf、registry.conf:

                        下载地址:seata/script/client at develop · seata/seata · GitHub

                        将文件拷贝到项目 src/main/resources 文件夹下 

                        file.conf:

                                 

                数据源:Seata 通过代理数据源的方式实现分支事务,所以在应用中需要重新配置数据源,注入 io.seata.rm.datasource.DataSourceProxy

package com.hqyj.springCloudAlibabaAccount.config;

import com.zaxxer.hikari.HikariDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * @ClassName DataSourceProxyConfig
 * @Author ZhuYouWan
 * @Date 2022/9/30 11:32
 **/
@Configuration
@EnableTransactionManagement
@MapperScan(
        sqlSessionFactoryRef = "sqlSessionFactory",
        sqlSessionTemplateRef="sqlSessionTemplate",
        basePackages = "com.hqyj.springCloudAlibabaAccount.dao")
public class DataSourceProxyConfig {
    //读远程也没问题
    // hikari config
    @Value("${spring.datasource.hikari.maximum-pool-size}")
    private int maximumPoolSize;
    @Value("${spring.datasource.hikari.minimum-idle}")
    private int minimumIdle;
    @Value("${spring.datasource.hikari.idle-timeout}")
    private long idleTimeout;
    @Value("${spring.datasource.hikari.auto-commit}")
    private boolean autoCommit;

    // mybatis config
    @Value("${mybatis.configuration.map-underscore-to-camel-case}")
    private boolean mapUnderscoreToCamelCase;//下划线和驼峰的转化

    @Bean(name="hikariDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public HikariDataSource dataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setMaximumPoolSize(maximumPoolSize);
        hikariDataSource.setMinimumIdle(minimumIdle);
        hikariDataSource.setIdleTimeout(idleTimeout);
        hikariDataSource.setAutoCommit(autoCommit);
        return hikariDataSource;
    }
    @Bean(name="dataSourceProxy")
    public DataSource dataSourceProxy(@Qualifier("hikariDataSource") DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }
    @Bean(name="sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean(
            @Qualifier("dataSourceProxy") DataSource dataSourceProxy) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSourceProxy);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(mapUnderscoreToCamelCase);
        bean.setConfiguration(configuration);
        return bean.getObject();
    }

    @Bean(name="sqlSessionTemplate")
    public SqlSessionTemplate mainDbSqlSessionTemplate(
            @Qualifier("sqlSessionFactory") SqlSessionFactory sessionfactory) {
        return new SqlSessionTemplate(sessionfactory);
    }

    @Bean(name = "mybatisTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("dataSourceProxy") DataSource dataSourceProxy) {
        return new DataSourceTransactionManager(dataSourceProxy);
    }
}

                 回滚日志表 undo_log:注意,需要把datetime字段类型改为timestamp,否则会报 jackson 序列化异常

CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

                 应用:微服务小事务使用 @Transactional 注解,分布式大事务使用 @GlobalTransactional 注解;

                 例如:

小事务:

@Override
@Transactional
public Result<City> deleteCityByCityId(int cityId) {
	cityDao.deleteCityByCityId(cityId);
	return new Result<>(Result.ResultStatus.SUCCESS.code,"Delete success.");
}

大事务

@Override
@Transactional
@GlobalTransactional
public Result<UserVo> updateUserVo(UserVo userVo) {
	cityFeignClient.updateCity(userVo.getCity());
	if (userVo.getId() < 0){
		int i=1/0;
	}
	User user = new User();
	BeanUtils.copyProperties(userVo, user);
	userDao.updateUser(user);
	return new Result<UserVo>(Result.ResultStatus.SUCCESS.code, "Update success", userVo);
}

启动流程:Nacos → Sentinel → Seata Server → 其它微服务 

九、总结 

        以上便是SpringCloud Alibaba的一些常用组件,包括了微服务的注册中心、配置中心、负载均衡、微服务之间的接口调用、限流熔断、分布式事务处理。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值