Tio Boot 的整合 spring-boot-starter-web

概述

什么是 Spring Boot 框架?

  • Spring Boot 是一个广泛使用的框架,它提供了一种快速、简单的方式来设置和启动 Spring 应用。它的自动配置、内置服务器和控制器使得开发 Web 应用变得更加容易。

为什么使用 Spring Boot 框架整合 Tio-Boot? 使用 Spring Boot 整合 Tio-Boot 有以下几个优势:

  • Tio-Boot 框架的代码可以在 Spring Boot 框架下运行。
  • 开发时使用 Tio-Boot 框架进行快速开发,开发完成后使用 Spring Boot 框架运行。
  • 可以利用 Spring Boot 对微服务的支持,将 Tio-Boot 框架作为一个微服务整合到 Spring Cloud 中。

Spring Boot 和 Tio-Boot 能否实现无缝整合?

  • 无法实现完全无缝的整合。
  • 对于 HTTP 服务器、请求参数封装、控制器以及微服务,仍然使用 Spring Boot 框架。
  • 对于其他服务,如服务器和数据库查询等,使用 Tio-Boot 框架。
  • 整合 Spring Boot 之后因为使用的是 spring-boot 内置的 http server 将无法使用 tio boot 的异步和非阻塞的方式处理网络请求

添加依赖

请将以下依赖添加到你的项目中,这些依赖包括 spring-boot 和 tio-boot 的相关依赖,以及一些其他必要的库。

  1. properties:这部分定义了一些全局变量,可以在 pom.xml 文件的其他地方引用。例如,${java.version} 在这里被定义为 1.8,然后在 <maven.compiler.source><maven.compiler.target> 中被引用,表示编译源代码和目标 JVM 的版本都是 1.8。

  2. dependencies:这部分列出了项目所依赖的库。每个 <dependency> 标签定义了一个依赖项,包括其 groupId(通常是项目的包名),artifactId(项目名),以及版本号。有些依赖项还定义了 <scope>,这决定了依赖在什么阶段可用。例如,<scope>test</scope> 表示这个依赖只在测试阶段可用。

    1. spring-boot-starter-web:这是 Spring Boot 的一个启动器,它包含了创建一个基于 Spring MVC 的 Web 应用所需的所有依赖。这意味着你的项目可能是一个 Web 应用。
    1. lombok:Lombok 是一个可以通过注解的方式,使 Java 代码更简洁的库。它提供了一系列的注解,如 @Data@Getter@Setter 等,可以自动为类生成 getter 和 setter 方法,以及 equals()hashCode()toString() 方法。<scope>provided</scope> 表示这个依赖在编译和运行时都需要,但在打包成最终的 JAR 或 WAR 文件时,不需要包含进去。
    1. spring-boot-starter-testjunit:这两个依赖都是用于测试的。spring-boot-starter-test 包含了使用 Spring Boot 进行集成测试所需的所有依赖,而 junit 是 Java 的一个单元测试框架。这两个依赖的 <scope> 都被设置为 test,表示它们只在测试阶段可用。
    1. tio-boot: 高性能的 JavaWeb 开发框架
    1. java-db:JFinal 框架的插件库。
    1. druid:Druid 是 Alibaba 开发的一个数据库连接池。它提供了强大的监控和扩展功能。
  • 7 mysql-connector-java:这是 MySQL 的 JDBC 驱动,用于在 Java 应用中连接 MySQL 数据库。

  1. build:这部分定义了构建项目时要使用的插件和配置。在这里,你使用了 spring-boot-maven-plugin 插件,它可以创建一个可执行的 JAR 文件,包含了所有的依赖和应用服务器。

  2. dependencyManagement:这部分允许你集中管理项目中所有的版本号,避免在每个 <dependency> 标签中都要写版本号。在这里,你引入了 spring-boot-dependencies,这是一个特殊的依赖,它包含了 Spring Boot 项目中所有可能用到的依赖的版本号。

