spring cloud alibaba学习笔记(一)使用nacos作为服务注册与配置中心

之前一直在使用nginx + spring boot + dubbo 的一个分布式框架,用过spring cloud发现当服务完全细分之后才能发挥出cloud的优势,在大多数情况下dubbo是够用,后来听说spring cloud alibaba可以兼容spring cloud和dubbo,所以这才来学习一下。首先贴上spring cloud alibaba源码github地址

nacos安装

首先建议看一下nacos的官方介绍,是阿里开源的一个服务注册、配置、管理中心。支持Kubernetes,dubbo,spring cloud的服务注册。相比zookeeper和eureka单纯的服务治理来说,多了配置的功能。
两种安装方式:

  1. git clone 源码编译
git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin
  1. 下载稳定版本
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
  cd nacos/bin

下载完成后,新建一个mysql数据库,执行conf目录下的nacos-mysql.sql文件,
然后在application.properties文件中配置数据库信息

spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://ip地址:端口/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=数据库用户名
db.password=数据库密码

配好之后就准备启动啦
windows环境下
双击 startup.cmd 或者cmd startup.cmd
linux/mac/unix
sh startup.sh -m standalone
如果使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,执行
bash startup.sh -m standalone
或者是将startup.sh文件中的#!/bin/sh 替换成 #!/bin/bash

启动好了之后访问http://ip:8848就可以了,会出现如下界面,账号密码默认都是nacos,登入之后可以修改密码。
登录进来这边是自己新建的两个配置文件
这边nacos就好啦,接下来就是java代码了。

项目结构

我们按照生产-消费-网关的模式搭建一个小的结构
在这里插入图片描述

父工程

首先创建一个工程作为父工程,引入相关依赖。
说一下,spring boot 和 spring cloud的版本兼容相当重要,参考一下

下面是需要引入的依赖

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!--引入配置中心阿里巴巴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--引入注册中心阿里巴巴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

    </dependencies>

service-provider 生产者

  1. bootstrap.properties
#使用配置中心时,必须使用bootstrap.properties/yml作为本地配置文件,优先加载bootstrap
spring.application.name=service-provider-sys
#nacos配置中心
spring.cloud.nacos.config.server-addr=ip:8848
#nacos配置文件类型
spring.cloud.nacos.config.file-extension=yaml
#nacos服务注册中心
spring.cloud.nacos.discovery.server-addr=ip:8848

启动类加上开启cloud服务注册注解

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProviderSysApplication {

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

}

control层,这里获取一下从nacos配置的端口号

@RestController
@RequestMapping("/sys")
public class SysController {

    @Value("${server.port}")
    String port;

    @GetMapping("/say")
    public String say(@RequestParam("name") String name) {
        return "Hello " + name + ", I'm from port " + port;
    }
}

service-consumer 消费者

这里的消费和生产只是一个相对的概念,在微服务中其实每一个服务都是消费者和生产者,所以才能形成微服务网。
引入依赖

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

启动类,这里注入一个RestTemplate ,实现两种服务调用的方式

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceConsumerSysApplication {

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

	@LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

control层

@RestController
public class SysController {

    @Autowired
    private SysService sysService;

    @Autowired
    private RestTemplate restTemplate;

        @GetMapping("/hello-feign/{name}")
    public String hello(@PathVariable String name) {
        return sysService.say(name);
    }

    @GetMapping("/hello/{name}")
    public String helloFeign(@PathVariable String name) {
        return restTemplate.getForObject("http://service-provider-sys/sys/say?name=" + name, String.class);
    }

}

基于feign实现的服务调用service

@FeignClient(value = "service-provider-sys", fallback = SysServiceFallback.class)
public interface SysService {

    @RequestMapping(value = "/sys/say", method = RequestMethod.GET)
    String say(@RequestParam("name") String name);
}

然后是feign调用失败的回调类,这里实现对应的接口,配置好feign的配置类和实现类

@Slf4j
@Component
public class SysServiceFallback implements SysService {

    @Override
    public String say(String name) {
        log.error("消费降级{}", name);
        return "Sentinel {由于你的访问次数太多,已为你限流、您已进入保护模式,请稍后再试!}>>>熔断处理函数";
    }
}

最后是bootstrap.properties的配置

#使用配置中心时,必须使用bootstrap.properties作为本地配置文件
#nacos 配置文件的data-id前缀
spring.application.name=service-consumer-sys
#nacos配置中心配置
spring.cloud.nacos.config.server-addr=ip:8848
spring.cloud.nacos.discovery.server-addr=ip:8848
spring.cloud.nacos.config.file-extension=yaml
#如果加上这个配置,会读取该文件名的配置
#spring.cloud.nacos.config.name=name-test

然后回到刚才nacos的界面,新增一个配置文件

这里是给应用设置一个端口,这里需要注意的是,注册中心和配置中心是需要在配置文件中配置的,不用我解释吧~

接下来启动啦
这边看到本地是没有配置端口的,但是启动之后没有使用默认的8080端口,而是使用了nacos上配置的8000端口。
在这里插入图片描述
首先provider的访问是没有问题的~
在这里插入图片描述
然后是consumer访问依然没有问题
在这里插入图片描述
我们来看一下nacos的注册信息

到这里基本上简单的注册和配置基本上就ok了。

service-gateway 网关

spring cloud最开始使用的组件是zuul,但是之前发现一个是不稳定,另外性能相比gateway和nginx差了很多,后来的zuul2还没有尝试过,我们这次使用的是gateway。
依赖gateway

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

启动类

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceGatewayApplication {

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

}

配置文件

spring:
  application:
    name: service-gateway
  cloud:
    nacos:
      config:
        server-addr: ip:8848
        file-extension: yaml
      discovery:
        server-addr: ip:8848
    sentinel:
      transport:
        dashboard: 127.0.0.1:8849
      eager: true
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: service-consumer-sys #id随便,不冲突就行
          uri: lb://service-consumer-sys # 服务注册的name,一定要和服务名一样
          predicates:
            - Method=GET,POST # 允许的请求
            - Path=/api-c/** #这里加上下面的StripPrefix类似nginx的一个转发
          filters:
            - StripPrefix=1
        - id: service-provider-sys
          uri: lb://service-provider-sys
          predicates:
            - Method=GET,POST
            - Path=/api-s/**
          filters:
            - StripPrefix=1

server:
  port: 9000
  
logging:
  level:
    org.springframework.cloud.gateway: debug

添加一个拦截器

@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    private static final String HEAR_AUTH = "Authorization";

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String ip = getIpAddress(request);
        String token = request.getHeaders().getFirst(HEAR_AUTH);
        if (token == null || token.isEmpty()) {
            ServerHttpResponse response = exchange.getResponse();
            Map<Object, Object> map = Maps.newHashMap();
            map.put("code", 401);
            map.put("message", "非法请求!");
            map.put("cause", "Token is null");
            map.put("ip", ip);
            ObjectMapper mapper = new ObjectMapper();
            // 输出错误信息到页面
            DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(map).getBytes());
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            return response.writeWith(Mono.just(buffer));

        }
        return chain.filter(exchange);
    }

    private String getIpAddress(ServerHttpRequest request) {
        //HttpHeaders headers = request.getHeaders();
        String ip;
        try {
            //根据header获取相应校验
            //logger.info(headers.getFirst("Authorization"));
            //List<String> list = headers.get("x-forwarded-for");
            InetSocketAddress address = request.getRemoteAddress();
            assert address != null;
            InetAddress inetAddress = address.getAddress();
            ip = inetAddress.getHostAddress();
            log.info("inetAddress host name :" + inetAddress.getHostName());
        } catch (Exception e) {
            log.error(e.getMessage());
            ip = "";
        }
        return ip;
    }
}

这里是一个简单的拦截器,校验做一个简单的header校验。
然后说一下yml的配置,注册中心和配置中心先不说了,spring cloud alibaba 对sentinel有着很好的支持,优秀的服务降级,流量监控,配置持久化,如果项目体量不够大其实可以用到cloud自身的hystrix熔断就够了,。
启动网关。
没有header的情况下,我们看到返回了自己配置的401.

加上之后我们看到转发成功。

然后我又启动了一个端口为8002的provider,可以看到多次请求的时候,不管是feign还是resttemplate的请求方式都是轮询请求,也就是LoadBalanced。

最后

今天的代码虽然比较简单,其实还有些问题

  1. hystrix对openfeign的支持应该是加了feign.hystrix.enabled=true之后会启用的,我之前使用springcloud的时候也是没问题的,但这次不知道为什么没有执行feign的fallback方法,这个我研究一下再更新。
    自己发现是请求的url错了,应该是请求/hello-feign的接口,我也是醉了,但是feign.hystrix.enabled=true一定要加上
  2. 有些常用的依赖我没有贴出来,缺失的话大家可以自己去找下
    如果大家有好的想法也可以提出来讨论,一起学习。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

紫金丨小飞侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值