springboot4.x之knife4j文档与日志和mybatis-plus搭建完整指南

 更新时间:2026年07月07日 10:04:30   作者:斗码士  
这篇文章主要介绍了springboot4.x之knife4j文档与日志和mybatis-plus搭建完整指南的相关资料,这篇Knife4j集成指南将带您快速上手,从兼容性依赖配置到OpenAPI3.0注解,再到在线调试功能,需要的朋友可以参考下

前言

在Spring Boot 4.x项目中集成Knife4j可以为你生成强大而美观的API文档。下面是一个清晰的搭建指南,其中已特别关注了依赖版本与Spring Boot 4.x的兼容性。

第一步:添加依赖

在项目的 pom.xml文件中添加Knife4j的依赖。Spring Boot 4.x 基于Spring Boot 3.x构建,因此需要使用支持OpenAPI 3.0和Jakarta EE的Knife4j starter

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>4.5.0</version> <!-- 建议使用最新版本 -->
</dependency>

关键点:请确保使用 knife4j-openapi3-jakarta-spring-boot-starter,它与Spring Boot 3.x/4.x兼容。老版本或错误的starter(如针对Swagger 2.x的)可能无法正常工作。

第二步:创建配置类

创建一个配置类(例如 Knife4jConfig)来定制文档信息。这里推荐使用OpenAPI 3.0的配置方式。

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.Contact;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class Knife4jConfig {
 
    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("你的项目API文档")
                        .version("1.0")
                        .description("Spring Boot 4.x项目API接口文档")
                        .contact(new Contact().name("开发者").email("dev@example.com")));
    }
 
    // 可选:接口分组配置
    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("public") // 分组名称
                .pathsToMatch("/api/**") // 匹配的接口路径
                .packagesToScan("com.yourpackage.controller") // 扫描的包
                .build();
    }
}

配置说明

  • OpenAPIBean用于配置文档的全局信息,如标题、版本等。

  • GroupedOpenApiBean可用于将接口分组显示,这在模块化项目中非常实用。

第三步:使用注解描述API

在Controller和模型类上使用Swagger注解,这样Knife4j才能生成详细的接口文档。

1. Controller层常用注解

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
 
@RestController
@RequestMapping("/api/users")
@Tag(name = "用户管理", description = "用户相关操作接口") // 标签,用于接口分组
public class UserController {
 
    @GetMapping("/{id}")
    @Operation(summary = "根据ID查询用户", description = "通过用户ID获取详细的用户信息") // 接口描述
    public User getUserById(
            @Parameter(description = "用户ID", example = "123", required = true) // 参数描述
            @PathVariable Long id) {
        // ... 业务逻辑
    }
 
    @PostMapping
    @Operation(summary = "创建新用户")
    public User createUser(@RequestBody User user) {
        // ... 业务逻辑
    }
}

2. 模型类(DTO/VO)常用注解

import io.swagger.v3.oas.annotations.media.Schema;
 
@Schema(description = "用户实体") // 模型描述
public class User {
    @Schema(description = "用户唯一标识", example = "1")
    private Long id;
 
    @Schema(description = "用户名", example = "张三", requiredMode = Schema.RequiredMode.REQUIRED)
    private String username;
 
    @Schema(description = "用户邮箱", example = "user@example.com")
    private String email;
 
    // ... getters and setters
}

通过这些注解,你可以清晰地说明每个接口、参数和返回值的含义,极大提升文档可读性。

第四步:访问与查看

完成以上步骤后,启动你的Spring Boot应用。

  • 访问Knife4j增强UI:在浏览器中打开 http://你的服务器地址:端口号/doc.html

  • 访问原生Swagger UI:你也可以通过 http://你的服务器地址:端口号/swagger-ui.html访问原生界面。

Knife4j的界面(doc.html)提供了更友好的文档展示和在线调试功能。

进阶配置与技巧

# application.yml
knife4j:
  enable: true   # 开发环境设为true

实战例子

项目结构

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zxs</groupId>
    <artifactId>zxs-log</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zxs-log</name>
    <description>zxs-log</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>21</java.version>
        <lombok.version>1.18.36</lombok.version>
        <mybatis-plus.version>3.5.15</mybatis-plus.version>
        <knife4j.version>4.5.0</knife4j.version>
        <mysql.version>8.0.33</mysql.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- MyBatis-Plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot4-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-jsqlparser</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <!-- 数据库相关 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- 文档相关 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version> <!-- 建议检查并使用最新版本 -->
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
server:
  port: 8080
spring:
  application:
    name: zxs-log
  profiles:
    active: dev

knife4j:
  enable: true
  setting:
    language: zh-CN
spring:
  datasource:
    url: jdbc:mysql://192.168.0.106:3306/zxs?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: baishou888
    driver-class-name: com.mysql.cj.jdbc.Driver
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8


mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false">

    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n" />

<!--    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %p %C - %m%n" />-->

    <property name="LOG_HOME" value="logs"/>


    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">


        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--先将今天的日志保存在这个文件中-->
        <file>${LOG_HOME}/log_debug.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名 -->
            <FileNamePattern>${LOG_HOME}/log_info.%d{yyyy-MM-dd}.%i.zip</FileNamePattern>
            <!--日志文件保留天数 -->
            <MaxHistory>30</MaxHistory>
            <maxFileSize>10MB</maxFileSize>
            <!--所有的日志文件最大20G,超过就会删除旧的日志-->
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/log_error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/log_error.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <springProfile name="dev">
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
        <logger name="com.zxs.zxslog" level="DEBUG"/>
        <logger name="com.baomidou.mybatisplus" level="DEBUG"/>
    </springProfile>

    <!-- 测试环境 -->
    <springProfile name="test">
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
        <logger name="com.zxs.zxslog" level="DEBUG"/>
        <logger name="com.baomidou.mybatisplus" level="DEBUG"/>
    </springProfile>

    <!-- 生产环境 -->
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
        <logger name="com.zxs.zxslog" level="INFO"/>
    </springProfile>

</configuration>
package com.zxs.zxslog.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Knife4jConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        final String securitySchemeName = "bearerAuth"; // 定义安全方案的名称
        return new OpenAPI()
                .info(new Info().title("API 文档").version("1.0"))
                // 添加全局安全要求,引用下面定义的安全方案
                .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
                // 定义组件(安全方案)
                .components(new Components()
                        .addSecuritySchemes(securitySchemeName,
                                new SecurityScheme()
                                        .name(securitySchemeName) // 头参数名,通常为 Authorization
                                        .type(SecurityScheme.Type.HTTP) // 类型为 HTTP
                                        .scheme("bearer") // 方案为 bearer
                                        .bearerFormat("JWT") // 令牌格式(可选)
                        ));
    }
}
package com.zxs.zxslog.config;

import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.GlobalOperationCustomizer;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import java.util.List;

@Slf4j
@Component
public class Knife4jOperationCustomizer implements GlobalOperationCustomizer {

    @Override
    public Operation customize(Operation operation, HandlerMethod handlerMethod) {
        // 检查该接口是否已经配置了安全要求,如果没有则添加
        if (operation.getSecurity() == null) {
            // 添加安全要求,这里的 "bearerAuth" 需要与方法一中定义的安全方案名称一致
            operation.setSecurity(List.of(new SecurityRequirement().addList("bearerAuth")));
        }
        return operation;
    }
}
package com.zxs.zxslog.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDateTime;

@Configuration
public class MybatisPlusConfig {

    /**
     * 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }

    /**
     * 自动填充处理器
     */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MetaObjectHandler() {
            @Override
            public void insertFill(MetaObject metaObject) {
                System.out.println("insertFill执行了");
                this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
                this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
            }

            @Override
            public void updateFill(MetaObject metaObject) {
                System.out.println("updateFill执行了");
                this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
            }
        };
    }
}
package com.zxs.zxslog.ctl;

import com.zxs.zxslog.entity.User;
import com.zxs.zxslog.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Slf4j
@RestController
@RequestMapping("/user")
@Tag(name = "用户管理", description = "用户相关接口")
public class LoginController {

    @Resource
    private UserService userService;

    @GetMapping
    @Operation(summary = "获取用户列表", description = "获取用户列表")
    public List<User> list() {
        log.trace("trace");
        log.debug("debug");
        log.info("info");
        log.warn("warn");
        log.error("error");
        return userService.list();
    }

    @GetMapping("/log")
    @Operation(summary = "主动抛出异常", description = "主动抛出异常")
    public List<User> log() {
        System.out.println(100/0);
        return userService.list();
    }

    @PostMapping
    @Operation(summary = "保存用户", description = "保存用户")
    public boolean save(@RequestBody User user) {
        return userService.save(user);
    }

    @PutMapping
    @Operation(summary = "更新用户", description = "根据用户id更新用户")
    public boolean update(@RequestBody User user) {
        return userService.updateById(user);
    }

    @DeleteMapping("/{id}")
    @Operation(summary = "删除用户", description = "根据用户id删除用户")
    public boolean delete(@PathVariable Long id) {
        return userService.removeById(id);
    }

    @GetMapping("/getUserById/{id}")
    @Operation(summary = "获取用户", description = "根据用户id获取用户")
    public User getUserById(@PathVariable("id") Long id){
        return userService.getById(id);
    }

}
package com.zxs.zxslog.entity.common;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

@Data
public class Common implements Serializable {

    @TableId
    private Long id;

