惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
月光博客
月光博客
腾讯CDC
Engineering at Meta
Engineering at Meta
博客园 - Franky
Vercel News
Vercel News
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Fortinet All Blogs
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
GbyAI
GbyAI
B
Blog
Hugging Face - Blog
Hugging Face - Blog
T
Tailwind CSS Blog

Sekyoro的博客小屋

Agent从入门到开发 从自动化测试到游戏脚本:使用Maafw开发 Claude Code 实战 网络中有趣的协议 Beyond AI Coding:Harness工程与更好地AI开发 C++重点知识回顾 项目场景扩展(二) OpenClaw学习与实战 项目场景扩展(一) 搭建Agent+MCP+SKILL进行成熟Vibe Coding 分布式IM聊天系统学习 AI工具尝鲜:从"模态爆发"到"生态耕耘" Java、JVM、并发进阶 经典算法题解析 线段树问题 服务器网站备份实战 cls文件编写实战 智力题总结 RAG系统设计 从零开始大数据 资源调度与项目管理平台 凤凰架构学习 博客网站构建指南 k8s学习 Java进阶知识 操作系统与计算机网络经典 构建AI应用程序的框架以及解决方案 MySQL与Redis经典面经 刷题总结篇
Gradle入门与使用
Sekyoro · 2026-06-24 · via Sekyoro的博客小屋

使用Gradle构建项目,尝试用的属性,与数据库、缓存,MQ搭配,以及构建模板。

Gradle 是一个构建自动化工具

用来做三件事:

  • 编译 Java / Kotlin
  • 管理依赖(类似 Maven)
  • 组织多模块工程

一个 Gradle 项目本质是:

1
Gradle = 一堆 Project + 每个 Project 的 build.gradle

每个 build.gradle 里都是“配置块”。

Gradle核心模型

Gradle 有 3 个核心对象:

Project(项目)

每个模块都是一个 Project:

1
2
3
4
root project
├── api
├── service
├── repository

每个 build.gradle = 一个 Project

Task(任务)

Gradle 的执行单位:

1
2
3
4
compileJava
test
bootJar
build

Dependency(依赖)

Java 代码依赖:

1
implementation 'org.springframework.boot:spring-boot-starter'

生命周期

1
2
3
1. 初始化(init)
2. 配置(configuration)
3. 执行(execution)

关键点: build.gradle 在“配置阶段”全部执行

所以:

1
println("hello")

会在执行 task 之前就打印。

一个项目结构让设计如下

1
2
3
4
5
6
7
purchase-system

├── common (基础模型)
├── contract (RPC接口)
├── repository (DAO)
├── service (业务 + Dubbo provider)
└── api (HTTP + Dubbo consumer)

插件块

build.gradle 这个脚本本身加依赖,通过buildscript或者plugins.给项目“增加能力”

比如:

  • java → 可以编译 Java
  • spring boot → 可以打 bootJar

plugins {}现代插件机制(声明式、Gradle 官方推荐)
buildscript {}旧插件机制(手动把依赖塞进构建脚本 classpath)

1
2
3
4
5
6
7
8
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:3.3.0"
}
}

通过repositories中的仓库查找对应插件并放到classpath.然后才apply plugin使用插件. Gradle本身自带一些插件,比如java,可以直接apply

