1. 全局异常处理 —— 相当于“服务员的统一微笑回复”
- 大白话:后厨做菜(代码运行)难免会出错(比如盘子摔碎了、没食材了)。如果没有这个,用户就会直接在屏幕上看到一大堆看不懂的黑底白字报错信息(像把后厨骂人的脏话展示给顾客了)。
- 代码干了啥:不管后厨出了啥幺蛾子,服务员统一拦截下来,微笑着对顾客说:“对不起,系统繁忙,请稍后再试”,格式非常整齐。
// 1. 统一给顾客看的“打包盒”
public record result<t>(int code, string message, t data) {
public static <t> result<t> success(t data) {
return new result<>(200, "成功", data);
}
public static <t> result<t> fail(string msg) {
return new result<>(500, msg, null);
}
}
// 2. 兜底的服务员(拦截所有报错)
@restcontrolleradvice
public class globalexceptionhandler {
@exceptionhandler(exception.class)
public result<void> handleexception(exception e) {
// 偷偷把错误记录在后台日志里,但给顾客返回礼貌提示
return result.fail("系统出了一点小问题,请稍后重试");
}
}2. redisson 分布式锁 —— 相当于“试衣间锁门”
- 大白话:试衣间(共享资源,比如最后 1 件衣服)只有一间。100 个人同时来抢,怎么办?谁先抢到门把手,谁就把门锁上(
trylock)。其他人只能在门口等着。里面的人试完出来,把门锁打开(unlock),下一个才能进去。 - 代码干了啥:防止几百个人同时修改同一个数据导致数据错乱。
@service
@requiredargsconstructor
public class seckillservice {
private final redissonclient redissonclient;
public void buyproduct(string productid) {
rlock lock = redissonclient.getlock("lock:" + productid);
try {
// 尝试拿锁:最多等 3 秒,拿到后锁 10 秒
if (lock.trylock(3, 10, timeunit.seconds)) {
try {
// 锁门成功!安心在这里处理买东西的逻辑
} finally {
// 试完了,必须把门锁解开,让给别人
if (lock.isheldbycurrentthread()) {
lock.unlock();
}
}
} else {
// 等了 3 秒还没门开,直接告诉顾客“没抢到”
}
} catch (interruptedexception e) {
thread.currentthread().interrupt();
}
}
}3. mq 消息手动确认(ack)—— 相当于“快递签收单”
- 大白话:快递员给你送货(消息队列给你发任务)。如果是“自动确认”,快递员扔到门口就走,万一被偷了你就亏了。如果是“手动确认(ack)”,你必须亲自把包裹拆开验完货(业务处理成功),再在签收单上签字(
basicack)。如果发现货坏了,你拒签(basicnack),让快递员拿回去重新处理。 - 代码干了啥:保证消息绝对不会因为程序突然断电、崩溃而丢失。
@component
public class mqconsumer {
@rabbitlistener(queues = "order.queue", ackmode = "manual")
public void receiveorder(string message, channel channel, @header(amqpheaders.delivery_tag) long tag) throws ioexception {
try {
// 1. 拆快递、验货、处理业务
system.out.println("收到订单消息:" + message);
// 2. 确认无误,签名签收!(告诉 mq 可以把这条消息删了)
channel.basicack(tag, false);
} catch (exception e) {
// 3. 出错了!拒签,退回给快递公司重新送
channel.basicnack(tag, false, false);
}
}
}4. 自定义线程池 —— 相当于“招募固定数量的厨师”
- 大白话:如果每来一个顾客你就临时招一个厨师(
new thread()),顾客太多时,厨房会挤爆(内存溢出 oom)。科学做法是:雇 10 个干活的厨师(核心线程),准备一个可以排 200 人的等候区(阻塞队列)。如果等候区也满了,多余的顾客让店长亲自去接待(拒绝策略)。 - 代码干了啥:控制系统的并发干活人数,防止把服务器卡死。
@configuration
public class threadpoolconfig {
@bean("mythreadpool")
public threadpooltaskexecutor mythreadpool() {
threadpooltaskexecutor executor = new threadpooltaskexecutor();
executor.setcorepoolsize(10); // 常驻厨师:10 人
executor.setmaxpoolsize(20); // 忙不过来时最多扩到:20 人
executor.setqueuecapacity(200); // 休息区桌子:200 张
executor.setthreadnameprefix("my-worker-"); // 给厨师衣服贴工号
// 人实在装不下了,让来派任务的主线程自己去干
executor.setrejectedexecutionhandler(new threadpoolexecutor.callerrunspolicy());
executor.initialize();
return executor;
}
}5. redis + lua 脚本预扣库存 —— 相当于“黑板刷秒杀法”
- 大白话:秒杀开始时,10 万人冲进来查数据库,数据库直接瘫痪。怎么办?把商品数量(比如 100 件)提前写在黑板(内存 redis)上。来一个人,直接在黑板上擦掉一个数(
decrby)。黑板擦到 0 了,后面的人连看都不用看数据库,直接提示“售罄”。 - 代码干了啥:把最耗时、最怕并发的检查,全在极速的内存里搞定。
@service
@requiredargsconstructor
public class stockservice {
private final stringredistemplate redistemplate;
// lua 脚本:在 redis 内部完成“检查库存 -> 扣减库存”,一体化搞定
private static final string script =
"local stock = tonumber(redis.call('get', keys[1])); " +
"if stock and stock > 0 then " +
" redis.call('decrby', keys[1], 1); " +
" return 1; " + // 扣减成功
"end; " +
"return 0;"; // 没库存了
public boolean buy(string stockkey) {
defaultredisscript<long> redisscript = new defaultredisscript<>(script, long.class);
long result = redistemplate.execute(redisscript, collections.singletonlist(stockkey));
return long.valueof(1).equals(result);
}
}6. 接口限流 —— 相当于“酒吧门口的保镖”
- 大白话:有人恶意用软件一秒钟刷你接口 10000 次,服务器马上就要崩。限流就像门口的保镖:规定 1 分钟内,同一个人最多只能进去 10 次。第 11 次直接一巴掌踢飞:“刷太快了,等会再来!”
- 代码干了啥:用切面(aop)加上 redis 计数,无侵入地拦截恶意恶刷。
// 1. 自定义标签:贴在方法上就能限流
@target(elementtype.method)
@retention(retentionpolicy.runtime)
public @interface ratelimit {
int maxcount() default 10; // 最多进 10 次
int second() default 60; // 60 秒内
}
// 2. 门口的保镖(切面)
@aspect
@component
@requiredargsconstructor
public class ratelimitaspect {
private final stringredistemplate redistemplate;
@around("@annotation(limit)")
public object intercept(proceedingjoinpoint pjp, ratelimit limit) throws throwable {
string key = "limit:" + pjp.getsignature().toshortstring();
long count = redistemplate.opsforvalue().increment(key);
if (count != null && count == 1) {
redistemplate.expire(key, duration.ofseconds(limit.second()));
}
if (count != null && count > limit.maxcount()) {
throw new runtimeexception("你刷得太快了,休息一下吧!");
}
return pjp.proceed(); // 放行,让他进去
}
}7. mybatis-plus 分页查询 —— 相当于“看书一页一页翻”
- 大白话:如果你的字典(数据库)有 100 万页,你不能把整本书一口气塞给用户看,那会把人的头撑爆(内存溢出)。正确做法是告诉数据库:“我只要第 1 页,一页放 10 条数据”。
- 代码干了啥:让数据库只返回当页的数据(sql 里的
limit),既快又省内存。
@service
@requiredargsconstructor
public class orderservice {
private final ordermapper ordermapper;
public page<order> getorders(long userid, int pagenum, int pagesize) {
// 1. 我要第 pagenum 页,每页 pagesize 条
page<order> page = new page<>(pagenum, pagesize);
// 2. 查询条件:查 userid 是这个人的订单,按时间倒序排
lambdaquerywrapper<order> wrapper = new lambdaquerywrapper<order>()
.eq(order::getuserid, userid)
.orderbydesc(order::getcreatetime);
// 3. 查数据库,只拿这 10 条出来
return ordermapper.selectpage(page, wrapper);
}
}8. resttemplate 设置超时 —— 相当于“打电话设定最长等待时间”
- 大白话:你给第三方(比如微信支付、快递查询 api)打电话(发 http 请求)。如果对方系统挂了、一直不接电话,你不能傻傻地举着电话等一辈子(占用系统资源)。你必须设定:响铃 3 秒不接(连接超时)或者 5 秒不说话(读取超时),立刻挂断!
- 代码干了啥:保护自己,不被调用的外部系统拖垮。
@configuration
public class restconfig {
@bean
public resttemplate resttemplate(resttemplatebuilder builder) {
return builder
.setconnecttimeout(duration.ofseconds(3)) // 等响应建立最多 3 秒
.setreadtimeout(duration.ofseconds(5)) // 等对方传数据最多 5 秒
.build();
}
}
// 调用第三方接口
@service
@requiredargsconstructor
public class remotecallservice {
private final resttemplate resttemplate;
public string callothersystem() {
// 超过时间没反应会直接抛异常挂断,绝对不傻等
return resttemplate.getforobject("https://api.example.com/data", string.class);
}
}还差哪 20% 才能彻底搞定工作与面试?
这 8 个场景帮你封顶了“业务开发”与“高并发”的主干,如果你想做到 100% 稳妥,只需要补齐以下两块:
- 数据库层面的调优(mysql)
- 工作/面试重点: 慢 sql 优化、索引失效场景(如最左前缀法则)、事务隔离级别与 mvcc 机制。
- 线上问题的排查工具与指令(linux / jvm)
- 工作/面试重点: 当服务器 cpu 飙到 100% 或内存溢出时,怎么用
top、jstack、jmap找到是哪行代码出的问题。
- 工作/面试重点: 当服务器 cpu 飙到 100% 或内存溢出时,怎么用
到此这篇关于spring boot后端开发 8 大核心生产级代码模板的文章就介绍到这了,更多相关spring boot 生产级代码模板内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论