    @Schema(description = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @Schema(description = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @Schema(description = "是否删除:0-未删除,1-已删除")
    private Integer deleted;

}
package com.zxs.zxslog.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zxs.zxslog.entity.common.Common;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@TableName("user")
public class User extends Common {

    @Schema(description = "用户名")
    private String username;

    @Schema(description = "密码")
    private String password;

    @Schema(description = "真实姓名")
    private String realName;

    @Schema(description = "邮箱")
    private String email;

    @Schema(description = "手机")
    private String phone;

    @Schema(description = "状态:0-禁用,1-启用")
    private Integer status;
}
package com.zxs.zxslog.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zxs.zxslog.entity.User;

public interface UserMapper extends BaseMapper<User> {}
package com.zxs.zxslog.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zxs.zxslog.entity.User;
import com.zxs.zxslog.mapper.UserMapper;
import com.zxs.zxslog.service.UserService;
import org.springframework.stereotype.Service;


@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

}
package com.zxs.zxslog.service;


import com.baomidou.mybatisplus.extension.service.IService;
import com.zxs.zxslog.entity.User;


public interface UserService extends IService<User> {
}
package com.zxs.zxslog;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;

import java.net.InetAddress;

@Slf4j
@SpringBootApplication
@MapperScan("com.zxs.zxslog.mapper")
public class ZxsLogApplication {

    @SneakyThrows
    public static void main(String[] args) {
        ConfigurableApplicationContext application=SpringApplication.run(ZxsLogApplication.class, args);
        Environment env = application.getEnvironment();
        log.info("\n----------------------------------------------------------\n\t" +
                        "Application '{}' is running! Access URLs:\n\t" +
                        "Local: \t\thttp://localhost:{}\n\t" +
                        "External: \thttp://{}:{}\n\t"+
                        "Doc: \thttp://{}:{}/doc.html\n"+
                        "----------------------------------------------------------",
                env.getProperty("spring.application.name"),
                env.getProperty("server.port"),
                InetAddress.getLocalHost().getHostAddress(),
                env.getProperty("server.port"),
                InetAddress.getLocalHost().getHostAddress(),
                env.getProperty("server.port"));
    }

}

由于我这里只是预留的Authorize,就随便填了

我这里设置的是一般日志与异常日志分离,方便我们更快定位异常

总结

到此这篇关于springboot4.x之knife4j文档与日志和mybatis-plus搭建完整指南的文章就介绍到这了,更多相关springboot4.x knife4j文档与日志内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Java中的HashTable

    详解Java中的HashTable

    这篇文章主要介绍了Java中的HashTable的相关资料,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-12-12
  • 基于Jenkins自动打包并部署docker环境的操作过程

    基于Jenkins自动打包并部署docker环境的操作过程

    这篇文章主要介绍了基于Jenkins自动打包并部署docker环境,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • java double 溢出报错的问题解决

    java double 溢出报错的问题解决

    在进行Java开发时,经常会遇到数字溢出的问题,这个问题在很多程序中都非常常见,尤其是在进行数值计算的时候,本文就来介绍一下如何解决,感兴趣的可以了解一下
    2025-09-09
  • springboot微服务项目集成html页面的实现

    springboot微服务项目集成html页面的实现

    本文主要介绍了springboot微服务项目集成html页面的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • 深入解析Java的设计模式编程中单例模式的使用

    深入解析Java的设计模式编程中单例模式的使用

    这篇文章主要介绍了深入解析Java的设计模式编程中单例模式的使用,一般来说将单例模式分为饿汉式单例和懒汉式单例,需要的朋友可以参考下
    2016-02-02
  • 详谈Java泛型中T和问号(通配符)的区别

    详谈Java泛型中T和问号(通配符)的区别

    下面小编就为大家带来一篇详谈Java泛型中T和问号(通配符)的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Java使用线程池批量处理数据操作具体流程

    Java使用线程池批量处理数据操作具体流程

    这篇文章主要给大家介绍了关于Java使用线程池批量处理数据操作的相关资料,Java多线程编程中线程池是一个非常重要的概念,线程池可以提高线程的复用率和任务调度的效率,尤其是当需要查询大批量数据时,需要的朋友可以参考下
    2023-06-06
  • Java8 CompletableFuture 异步执行操作

    Java8 CompletableFuture 异步执行操作

    CompletableFuture是java8提供的基于异步操作的封装,日常开发中经常会用到,接下来通过本文给大家介绍Java8 CompletableFuture 异步执行操作,感兴趣的朋友一起看看吧
    2021-06-06
  • 浅谈JavaIO之try with底层原理

    浅谈JavaIO之try with底层原理

    众所周知,所有被打开的系统资源,比如流、文件或者Socket连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故。本文将介绍JavaIO之try with底层原理。
    2021-06-06
  • Java责任链设计模式

    Java责任链设计模式

    这篇文章主要介绍了Java责任链设计模式的相关资料,需要的朋友可以参考下
    2016-03-03

最新评论