而`plugins自己去“插件仓库”下载 plugin

然后自动解析 plugin marker,找找 implementation jar,自动 apply. 配置下载仓库在settings.gradle中,默认使用Gradle官方的

1
2
3
plugins {
id "org.springframework.boot" version "3.3.0"
}

仓库块

1
2
3
4
repositories {
mavenCentral()
maven { url "https://maven.aliyun.com/repository/public" }
}

告诉 Gradle 去哪里下载依赖

依赖块

1
2
3
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
}

给 Java 代码引入库

关键字作用
implementation运行 + 编译
compileOnly只编译
testImplementation测试用
runtimeOnly运行时

ext

1
2
3
4
ext {
lombokVersion = '1.18.34'
dubboVersion = '3.2.15'
}

作用: 定义“全局变量

现在推荐替代方案

1
gradle.properties

allprojects

1
2
3
4
5
allprojects {
repositories {
mavenCentral()
}
}

作用: 对“所有 project(包括 root + 子模块)”生效

subprojects

1
2
3
4
5
6
7
subprojects {
apply plugin: 'java'

dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}
}

作用: 只对“子模块”生效(不包括 root)

作用:

统一 Java plugin

统一 Lombok

统一 test 配置

project(“:xxx”)

1
2
3
4
5
project(":api") {
dependencies {
implementation project(":common")
}
}

配置“某一个指定模块”

dependencyManagement {}

1
2
3
4
5
dependencyManagement {
imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:3.3.0"
}
}

作用:统一版本号(不在 dependencies 写版本)

tasks (任务块)

1
2
3
4
5
tasks.register('hello') {
doLast {
println("hello gradle")
}
}

作用:定义构建步骤

常用插件

自带插件

1)java(最重要)

1
2
3
plugins {
id 'java'
}

提供能力:

  • compileJava

  • jar

  • test

  • sourceSets

    Java 项目基础插件

2)java-library(更专业)

1
2
3
plugins {
id 'java-library'
}

多了:

  • api / implementation 区分
  • 更适合模块化项目

    推荐多模块项目用这个

maven-publish

Gradle Maven Publish Plugin

1
2
3
plugins {
id 'maven-publish'
}

用于发布 jar 到 Maven 仓库

数据库 / ORM 常见插件

MyBatis Generator

1
2
3
plugins {
id 'org.mybatis.generator'
}

自动生成 mapper / entity

Spring 生态插件

Spring Boot Plugin

Spring Boot Gradle Plugin

1
2
3
plugins {
id 'org.springframework.boot' version '3.3.0'
}

提供:

  • bootJar(fat jar)
  • bootRun
  • 自动依赖管理

Spring Dependency Management

1
2
3
plugins {
id 'io.spring.dependency-management'
}

提供:BOM 管理(不写版本号)

基于Spring-boot-starter与Mybatis整合

mybatis-spring-boot-autoconfigure – 简介

1
2
3
dependencies {
implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2")
}

MyBatis-Spring-Boot-Starter 将会:

  • 自动探测存在的 DataSource
  • 将使用 SqlSessionFactoryBean 创建并注册一个 SqlSessionFactory 的实例,并将探测到的 DataSource 作为数据源
  • 将创建并注册一个从 SqlSessionFactory 中得到的 SqlSessionTemplate 的实例
  • 自动扫描你的 mapper,将它们与 SqlSessionTemplate 相关联,并将它们注册到Spring 的环境(context)中去,这样它们就可以被注入到你的 bean 中

数据源是基础底层,SqlSessionFactory 利用数据源创建连接并作为核心工厂,生产出具体的执行器 SqlSessionTemplate,而 SqlSessionTemplate 在幕后真正驱动并支撑 Mapper 接口的方法执行。

它们之间的分层依赖与调用关系如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[DataSource (数据源)]

│ 提供数据库连接池 (如 HikariCP)

[SqlSessionFactory (会话工厂)]

│ 作为单例核心引擎,用来创建会话

[SqlSessionTemplate (会话模板)]

│ 线程安全,代理并管理实际的 SqlSession 会话与生命周期

[Mapper 接口 (动态代理对象)]

mybatis-spring-boot-autoconfigure – 简介

配置

引入依赖

pom.xml 中引入 MyBatis 自己的 Starter(它会顺着依赖把需要的工厂类和模板类全部下载下来):

1
2
3
4
5
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
  1. 核心配置文件 (application.yml)

只需要配置两部分:一是数据源(让它能自动探测到 DataSource),二是告诉它你的 SQL 映射文件(XML)放在哪。

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
datasource:

url: jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf-8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:

mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
  1. 在代码中打个“招呼”

最后在Spring Boot 启动类(或者配置类)上,加上一个 @MapperScan 注解。

这是为了告诉它:“我的 Mapper 接口都放在这个包底下了,你快去自动扫描它们,把它们和 SqlSessionTemplate 关联起来吧!”

Java

1
2
3
4
5
6
7
@SpringBootApplication
@MapperScan("com.example.ecommerce.mapper")
public class EcommerceApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceApplication.class, args);
}
}

整合springBoot与Redis

快速导览 :: Spring Kafka - Spring 框架

在 Spring Boot 中,spring-boot-starter-data-redis(通常简称为 spring-redis-starter)是整合 Redis 的核心组件。它不仅引入了 Redis 客户端驱动,还通过 Spring Boot 的 Auto-Configuration(自动装配) 机制,让开发者几乎可以零配置直接使用。

  1. 默认客户端驱动:Lettuce
  • 在老的 Spring Boot 1.x 版本中,默认使用的是 Jedis 客户端。
  • Spring Boot 2.x/3.x 开始,官方默认将驱动切换为了 Lettuce
  • 为什么用 Lettuce? Jedis 的多线程并发是基于连接池的(线程不安全),而 Lettuce 是基于 Netty 的,它的连接可以在多个线程间共享,属于异步非阻塞的架构,在高并发场景下性能更优、资源消耗更小。
  1. 自动装配类:RedisAutoConfiguration

当你引入了 Starter 后,Spring Boot 的类路径扫描会激活 RedisAutoConfiguration 这个自动配置类。它在幕后默默做了两件事:

  • 自动创建连接工厂(RedisConnectionFactory:它会读取你在 yml 中配置的 host、port 等参数,实例化一个 LettuceConnectionFactory,负责建立与 Redis 服务器的物理连接。
  • 自动注入两个核心模板类
    • RedisTemplate<Object, Object>:通用模板,键值对都可以是任意对象。
    • StringRedisTemplate:专门处理 String 类型的模板(因为 Redis 中 90% 的场景都是字符串)。
  1. 序列化机制(关键踩坑点)

Redis 底层只存储字节数组(byte[]),而 Java 是一门面向对象的语言。因此,Java 对象存入 Redis 必须经过序列化

  • StringRedisTemplate:默认使用 StringRedisSerializer。它存进去的就是人类直观可见的普通字符串。
  • RedisTemplate:默认使用 JdkSerializationSerializer。这会导致两个严重问题:
    1. 存入 Redis 的 Key 和 Value 前面会带有一串乱码般的十六进制前缀(如 \xac\xed\x00\x05t\x00...)。
    2. 难以通过可视化工具(如 RDM)直接查看,且跨语言(如 Python 读写)极不友好。

配置

引入依赖 (POM)

除了 Starter 本身,如果需要配置连接池,必须引入 commons-pool2

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
  1. 核心配置文件 (application.yml)

标准 Lettuce 连接池配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
data:
redis:
host: 127.0.0.1
port: 6379
password: your_password
database: 0
timeout: 5000ms
connect-timeout: 5000ms
lettuce:
pool:
max-active: 32
max-idle: 16
min-idle: 4
max-wait: 2000ms
  1. 自定义配置类:重写 RedisTemplate(必做步骤)

为了解决上面提到的 “JDK 序列化乱码” 问题,在实际开发中,我们必须自己写一个配置类,把默认的序列化方式替换为 JSON 序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);


GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();


template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());


template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);

template.afterPropertiesSet();
return template;
}
}

三、 总结:如何选择 RedisTemplateStringRedisTemplate

在代码中注入并使用它们时,遵循以下基本原则:

  1. 如果你只存纯文本、数字、或者你自己手动转好的 JSON 字符串: 直接使用 StringRedisTemplate。它免去了任何框架层的序列化开销,性能最高,且在 Redis 内呈现最干净的字符串。
  2. 如果你想直接把一个 Java 对象(如 User 实体、Order 实体)丢进 Redis: 使用你刚才自定义好序列化器的 RedisTemplate<String, Object>。它会在底层自动帮你把对象转成标准 JSON 串存入,取出来时自动反序列化回 Java 对象,开发体验最顺畅。

整合springBoot与Kafka

引入依赖

1
2
3
<dependency>  
<groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>4.0.0</version>
</dependency>

spring-kafka 的自动装配核心是 KafkaAutoConfiguration 类,它在项目启动时主要帮你完成了以下几件大事:

  1. 自动构建三大工厂(基础层)

它会读取 yml 中的集群地址等参数,在后台自动实例化:

  • ProducerFactory:生产者工厂,负责专门创建、管理和复用低层的 Kafka 生产者实例(KafkaProducer)。
  • ConsumerFactory:消费者工厂,负责配置消费组 ID、反序列化器,并创建原生的 KafkaConsumer
  • KafkaListenerContainerFactory:监听器容器工厂(最核心)。它负责把你的 @KafkaListener 注解转换为后台不断轮询(poll())消息的异步线程池容器。
  1. 自动注入核心发送模板:KafkaTemplate

类似于 RedisTemplate,Spring 自动为你提供了一个 KafkaTemplate<K, V>

  • 它对原生的生产者进行了高级封装。
  • 它默认是线程安全的,你可以在任何 Service 里直接注入并调用 .send(topic, message)
  • 支持同步发送(等待 Broker 回应)和异步发送(通过 CompletableFuture 回调接收发送结果)。
  1. @KafkaListener 幕后的死循环轮询

当你在某个方法上加上 @KafkaListener(topics = "my-topic") 时:

  1. Spring 启动后,监听器容器工厂会为这个方法单独开启独立的线程
  2. 线程内部会进入一个 while(true)死循环,源源不断地调用 Kafka 原生的 consumer.poll(timeout) 方法去拉取消息。
  3. 一旦拉取到消息,通过反射调用你写的方法,将消息作为参数传入。

引入依赖 (POM)

1
2
3
4
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
  1. 核心配置文件 (application.yml)

在实际的业务场景中,我们必须精细控制ACK应答级别以防丢消息,以及关闭自动提交改为手动提交。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
spring:
kafka:
bootstrap-servers: 127.0.0.1:9092


producer:
retries: 3
acks: all
batch-size: 16384
buffer-memory: 33554432
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer


consumer:
group-id: ecommerce-order-group
enable-auto-commit: false
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
max-poll-records: 500


listener:


ack-mode: manual_immediate
concurrency: 3

三、 核心代码使用示例

  1. 生产者:发送消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@RestController
@RequestMapping("/order")
public class OrderController {

@Autowired
private KafkaTemplate<String, String> kafkaTemplate;

@GetMapping("/create")
public String createOrder() {
String orderJson = "{\"orderId\": 10023, \"amount\": 299.00}";


CompletableFuture<SendResult<String, String>> future = kafkaTemplate.send("order-topic", orderJson);


future.whenComplete((result, ex) -> {
if (ex == null) {
System.out.println("消息发送成功,偏移量为:" + result.getRecordMetadata().offset());
} else {
System.err.println("消息发送失败:" + ex.getMessage());
}
});

return "Order processing...";
}
}
  1. 消费者:监听并手动确认(Ack)

当你在上面配置了 ack-mode: manual_immediate,你的消费方法里可以引入 Acknowledgment 对象。当业务代码顺利跑完,调用 ack.acknowledge() 告诉 Kafka:“这条消息我吃下了,你可以推进 Offset 了”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class OrderConsumer {


@KafkaListener(topics = "order-topic", groupId = "ecommerce-order-group", concurrency = "3")
public void onMessage(ConsumerRecord<String, String> record, Acknowledgment ack) {
try {

System.out.printf("线程 %s 收到消息 -> 分区: %d, 消息体: %s%n",
Thread.currentThread().getName(), record.partition(), record.value());





ack.acknowledge();
} catch (Exception e) {

System.err.println("消费异常,暂不提交偏移量: " + e.getMessage());
}
}
}