<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.5.6</spring-boot.version>
    <main.class>com.litongjava.spring.boot.tio.boot.demo01.Applicaton</main.class>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </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>

    <dependency>
      <groupId>com.litongjava</groupId>
      <artifactId>tio-boot</artifactId>
      <version>1.3.5</version>
    </dependency>

    <dependency>
      <groupId>com.litongjava</groupId>
      <artifactId>java-db</artifactId>
      <version>1.0.1</version>
    </dependency>
    <!-- 连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
    <!-- 数据库驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</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>
          <excludeGroupIds>org.projectlombok</excludeGroupIds>
        </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>
    </dependencies>
  </dependencyManagement>

编写代码

启动类

这是一个 Spring Boot 应用的启动类,它同时启动了 SpringApplication 和 TioApplication。:

  1. @SpringBootApplication:这是一个组合注解,它包含了 @AConfiguration@EnableAutoConfiguration@AComponentScan。这个注解告诉 Spring Boot 这个类是一个配置类,也是自动配置和组件扫描的起点。

  2. @AComponentScan:这是一个自定义注解,用于 tio-boot 扫描类

  3. main 方法:这是 Java 程序的入口点。在这个方法中,首先启动了 SpringApplication,然后又启动了 TioApplication。

    • SpringApplication.run(Applicaton.class, args):这行代码启动了 Spring Boot 应用。它会创建一个 Spring 应用上下文,执行自动配置,然后启动 Spring Boot 的内嵌服务器(如果有的话)。

    • TioApplication.run(Applicaton.class, newArgs):这行代码启动了 TioApplication。在启动之前,它添加了一个参数 --tio.noServer=true 到参数列表中。这个参数的目的是告诉 TioApplication 不启动 Tio Boot 的服务器。这样就可以只启动 Spring Boot 的服务器.

  4. 计算启动时间:这段代码计算了从启动 SpringApplication 到启动 TioApplication 的总时间,并打印出来。

package com.litongjava.spring.boot.tio.boot.demo01;

import java.util.ArrayList;
import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.litongjava.jfinal.aop.annotation.AComponentScan;
import com.litongjava.tio.boot.TioApplication;

@SpringBootApplication
@AComponentScan
public class Applicaton {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    SpringApplication.run(Applicaton.class, args);

    List<String> list = new ArrayList<String>();
    for (int i = 0; i < args.length; i++) {
      list.add(args[i]);
    }
    list.add("--tio.noServer=true");
    String[] newArgs = list.toArray(new String[] {});

    TioApplication.run(Applicaton.class, newArgs);
    long end = System.currentTimeMillis();
    System.out.println(end - start + "(ms)");
  }
}

编写配置类连接数据库

配置类中包含了连接数据库的设置,使用 DruidPlugin 和 ActiveRecordPlugin。

  1. @AConfiguration:这是一个 tio-boot 注解,用于标记这个类是一个配置类。

  2. druidPlugin 方法:这个方法用于创建和配置一个 DruidPlugin 对象,这是一个数据库连接池插件。它使用了 @ABean(priority = 10) 注解用于告诉 Tio Boot 在其他 Bean 之前创建这个 Bean。在这个方法中,首先定义了数据库的连接信息,然后创建了一个 DruidPlugin 对象,并启动了它。

  3. activeRecordPlugin 方法:这个方法用于创建和配置一个 ActiveRecordPlugin 对象,这是一个 数库查询 插件。它使用了 @ABean 注解,用于告诉 Tio Boot 这个方法返回的对象应该被管理为一个 Bean。在这个方法中,首先从 Tio Boot 的 Aop 容器中获取了 DruidPlugin 对象,然后创建了一个 ActiveRecordPlugin 对象,并设置了一个新的 OrderedFieldContainerFactory 对象作为其容器工厂,最后启动了它。

package com.litongjava.spring.boot.tio.boot.demo01.config;

import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.aop.annotation.ABean;
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.litongjava.jfinal.plugin.activerecord.OrderedFieldContainerFactory;
import com.litongjava.jfinal.plugin.druid.DruidPlugin;

