分布式组件

271 阅读7分钟

分布式组件

看到很多帖子,说SpringCloud的eureka停止维护了,开始采用SpringCloud Alibaba的Nacos作为注册中心和配置中心,也具有可视化监控界面,非常方便。

中文文档

配置SpringCloud Alibaba的依赖管理器

配置后,SpringCloud Alibaba的组件依赖就不用规定版本了,都交给依赖管理器统一管理。

注意:版本需要跟SpringBoot的版本相互对应,要不会不兼容冲突。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2021.0.1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Nacos

Nacos 致力于发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

安装

由于兼容性问题,我安装的是1.1.3版本的nacos,不会出现启动闪退的情况。

注意:启动Nacos是要使用java环境的,请确定环境变量中添加了JAVA_HOME, %JAVA_HOME%\bin

安装后启动startup程序:

会启动nacos服务器,该服务器的是默认在localhost:8848启动的:

注意:在Springboot项目启动过程中,Nacos一定要保持在线状态!!

配置 注册中心(nacos-discovery)

注册中心,采用注册发现机制,上线一个微服务,就会到注册中心进行注册,注册中心对所有服务统一进行管理。

依赖配置

将子工程都需要的依赖导入父工程中,然后子工程依赖父工程,子工程就不用一个个配置相同的依赖了,方便很多。

注意,官网的是boot在2.4以下的依赖,如果是2.6X版本,需要排除ribbon,并且导入loadbalancer依赖。

<!--配置nacos注册中心(服务注册发现)-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.netflix.ribbon</groupId>
            <artifactId>ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--loadbalancer-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
    <version>3.1.1</version>
</dependency>

注解配置

微服务中,每启动一个服务,都需要注册到注册中心中统一管理,那么在远程调用的时候,就知道哪些服务在线,方便进行相应的调用。

如何让一个应用注册到Nacos呢?其实及其简单,在主程序上加上一个注解@EnableDiscoveryClient就可以解决了!

@SpringBootApplication
//开启了应用服务注册发现功能
@EnableDiscoveryClient
@EnableFeignClients(basePackages= "com.gulimall.member.feign")
public class GulimallMemberApplication {
    public static void main(String[] args) {
        SpringApplication.run(GulimallMemberApplication.class, args);
    }
}

配置文件

同时需要在应用配置文件Application.yml中配置相应的服务名,和Nacos服务器地址

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-member  //名字最好与服务模块名一样,方便管理

测试

这样,服务注册发现的配置就差不多配好了,咱们启动相应的服务,并访问http://localhost:8848/nacos/index.html,就可以进入到Nacos主页,登录进去,可以看到相应服务的状态,就可以可视化管理微服务了:

配置 配置中心(nacos-config)

以前,如果要更改服务的某个配置,需要下线服务后修改好再重新打包部署上线,单体服务还好,但如果服务集群,那真的是裂开,有没有一种办法能统一管理一种服务的所有配置,并动态更改服务配置,就非常方便。

nacos-config组件,就是一个配置中心,可以将一个服务的配置全部托管至配置中心中管理,就不需要再在服务配置文件中做过多冗余配置了。

配置依赖

注意:SpringBoot2.4x之前的只需要导入nacos-config启动器,但是后面的版本还需要导入BootStrap依赖

<!--nacos配置中心-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bootstrap -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
    <version>3.1.1</version>
</dependency>

配置文件

需要添加一个BootStrap.Properties配置文件,这个文件优先级是高于Application.properties的,在其中配置服务名和Nacos地址。

spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

传统方式,在Applicaiton.yml中添加配置:

coupon:
    user:
        name:jh
        age:20

之后通过@value("${coupon.user.name}")来获取相应的属性值,现在有了配置中心,所有配置都可以转移到配置中心上管理。

启动项目

观察到本地的配置跟可以跟Nacos配置中心的名字(Data Id)为 应用名.properties 的配置进行绑定。

那么我们在配置中心上添加一个Data Id为 应用名.properties 的配置,就可以绑定到相应服务的配置了。

注意:创建的配置一定是Properties,yml可能出错噢!!

我们就不用在本地配置文件中编写属性配置了,直接交给配置中心统一管理就行了。

@RefreshScope

