使用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 在“配置阶段”全部执行
所以:
会在执行 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' }
|
作用: 定义“全局变量
现在推荐替代方案
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(最重要)
提供能力:
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>
|
- 核心配置文件 (
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
|
- 在代码中打个“招呼”
最后在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(自动装配) 机制,让开发者几乎可以零配置直接使用。
- 默认客户端驱动:Lettuce
- 在老的 Spring Boot 1.x 版本中,默认使用的是 Jedis 客户端。
- 从 Spring Boot 2.x/3.x 开始,官方默认将驱动切换为了 Lettuce。
- 为什么用 Lettuce? Jedis 的多线程并发是基于连接池的(线程不安全),而 Lettuce 是基于 Netty 的,它的连接可以在多个线程间共享,属于异步非阻塞的架构,在高并发场景下性能更优、资源消耗更小。
- 自动装配类:
RedisAutoConfiguration
当你引入了 Starter 后,Spring Boot 的类路径扫描会激活 RedisAutoConfiguration 这个自动配置类。它在幕后默默做了两件事:
- 自动创建连接工厂(
RedisConnectionFactory):它会读取你在 yml 中配置的 host、port 等参数,实例化一个 LettuceConnectionFactory,负责建立与 Redis 服务器的物理连接。 - 自动注入两个核心模板类:
RedisTemplate<Object, Object>:通用模板,键值对都可以是任意对象。StringRedisTemplate:专门处理 String 类型的模板(因为 Redis 中 90% 的场景都是字符串)。
- 序列化机制(关键踩坑点)
Redis 底层只存储字节数组(byte[]),而 Java 是一门面向对象的语言。因此,Java 对象存入 Redis 必须经过序列化。
StringRedisTemplate:默认使用 StringRedisSerializer。它存进去的就是人类直观可见的普通字符串。RedisTemplate:默认使用 JdkSerializationSerializer。这会导致两个严重问题:- 存入 Redis 的 Key 和 Value 前面会带有一串乱码般的十六进制前缀(如
\xac\xed\x00\x05t\x00...)。 - 难以通过可视化工具(如 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>
|
- 核心配置文件 (
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
|
- 自定义配置类:重写
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; } }
|
三、 总结:如何选择 RedisTemplate 和 StringRedisTemplate?
在代码中注入并使用它们时,遵循以下基本原则:
- 如果你只存纯文本、数字、或者你自己手动转好的 JSON 字符串: 直接使用
StringRedisTemplate。它免去了任何框架层的序列化开销,性能最高,且在 Redis 内呈现最干净的字符串。 - 如果你想直接把一个 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 类,它在项目启动时主要帮你完成了以下几件大事:
- 自动构建三大工厂(基础层)
它会读取 yml 中的集群地址等参数,在后台自动实例化:
ProducerFactory:生产者工厂,负责专门创建、管理和复用低层的 Kafka 生产者实例(KafkaProducer)。ConsumerFactory:消费者工厂,负责配置消费组 ID、反序列化器,并创建原生的 KafkaConsumer。KafkaListenerContainerFactory:监听器容器工厂(最核心)。它负责把你的 @KafkaListener 注解转换为后台不断轮询(poll())消息的异步线程池容器。
- 自动注入核心发送模板:
KafkaTemplate
类似于 RedisTemplate,Spring 自动为你提供了一个 KafkaTemplate<K, V>。
- 它对原生的生产者进行了高级封装。
- 它默认是线程安全的,你可以在任何 Service 里直接注入并调用
.send(topic, message)。 - 支持同步发送(等待 Broker 回应)和异步发送(通过
CompletableFuture 回调接收发送结果)。
@KafkaListener 幕后的死循环轮询
当你在某个方法上加上 @KafkaListener(topics = "my-topic") 时:
- Spring 启动后,监听器容器工厂会为这个方法单独开启独立的线程。
- 线程内部会进入一个
while(true) 的死循环,源源不断地调用 Kafka 原生的 consumer.poll(timeout) 方法去拉取消息。 - 一旦拉取到消息,通过反射调用你写的方法,将消息作为参数传入。
引入依赖 (POM)
1 2 3 4
| <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency>
|
- 核心配置文件 (
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 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..."; } }
|
- 消费者:监听并手动确认(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()); } } }
|