@AConfiguration
public class ActiveRecordPluginConfig {
  @ABean(priority = 10)
  public DruidPlugin druidPlugin() {
    String jdbcUrl = "jdbc:mysql://192.168.3.9:3306/mybatis_plus_study";
    String jdbcUser = "root";
    String jdbcPswd = "robot_123456#";

    DruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, jdbcUser, jdbcPswd);
    druidPlugin.start();
    return druidPlugin;
  }

  @ABean
  public ActiveRecordPlugin activeRecordPlugin() {
    DruidPlugin druidPlugin = Aop.get(DruidPlugin.class);
    ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
    arp.setContainerFactory(new OrderedFieldContainerFactory());
    arp.start();
    return arp;
  }
}

编写 UserService 接口

创建 UserService 接口,定义了获取用户列表的方法。

package com.litongjava.spring.boot.tio.boot.demo01.services;

import java.util.List;

import com.litongjava.jfinal.plugin.activerecord.Record;

public interface UserService {
  List<Record> listAll();
}

编写 UserServiceImpl 实现类

实现 UserService 接口,通过调用数据库操作获取用户列表。这是一个 tio boot 的 service,使用了@AService 注解

package com.litongjava.spring.boot.tio.boot.demo01.services;

import java.util.List;

import com.litongjava.jfinal.aop.annotation.AService;
import com.litongjava.jfinal.plugin.activerecord.Db;
import com.litongjava.jfinal.plugin.activerecord.Record;

@AService
public class UserServiceImpl implements UserService {

  public List<Record> listAll() {
    return Db.findAll("user");
  }
}

编写 UserController

在 Controller 中调用 UserService,返回获取的用户数据。这个是 spring 的 controller 使用了@RestController,在方法中使用了 Aop.get 方法从 tio boot 的 aop 容器中获取一个 bean

package com.litongjava.spring.boot.tio.boot.demo01.AController;

import java.util.List;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.plugin.activerecord.Record;
import com.litongjava.spring.boot.tio.boot.demo01.services.UserService;

@RestController
@RequestMapping("/user")
public class UserController {

  @RequestMapping("/listAll")
  public List<Record> listAll(){
    return Aop.get(UserService.class).listAll();
  }
}

访问接口测试

启动项目后,访问接口测试:http://localhost:10510/user/listAll

打包成 fastjar

使用以下命令将项目打包成 fastjar:

mvn clean install -DskipTests -Dgpg.skip

启动 fastjar

使用以下命令启动 fastjar:

java -jar target\spring-boot-2.5.6-tio-boot-1.0.jar

再次访问接口测试:http://localhost:10510/user/listAll

测试 UserService

编写一个测试类 UserServiceTest,测试 UserService

package com.litongjava.spring.boot.tio.boot.demo01.services;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

import com.litongjava.jfinal.aop.Aop;
import com.litongjava.jfinal.plugin.activerecord.Record;
import com.litongjava.spring.boot.tio.boot.demo01.Applicaton;
import com.litongjava.tio.boot.TioApplication;

public class UserServiceTest {

  @Before
  public void before() {
    List<String> list = new ArrayList<String>();
    list.add("--tio.noServer=true");
    String[] args = list.toArray(new String[] {});
    TioApplication.run(Applicaton.class, args);
  }

  @Test
  public void test() {
    UserService userService = Aop.get(UserService.class);
    List<Record> listAll = userService.listAll();
    System.out.println(listAll);
  }
}

这是一个使用 JUnit 框架编写的测试类,用于测试 UserService 类的功能。

  1. @Before:这是一个 JUnit 注解,表示 before() 方法会在每个测试方法执行之前运行。在这个方法中,它启动了 TioApplication,但是通过添加 --tio.noServer=true 参数,不启动 Tio Boot 的服务器。

  2. @Test:这是一个 JUnit 注解,表示 test() 方法是一个测试方法。在这个方法中,首先从 tio-boot aop 容器中获取了 UserService 对象,然后调用了 listAll() 方法获取所有的用户记录,并打印出来。

这个测试类的目的是验证 UserService 类的 listAll() 方法是否能正确地获取所有的用户记录。