← 返回首页
SpringCloud基础教程(五)
发表时间:2021-06-01 16:57:20
使用nacos作为注册中心和配置中心

本案例提供2020版本的最佳实践方案,使用我认为最容易学习的组件,可能很多组件有很多替代方案,在这里不依依讲述。本案例使用的组件如下:

本案例总体架构如下:

本案例包括2个模块,一个服务提供者provider 、服务消费者consumer。

在父模块(pom)添加依赖如下:

   <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring-boot.version>2.4.4</spring-boot.version>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
        <spring-cloud-alibaba.version>2020.0.RC1</spring-cloud-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- spring boot 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring cloud 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring cloud alibaba 依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

服务提供者provider

在provider的pom文件引入依赖:

<!--springcloud依赖-->
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置文件application.yml:

server:
  #端口配置
  port: 8762
  #上下文
  servlet:
    context-path: /springbootdemo
#数据源配置
spring:
  application:
    name: provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

在config包下创建ServerConfig,实现一个getIp方法用来获取当前服务的IP地址和端口号。


@Configuration
public class ServerConfig  implements ApplicationListener<WebServerInitializedEvent> {

    private int serverPort;

    //获取内置tomcat端口号
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.serverPort = event.getWebServer().getPort();
    }

    // 获取项目IP
    public String getIp() {
        InetAddress address = null;
        try {
            address = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        if(this.serverPort == 0){ // 获取外置tomcat端口号
            this.serverPort = getTomcatPort();
        }
        return "http://"+address.getHostAddress() +":"+this.serverPort;
    }

    public int getTomcatPort() {
        MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
        try {
            QueryExp protocol = Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"));
            ObjectName name = new ObjectName("*:type=Connector,*");
            Set<ObjectName> objectNames = beanServer.queryNames(name, protocol);
            for (ObjectName objectName : objectNames) {
                String catalina = objectName.getDomain();
                if ("Catalina".equals(catalina)) {
                    return Integer.parseInt(objectName.getKeyProperty("port"));
                }
            }
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        }
        return 0;
    }
}

在controller包下存在有以下测试接口。


@RestController
@RequestMapping("goods")
public class ItemsController {

    @Resource
    private GoodsService goodsService;
    @Autowired
    private ServerConfig serverConfig;

    @GetMapping("query/{catalog}")
    public Map<String,Object> queryAllGoodsListByCatalogName(@PathVariable("catalog")  String catalogName){
        Map<String, Object> result = new HashMap<String, Object>();
        //执行这个接口的时候,请问大家,程序如何获得当前服务的ip地址和端口号。

        try {
            List<Goods> goodsList = goodsService.queryAllGoodsListByCatalog(catalogName);
            result.put("code", 200);
            result.put("msg", "查询所有商品列表成功!");
            result.put("data", goodsList);
            //用来测试负载均衡时,Consumer可以查询调用那个provider的服务。
            result.put("host", serverConfig.getIp());
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
            result.put("code", 400);
            result.put("msg", "程序出现错误!");
            return result;
        }
    }
}

在provider启动类添加@EnableDiscoveryClient

@RestController
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("com.oracle.springbootdemo.mapper")
public class MallServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(MallServerApplication.class, args);
        //输出sa-token的基本配置
        System.out.println("启动成功:sa-token配置如下:" + SaManager.getConfig());
    }
}

服务消费者consumer

在pom文件引入以下依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</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-starter-loadbalancer</artifactId>
        </dependency>

需要注意的是引入openfeign,必须要引入loadbalancer,否则无法启动。

配置文件:

server:
  port: 8763

spring:
  application:
    name: consumer

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

在consumer工程的启动类开启FeignClient的功能:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {

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

}

在repository包下写一个FeignClient,去调用provider服务的接口:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "provider" )
public interface ProviderClient {

    @GetMapping("/springbootdemo/items/catalog")
    String queryItemsListByCatalogName(@RequestParam(value = "catalogName", defaultValue = "all", required = true) String catalogName);
}

在controller包下写一个接口,让consumer去调用provider服务的接口:

@RestController
public class ConsumerController {

    @Autowired
    ProviderClient providerClient;

    @GetMapping("/items/catalog")
    public String itemsCatalogList(@RequestParam(value = "catalogName",required = true,defaultValue = "all") String catalogName){return providerClient.queryItemsListByCatalogName(catalogName);}
}

服务调用:

启动两个工程,在nacos页面查看,可见2个服务都已经注册成功:

在浏览器上输入http://localhost:8763/items/catalog?catalogName=食品,浏览器返回响应:

