tio-boot spring-cloud

概述

  • tio-boot 完全支持 spring-cloud
  • 仅仅是 web 中间件使用 tio-boot-server,其他组件仍然是 spring-cloud

tio-boot, Spring Cloud, 和 Consul

整合 tio-boot, Spring Cloud, 和 Consul 实现服务注册与发现是一种提升微服务架构可靠性和灵活性的有效方法。本文档将详细介绍如何创建两个服务,spring-cloud-consul-product-servicespring-cloud-consul-order-service,并通过 Consul 实现这两个服务的注册与发现。其中 product-service 提供接口,order-service 调用 product-service 的接口。

流程概述

  1. 启动 Consul: Consul 作为服务注册和服务发现的工具,可以通过简单的命令启动。
  2. 配置 product-service 包括 Maven 依赖配置、application 属性配置、启动类和相关组件的配置,确保服务可以正确注册到 Consul。
  3. 配置 order-service 类似于 product-service,配置相关依赖和属性,以及 RestTemplate 用于服务间的调用。
  4. 服务注册与发现: 服务启动后,会自动注册到 Consul,order-service 可以通过 Consul 发现 product-service 并进行调用。

启动 Consul

在开始之前,确保你有 Consul 环境,可以通过以下命令启动 Consul:

consul.exe agent -dev

product-service

  1. Maven 配置(pom.xml): 定义了项目的 Java 版本、依赖项(包括 Spring Boot、tio-boot、Spring Cloud Consul Discovery 等)。

pom.xml

  <properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.1.6.RELEASE</spring-boot.version>
    <tio-boot.version>1.6.2</tio-boot.version>
    <main.class>demo.ProductApp</main.class>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-json</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-reactor-netty</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>com.litongjava</groupId>
      <artifactId>tio-boot</artifactId>
      <version>${tio-boot.version}</version>
    </dependency>


    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.litongjava</groupId>
      <artifactId>hotswap-classloader</artifactId>
      <version>1.2.1</version>
    </dependency>

    <!-- SpringBoot集成Test -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>

    <!--SpringCloud提供的基于Consul的服务发现-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>

    <!--actuator用于心跳检查-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <!-- Spring Boot -->
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot.version}</version>
        <configuration>
          <includeSystemScope>true</includeSystemScope>
          <!--使该插件支持热启动 -->
          <fork>true</fork>
          <mainClass>${main.class}</mainClass>
        </configuration>
        <!-- 设置执行目标 -->
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Greenwich.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  1. 应用配置(application.yml): 指定了服务的端口、应用名称和 Consul 服务器的地址。

application.yml

server:
  port: 8001 #端口
spring:
  application:
    #访问名称
    name: consul-provider-product
  cloud:
    consul:
      #服务地址
      host: localhost
      #服务端口
      port: 8500
      discovery:
        service-name: ${spring.application.name}

app.properties

server.port=8001

app.properties 和 application.yml 都需要指定端口

  1. 启动类(ProductApp.java): 标记了 Spring Boot 应用、启用了服务发现,并导入了必要的配置。
package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Import;

import com.litongjava.jfinal.aop.annotation.AComponentScan;
import com.litongjava.tio.boot.spring.SpringBootArgs;
import com.litongjava.tio.boot.spring.TioBootServerAutoConfiguration;

@SpringBootApplication
@EnableDiscoveryClient
@AComponentScan
@Import(TioBootServerAutoConfiguration.class)
public class ProductApp {

  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    SpringBootArgs.set(ProductApp.class, args);
    SpringApplication.run(ProductApp.class, args);
    long end = System.currentTimeMillis();
    System.out.println((end - start) + "(ms)");
  }
}

  1. RestTemplate 配置(ApplicationContextConfig.java): 配置了 RestTemplate 并启用了负载均衡,使其可以通过服务名调用其他服务。
package demo.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class ApplicationContextConfig {


  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    log.info("restTemplate:{}", restTemplate.toString());
    return restTemplate;
  }
}

  1. Tio-Boot 集成配置(SpringBeanContextConfig.java): 配置了 tio-boot 与 Spring 的集成。
package demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.aop.AopManager;
import com.litongjava.jfinal.spring.SpringBeanContextUtils;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class SpringBeanContextConfig {

  @Autowired
  private ApplicationContext applicationContext;

  @Bean(destroyMethod = "close")
  @DependsOn("restTemplate")
  public void myBean() {
    log.info("add Autowired");
    // 开启和spring的整合
    AopManager.me().getAopFactory().setEnableWithSpring(true);
    SpringBeanContextUtils.setContext(applicationContext);
    // 让 tio-boot的bean支持Autowired注解
    Aop.addFetchBeanAnnotation(Autowired.class);
  }
}

  1. 健康控制器(ActuatorController.java): 定义了对外提供的 健康 接口。consul 会通过这个接口检查应用是否健康 ActuatorController
package demo.controller;

import java.util.HashMap;
import java.util.Map;

import com.litongjava.tio.http.server.annotation.RequestPath;

@RequestPath("/actuator")
public class ActuatorController {
  public Map<String, String> health() {
    HashMap<String, String> hashMap = new HashMap<>(1);
    hashMap.put("status", "up");
    return hashMap;
  }

}

  1. 业务控制器(ProductController.java): 定义了对外提供的 REST 接口。
package demo.controller;

import java.util.UUID;

import com.litongjava.tio.http.server.annotation.RequestPath;

@RequestPath
public class ProductController {

  @RequestPath("/product/consul")
  public String paymentConsul() {
    return "tio-boot with consul: " + UUID.randomUUID().toString();
  }
}

order-service

product-service 配置类似,不同之处主要在于 OrderController.java,在这里通过 RestTemplate 调用 product-service 提供的服务。

  • pom.xml 和 product-service 相同
  • 启动类 和 product-service 仅类名不同
  • ApplicationContextConfig 和 product-service 相同
  • SpringBeanContextConfig 和 product-service 相同
  • ActuatorController 和 product-service 相同
  • OrderController 调用 product-server
package demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import com.litongjava.jfinal.spring.SpringBeanContextUtils;
import com.litongjava.tio.http.server.annotation.RequestPath;

import demo.service.UserService;
import lombok.extern.slf4j.Slf4j;

@RequestPath("/consumer")
@Slf4j
public class OrderController {

  // consul服务中心的服务名称
  public static final String INVOKE_URL = "http://consul-provider-product";

  @Autowired
  RestTemplate restTemplate;

  public String getRestTemplate() {
    return restTemplate.toString();
  }

  @RequestPath(value = "/payment/consul")
  public String paymentInfo() {
    log.info("restTemplate:{}", restTemplate.toString());
    String result = restTemplate.getForObject(INVOKE_URL + "/product/consul", String.class);
    return result;
  }
}

测试服务调用

  1. 启动 Consul。
  2. 分别启动 product-serviceorder-service
  3. 通过访问 order-service 的 APIhttp://127.0.0.1:8002/consumer/payment/consul测试调用 product-service 是否成功。 显示如下说明调用成功
tio-boot with consul: c78c2ce5-fa6a-4218-94f2-add528f1e04d

源码地址

https://github.com/litongjava/java-ee-spring-cloud-study/tree/main/maven/spring-cloud-consul-study/spring-cloud-consul-tio-boot