动态更新配置注解。

注意:如果配置中心和当前应用配置文件中都配置了相同的属性项。配置中心优先

命名空间

用作配置隔离。(一般每个微服务一个命名空间)

  • 默认为public命名空间
  • 可以自定义命名空间

一般,一个微服务就对应一个命名空间,方便对不同的服务配置做统一管理。

配置集

类似于配置文件名,即Data ID(就是配置的名字加类型)

配置分组

不同配置对应的组别。默认所有的配置集都属于DEFAULT_GROUP

配置分类

往往将所有配置都写在一个配置文件中太过于复杂,且不易于维护,我们可以将整体配置按不同类型拆分成多个小的配置文件,合起来便是整个配置文件。

如何将本地的配置转移到配置中心呢?

很简单,只用在bootstrap.properties中添加相应的配置就行了。

注意:所有配置中心的配置都要写在bootstrap.properties中。

# 声明应用名
spring.application.name=gulimall-coupon
# nacos地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848# 使用对应命名空间号下的配置
spring.cloud.nacos.config.namespace=417a06cb-3f8e-4b49-8010-c9b2684c217f
# 选择对应命名空间下对应组的配置
spring.cloud.nacos.config.group=dev
​
# 扩展配置文件声明
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
# 确认对应配置文件的组别
spring.cloud.nacos.config.extension-configs[0].group=dev
# 开启自动刷新
spring.cloud.nacos.config.extension-configs[0].refresh=true
​
spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true
​
spring.cloud.nacos.config.extension-configs[2].data-id=other.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

通常,我们采取每个微服务创建自己的命名空间,使用配置分组来区分环境(dev,test,prod...),同时一个环境的配置又可以通过分类拆分成小的配置文件,方便管理。 但是,在开发过程中,为了方便,配置文件还是先写在本地,等部署完善后,再将配置转移至配置中心管理。

远程调用(Feign)

微服务中肯定存在互相调用,那么如何找到相应的服务并调用其中的接口,就要结合注册中心和Feign组件来完成。

配置依赖

在构建boot项目时勾选上SpringCloud的OpenFeign模块,就会导入相应依赖:

<!--配置SprigCloud-OpenFeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

编写远程调用接口

不同微服务间通过Feign类来进行关联,编写相应的Feign:

//@FeignClient声明此类是一个远程调用接口,参数为对应要调用服务的服务名
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
    @RequestMapping("/coupon/coupon/member/list")
    public R memberCoupons();
}

对应的服务接口方法

@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;
    
    @RequestMapping("/member/list")
    public  R memberCoupons()
    {
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponName("满100减10");
        return R.ok().put("coupons", Arrays.asList(couponEntity));
    }
}

只需要把要调用服务的接口方法复制到Feign中,代表了想要调用对应服务的接口方法,调用接口的每一个方法都对应调用相应服务的一个接口。

主程序配置

同时,我们需要应用能够扫描到Feign并加载,在主程序中加上相应的@EnableFeignClients注解:

@SpringBootApplication
//开启注册发现功能
@EnableDiscoveryClient
//开启远程调用功能,启动应用时,扫描该包下的所有带@FeignClient注解类,这些类就是远程调用的一个个接口。
@EnableFeignClients(basePackages= "com.gulimall.member.feign")
public class GulimallMemberApplication {

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

测试

编写一个controller

@RestController
@RequestMapping("member/member")
public class MemberController {
    @Autowired
    private MemberService memberService;

    @Autowired
    //注入Feign组件
    private CouponFeignService couponFeignService;

    @RequestMapping("/coupons")
    public R test()
    {
        MemberEntity memberEntity = new MemberEntity();
        memberEntity.setNickname("张三");
        R r = couponFeignService.memberCoupons();
        Object coupons = r.get("coupons");

        return R.ok().put("member",memberEntity).put("coupons",coupons);
    }
}

启动两个服务,服务必须都上线,要不肯定不能完成相互调用,上线后,并访问相应接口,可以完成调用相应服务的对应接口。

调用原理

调用远程调用接口的相应方法 --> 先去注册中心中找相应服务名的服务 --> 在匹配当前接口和调用服务的接口,完成匹配 --> 调用成功