[{"version":0,"createTime":"2020-04-16 00:01:54","modifyTime":null,"flag":true,"id":97,"name":"康师傅红烧牛肉面","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_33.jpg","number":500,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2020-11-08 11:40:05","modifyTime":null,"flag":true,"id":102,"name":"统一老谭酸菜面","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_34.jpg","number":500,"catalog":"食品","city":"长沙","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2020-11-09 15:37:12","modifyTime":null,"flag":true,"id":103,"name":"康师傅西红柿牛腩面","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_33.jpg","number":500,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2020-11-09 16:26:40","modifyTime":null,"flag":true,"id":104,"name":"白象方便面","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_35.jpg","number":500,"catalog":"食品","city":"郑州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2020-11-17 17:19:56","modifyTime":null,"flag":true,"id":105,"name":"韩国火鸡方便面","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_36.jpg","number":500,"catalog":"食品","city":"沈阳","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2020-11-17 17:19:58","modifyTime":null,"flag":true,"id":106,"name":"农心辛拉面","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_37.jpg","number":500,"catalog":"食品","city":"沈阳","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2020-11-17 17:19:59","modifyTime":null,"flag":true,"id":107,"name":"太阳牌锅巴","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_38.jpg","number":500,"catalog":"食品","city":"西安","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":1,"freePost":false},{"version":0,"createTime":"2021-02-05 09:25:41","modifyTime":"2021-02-05 09:25:41","flag":true,"id":111,"name":"诸葛卧龙手工锅巴","price":10,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_42.jpg","number":0,"catalog":"食品","city":"武汉","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-02-05 10:34:32","modifyTime":"2021-02-05 10:34:32","flag":true,"id":112,"name":"百吉猫手工锅巴","price":12,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_43.jpg","number":0,"catalog":"食品","city":"西安","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-02-05 10:34:34","modifyTime":"2021-02-05 10:34:34","flag":true,"id":113,"name":"北京牌方便面","price":1,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_44.jpg","number":0,"catalog":"食品","city":"武汉","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-03-25 11:25:35","modifyTime":"2021-03-25 11:25:35","flag":true,"id":114,"name":"老襄阳手工锅巴","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_45.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-03-25 11:27:32","modifyTime":"2021-03-25 11:27:32","flag":true,"id":115,"name":"蒙牛纯牛奶","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_46.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-03-25 11:27:32","modifyTime":"2021-03-25 11:27:32","flag":true,"id":116,"name":"夏进纯牛奶","price":3,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_47.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-03-25 11:32:29","modifyTime":"2021-03-25 11:32:29","flag":true,"id":117,"name":"完达山纯牛奶","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_48.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-03-25 11:33:29","modifyTime":"2021-03-25 11:33:29","flag":true,"id":118,"name":"君乐宝纯牛奶","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_49.jpg","number":0,"catalog":"食品","city":"石家庄","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-04-01 14:28:20","modifyTime":"2021-04-01 14:28:20","flag":true,"id":119,"name":"伊利纯牛奶","price":4,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_50.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-04-01 14:28:55","modifyTime":"2021-04-01 14:28:55","flag":true,"id":120,"name":"澳大利进口纯牛奶","price":12,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_51.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-04-01 14:33:50","modifyTime":"2021-04-01 14:33:50","flag":true,"id":121,"name":"徐福记沙琪玛","price":16,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_52.jpg","number":0,"catalog":"食品","city":"杭州","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-04-01 14:35:21","modifyTime":"2021-04-01 14:35:21","flag":true,"id":122,"name":"三只松鼠沙琪玛","price":15,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_53.jpg","number":0,"catalog":"食品","city":"南京","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false},{"version":0,"createTime":"2021-04-06 20:09:07","modifyTime":"2021-04-06 20:09:07","flag":true,"id":123,"name":"稻香村沙琪玛","price":20,"pic":"http://114.67.88.176:8080/examdemo/images/api/goodList/pics_small/good_54.jpg","number":0,"catalog":"食品","city":"北京","property":null,"province":null,"shopId":0,"shopName":null,"discount":0.0,"buyCount":0,"status":0,"freePost":false}]

测试负载均衡:

其实feign使用了spring cloud loadbanlancer作为负载均衡器。 可以通过修改provider的端口,再在本地启动一个新的provider服务,那么本地有2个provider 服务,端口分别为8761 和8762。在浏览器上多次调用http://localhost:8763/items/catalog?catalogName=食品 接口,可以获得不同provider返回的数据。

idea2022.3 运行启动多个springboot实例配置如下: