Spring实战问题排查:从环境搭建到微服务的避坑清单

发布时间:2026/10/8 18:47:31

Spring实战问题排查:从环境搭建到微服务的避坑清单 只要你肯在Java后端群里蹲一个月就会发现Spring相关的提问翻来覆去就那么几类项目创建不了、Bean注入不上、AOP明明写了却不执行、MyBatis查不到数据、端口号改了没生效、OAuth2登录突然报错……这些问题看起来散其实原因都特别集中通常就是一个配置、一个注解或者一个代理细节的问题。我把自己在带团队做业务系统、帮新人排查问题过程中反复踩过的坑整理成了一份排查方案从项目初始化、Bean容器、Web层、数据访问、配置管理一直延伸到安全、状态机和微服务覆盖了大家搜索频率很高的那几个点。1. 开发环境与项目初始化别卡在第一步1.1 IDEA创建不了Spring项目先分清是网络还是工程结构问题“IDEA为什么创建不了Spring项目”是我见过提问量最高的问题之一。但很多人卡住并不是代码问题而是操作入口和网络问题。先说入口。IDEA有两个版本社区版Community和旗舰版Ultimate。社区版默认没有Spring Initializr向导新建项目时你根本看不到Spring相关选项。这不是软件坏了而是功能本身不在社区版里。应对方法也很简单去 start.spring.io 网页上填好你想要的技术栈下载一个ZIP包然后用IDEA的 File - Open 直接打开Maven项目IDEA会识别pom.xml并自动拉取依赖。如果你用的是旗舰版新建项目时选择Spring Initializr之后一直转圈或者点Finish之后卡在下载进度条大概率是本地网络访问 start.spring.io 失败。这个服务在国外国内网络经常会出现连接超时。解决办法有两个第一在IDEA的 Initializr URL 自定义项里填国内镜像地址比如https://start.aliyun.com第二直接用网页生成ZIP再导入。核心逻辑是一样的只是换了一个更稳定的下载通道。还有一类情况是项目建好了但pom文件一直飘红依赖下载不下来。这里要检查两个东西Maven的settings.xml里面localRepository指向的本地仓库路径是否可用以及是否配置了镜像。建议在settings.xml里加一个阿里云镜像不然首次下载Spring Boot全家桶依赖会非常痛苦。提示项目名不要用中文路径不要带空格否则有些插件解析会出现奇怪的问题。这个习惯建议从一开始就养成。1.2 VSCode里连Spring Boot都跑不起来怎么办用VSCode写Spring Boot的人现在越来越多主要原因是轻量、启动快。但VSCode的问题也很有代表性不是代码问题而是扩展和JDK配置问题。首先必须要装两个扩展Extension Pack for Java和Spring Boot Extension Pack。只装Java扩展的话虽然能跑main方法但Spring Boot Dashboard、自动配置提示、yml文件跳转这些能力都不完整。装完之后VSCode左下角会出现一个Spring Boot的图标点进去能看到当前工作区里所有的Boot应用。常见的“命令不可用”问题第一反应不是重装扩展而是执行命令面板里的Java: Clean Java Language Server Workspace清掉语言服务器的缓存再重新导入。很多情况下是Java Language Server状态乱了而不是扩展没装好。如果还是不行检查JAVA_HOME环境变量是否指向了正确的JDKVSCode自己的终端里执行mvn -v确认Maven能读到同一个JDK。VSCode跑Spring Boot还有一种恶心的现象debug运行时断点不生效。这往往是因为项目没有在Maven的生命周期里重新编译代码和class不同步。执行mvn clean compile再启动基本能解决。没必要迷信IDE开发工具的本质都是给你编译和运行的能力出了问题先看底层命令能不能跑通。2. 容器核心Bean装配、三级缓存和“手写”一条龙2.1 三级缓存到底在缓存什么很多人面试背了“三级缓存”但看代码时根本不知道三个Map在哪里。它就在DefaultSingletonBeanRegistry里面MapString, Object singletonObjects new ConcurrentHashMap(256); MapString, Object earlySingletonObjects new ConcurrentHashMap(16); MapString, ObjectFactory? singletonFactories new HashMap(16);三个Map就是三级缓存。先是singletonFactories存原始对象的工厂再是earlySingletonObjects存提前暴露的半成品实例最后singletonObjects存完整Bean。为什么需要这么绕因为Spring要解决循环依赖。举个最常见的例子A依赖BB又依赖A。A先创建发现需要注入B于是去创建BB创建时又需要A如果此时拿不到A就完蛋了。Spring的做法是A实例化后先把一个ObjectFactory放进第三级缓存这个工厂能返回A的“早期引用”给外部使用。B通过这个早期引用拿到A完成创建A再拿到B完成注入。最终两个Bean都进入一级缓存。那为什么不止两级关键在AOP。如果A需要被代理早期暴露出来的对象应该直接是代理对象。但Spring不能确定A会不会遇到循环依赖它只能通过第三级缓存的ObjectFactory在需要暴露的那一刻才去生成代理。如果没有第三级所有Bean在实例化后都得提前生成代理不仅浪费而且无法处理异常情况。这个设计也解释了一个经典教训构造器注入的循环依赖解决不了。因为构造器注入在实例化阶段就必须拿到完整Bean而三级缓存只能提供“早期引用”没法让B在A构造完成前得到A的可注入属性。所以项目里出现循环依赖优先重构而不是硬扛。2.2 手写Spring用200行代码把IOC和AOP打通“手写Spring”是我特别推荐新人做的一步。你不需要写一个完整的框架只要实现最简单的注解扫描、实例化和属性注入思路立刻通透。核心流程是这样的public class MiniApplicationContext { private final MapString, Object beans new ConcurrentHashMap(); public void scan(String basePackage) throws Exception { // 1. 扫描basePackage下带Component的类 // 2. 反射创建实例 // 3. 放入beans缓存 } private void inject(Object bean) throws IllegalAccessException { for (Field field : bean.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); field.set(bean, beans.get(field.getName())); } } } }这只是个示例真正的MiniSpring还要处理构造函数注入、接口代理、BeanPostProcessor等。但你会发现真写起来时循环依赖会让人非常头疼。A需要BB需要A你不得不在某个环节提前暴露一个不完整的引用于是二级缓存出现了你又需要支持代理于是三级缓存出现了。知道了这个演化过程你再去看Spring源码就不会觉得那三个Map是什么黑魔法了。手写过程中的第二个启发是AOP。你可以给容器加一个后处理器在某个Bean完成初始化后通过反射动态生成一个代理对象放回缓存里。这样调用方拿到的Bean其实是一个代理日志、事务这类能力就都能织入进去。理解这个点后面AOP不生效的排查就会特别快。2.3 NoSuchBeanDefinitionException的排查顺序遇到NoSuchBeanDefinitionException不要急按顺序查包扫描范围。Spring Boot启动类默认扫描它所在包及子包如果你的Service放在别的包下没加ComponentScan就会找不到。是否加了注解。Service、Repository、Component等价于注册Bean但很多人只加了接口实现类没写注解。有没有多个实现类。两个类实现了同一个接口注入时Spring不知道选谁类型匹配失败。解决方案是用Primary指定主实现或者加上Qualifier指定Bean名字。注入方式。构造器注入、字段注入、setter注入对某个参数不存在时的报错都快差不多但查看堆栈时注意看行号。这里给一个比较省事的排查技巧直接在启动类里注入目标类型启动时如果报错会明确告诉你“expected at least 1 bean which qualifies as autowire candidate”。把这句话翻译成人话要么没有这个Bean要么有两个候选Spring不知道选谁。大多数时候问题就是这两个。3. Web层与AOP接口日志、MVC路由问题的排查3.1 用AOP实现日志记录的两种姿势AOP日志是搜索热度很高的场景项目里做操作日志、接口访问日志都离不开它。最简单的做法是切所有ControllerAspect Component public class WebLogAspect { Around(within(org.springframework.web.bind.annotation.RestController)) public Object around(ProceedingJoinPoint pjp) throws Throwable { long start System.currentTimeMillis(); Object result pjp.proceed(); long cost System.currentTimeMillis() - start; log.info(调用{}.{} 耗时{}ms, pjp.getSignature().getDeclaringTypeName(), pjp.getSignature().getName(), cost); return result; } }这种直接用within表达式会切所有RestController适合全局访问日志。如果你想控制粒度可以自定义一个注解Target({ElementType.METHOD, ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) public interface OpLog { String value() default ; }然后在切面里用annotation(opLog)并且把注解当作切面方法的入参传进来就能拿到具体的操作描述。这个模式在电商类项目里非常常用比如“用户下单”“商品上架”“删除商品”每个方法上标一个值日志整理起来特别清晰。需要注意AOP打印参数时经常会遇到序列化失败。HttpServletRequest、MultipartFile这类对象不能直接toString必须排除掉。最简单的处理方式是把参数列表转换成JSON但用Jackson序列化时也要过滤掉非标准对象。不然你的“日志切面”反而会成为系统的报错源。3.2 怎么查看AOP切面到底有没有生效这个问题比“怎么实现日志记录”更难排查。AOP明明写了却不生效原因通常不出在语法上而在代理机制上。先讲怎么确认AOP有没有启用。Spring Boot环境下只要引入spring-boot-starter-aop自动配置会帮你启用EnableAspectJAutoProxy。如果你想验证是否真的启用了可以在application.yml里打开自动配置报告management: endpoints: web: exposure: include: conditions访问/actuator/conditions搜索AopAutoConfiguration如果显示POSITIVE就说明自动配置生效了。更直观的方式是断点调试在切面里打一个断点如果请求进入切面那就说明一切正常。还有一个更简单的办法在要检查的Bean上打印它的Class名称如果名字里带CGLIB或者$Proxy说明它已经被代理了。真正不生效的常见原因有四个缺依赖。用了AOP但没引spring-boot-starter-aop。切点表达式不对。execution(* com.xx.service.*.*(..))和实际包名对不上表达式写歪了。类或方法是final或private。Spring AOP默认用代理代理类无法继承或覆盖final方法。内部自调用。类A的方法a()调用了同类的方法b()b()上面加了Around是不会触发的因为调用发生在类内部压根没经过代理对象。解决自调用的标准方案有两种注入自身实例或者用AopContext.currentProxy()。用后者需要在启动配置里开启exposeProxytrue让Spring把代理对象放到ThreadLocal里。但本质上这属于设计问题真正干净的做法是把切面逻辑抽到另一个组件中让方法调用通过代理完成。3.3 Spring MVC的404和跨域问题不只是路由的锅Spring MVC最常见的两个问题一个是你写了个Controller方法返回String类型结果页面显示404另一个是前端跨域请求被拦截。返回String出现404十有八九是视图解析器导致的。Controller加方法返回StringSpring MVC会把这个字符串当成逻辑视图名去找对应的Thymeleaf或JSP模板。找不到就报404。你要返回JSON数据请使用RestController或者在方法上加ResponseBody。这个问题我见过太多新人踩坑重要到可以背下来RestControllerControllerResponseBody。跨域问题则常见于前后端分离项目后端请求接口返回正常但浏览器就是拦截。Spring Boot的解决方法是统一注册CORS配置Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(http://localhost:5173) .allowedMethods(*) .allowedHeaders(*); } }注意allowedOrigins不能写*同时配allowCredentials(true)否则会报错。前端如果用的是Vite开发服务器端口默认5173后端要把这个来源加进去。另外加了EnableWebMvc后Spring Boot对静态资源的默认映射全部失效这也是很多项目里静态资源突然404的隐藏原因。4. 数据访问MyBatis集成与业务项目里的坑4.1 Spring Boot MyBatis集成必查的五个配置有人下载“Spring Boot MyBatis的多商户跨境商城源码”之后跑不起来第一反应是源码问题。但绝大多数是配置没对齐。MyBatis集成到Spring Boot最容易被忽略的是Mapper扫描。有三种方式任选其一在配置类上用MapperScan(com.xxx.mapper)在每个Mapper接口上加Mapper或者在MyBatis的配置里开启包扫描。没配置好启动时就报“Invalid bound statement”。其次是XML路径mybatis: mapper-locations: classpath:mapper/**/*.xml第三个是驼峰映射。数据库字段是user_nameJava属性是userName如果不开启驼峰转换查询结果里这个字段就是null。配置如下mybatis: configuration: map-underscore-to-camel-case: true第四个是别名包。XML里写resultTypeUser而不是com.xxx.entity.User需要配置type-aliases-package。最后是打印SQL日志可以用mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这套配置加上之后大部分“运行不了”的问题都能解决。4.2 多商户跨境电商项目、仿天猫购物系统里的登录注册模块“Spring Boot MyBatis多商户跨境商城源码”和“基于Spring Vue仿天猫购物系统”这类项目核心都绕不开登录注册和用户管理模块。很多源码能跑通但一旦你往里加功能就出问题问题大多出在这两处。第一处是密码加密。老项目里大量使用MD5加盐但正规项目应该使用BCryptPasswordEncoder。它自带随机盐同一个密码每次加密结果都不同校验时用.matches(明文, 密文)。千万别在数据库里存明文密码也不要自己写一个看起来很高端实际有漏洞的Hash算法。第二处是多商户的数据隔离。多商户商城里有个很容易被忽略的字段商户ID。商品表、订单表、优惠券表都有这个字段。如果你每次查询都要手动写WHERE merchant_id ?总有一天会漏掉一个Mapper导致数据越权。靠谱的做法是做一个MyBatis拦截器自动解析当前登录商户往查询SQL里追加商户ID条件。这也是很多成熟多租户方案的核心思路。登录注册的用户管理模块还有一个高频坑分页。直接用PageHelper时要注意PageHelper.startPage()必须紧跟第一条查询语句中间不能有别的SQL操作否则分页条件会加到错误的查询上。这个注解式分页虽然方便但也容易让新人摸不着头脑。4.3 大学生就业推荐系统这类CRUD项目的性能点“基于Spring Boot的大学生就业推荐系统”是典型的毕业设计或实践项目。它看着功能多其实就是学生、简历、岗位和推荐记录几张表之间的CRUD。这类项目最容易出现N1查询问题。比如查岗位列表时每查出一个岗位又去查一次所属公司信息循环里发SQL。解决方法是使用MyBatis的resultMap集合映射一次联表查询把多层对象组装出来。不过联表也别上来就三表五表乱join先看字段是否真的需要。推荐功能也不一定要上机器学习。最简单可解释的方案是做标签匹配把学生技能和岗位要求分别拆成标签交集数量越多推荐分越高。用一条带动态SQL的查询就能搞定。这类系统的数据库表结构设计要注意唯一索引比如用户名和邮箱都加唯一约束避免用户注册重复数据。加上数据库层面的兜底远比在代码里做一次if判断更可靠。5. 配置管理端口号修改、配置优先级与占用排查5.1 修改Spring Boot Demo端口号的五种方式“Spring Boot修改Demo端口号”是非常基础的问题但实际工作中你会发现端口号问题远不止写一行配置那么简单。最直接的方式是在application.properties里写server.port9090如果项目用yml则是server: port: 9090第三种是启动时通过命令行参数覆盖java -jar demo.jar --server.port9090第四种是设置环境变量为SERVER_PORT9090Spring Boot会把它映射到server.port属性。第五种是在代码里设置默认属性SpringApplication app new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap(server.port, 9090)); app.run(args);这几种方式不是乱用的它们之间有一定优先级。当命令行参数存在时它优先于环境变量环境变量又优先于application.yml。这意味着你明明改了application.yml里的端口号但启动时还是8080极大可能是IDEA或命令行里带了旧参数。对于多套环境比如本地、测试、生产建议在配置文件里引用环境变量server: port: ${SERVER_PORT:8080}没有设置SERVER_PORT时就默认8080设置了就用环境变量的值。这样代码移植性强不会每次部署都改配置文件。5.2 端口被占用和“改了不生效”的真相端口被占用经常会伴随错误信息Port already in use。在Linux/Windows下先用命令找到占用进程# Linux/macOS lsof -i :8080 # Windows netstat -ano | findstr 8080找到PID后杀掉进程或者换端口。这类问题排查本身并不难难的是“我明明改成了9090却还在报8080被占用”。这种“改了不生效”大概率不是你改错了地方而是启动方式或配置优先级的问题。IDEA里有一个很隐蔽的坑运行配置Run/Debug Configurations里把参数写死在Program arguments中比如--server.port8080。你改application.properties没用因为命令行参数优先级更高。解决方法是编辑运行配置把旧的端口参数删掉。同理如果环境变量里设置了SERVER_PORT它也会静静覆盖配置文件。还有一种情况是Spring Cloud项目使用了bootstrap.yml而不是application.yml。在Spring Cloud早期的版本里远端的配置优先本地application.yml反而会被忽略。所以排查的原则很简单先检查启动命令再检查环境变量最后检查配置文件层级“不生效”的真相往往就在这一步。6. Spring Security OAuth2、状态机与自定义校验6.1 OAuth2 Authorization Server配置范本与常见报错Spring Security的授权服务器在旧版本里是spring-security-oauth2新项目建议直接用官方维护的spring-boot-starter-oauth2-authorization-server。它承担Authorization Server角色独立于资源服务器这个职责拆分经常让新人困惑。一个最精简的配置包含三个BeanSecurityFilterChain、RegisteredClientRepository和JWKSource。RegisteredClient用来定义客户端信息RegisteredClient client RegisteredClient.withId(UUID.randomUUID().toString()) .clientId(web-client) .clientSecret({noop}secret) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri(http://127.0.0.1:8080/login/oauth2/code/web-client) .scope(openid) .build();JWKSource用于签发和验证Token的密钥。用RSA KeyGenerator生成一对密钥包装成JWKSet即可。生产环境要用持久化的RSA密钥否则服务重启后已签发的Token全部失效。最常见的报错有两种一种是redirect_uri不一致。你配置的注册客户端里写的回调地址必须和请求中的redirect_uri完全一致包括协议、端口和路径少一个斜杠都不行这个规则比你想的严格得多。另一种是unsupported_grant_type请求的授权类型没有在authorizationGrantType里注册比如用密码模式但只配置了授权码模式自然会失败。还有一点很关键Authorization Server的过滤链和普通业务的过滤链要分开用Order明确优先级。不然/oauth2/token和你的后台接口会被相同的登录逻辑拦截调试起来会让你怀疑人生。6.2 Spring状态机把复杂流程从if else里解放出来订单状态、审批流、工单流转这些业务用一堆if else判断也不是不能写但状态一多就变成谁都不敢动的面条代码。Spring State Machine的价值在把状态、事件、迁移规则和动作彻底拆开。核心概念就三个状态、事件、迁移。用状态机描述订单就是StateMachineBuilder.BuilderOrderState, OrderEvent builder StateMachineBuilder.builder(); builder.configureStates() .withStates() .initial(OrderState.WAIT_PAY) .end(OrderState.CLOSED); builder.configureTransitions() .withExternal() .source(OrderState.WAIT_PAY) .target(OrderState.PAID) .event(OrderEvent.PAY) .and() .withExternal() .source(OrderState.PAID) .target(OrderState.CLOSED) .event(OrderEvent.CLOSE); StateMachineOrderState, OrderEvent machine builder.build(); machine.start(); machine.sendEvent(OrderEvent.PAY);迁移上还可以挂Guard和Action。Guard决定这个事件在当前状态下能不能被接受Action表示迁移成功后要执行的业务动作比如支付成功后的发货通知。这里有个非常容易踩的坑状态机实例不是线程安全的而且它自带当前状态。多个用户并发操作同一订单时不能共用一个状态机Bean来读状态否则会串。建议每次处理业务时从构建器重新生成状态机或者使用StateMachinePersister把状态持久化到数据库每次从数据库恢复。另一个坑是状态迁移时事件不匹配。发送一个当前状态下不允许触发的事件时状态机返回false但不会抛异常。如果你没有监听事件整个流程看起来就是“什么都没发生”。正确做法是要实现Listener或者在调用处显式校验machine.sendEvent(...)的返回值。6.3 自定义Validate不触发很多是注解目标写错了Spring自定义校验是个很实用的功能。业务上比如校验手机号、校验身份证号写一个自己的校验注解并不复杂。先定义一个注解Documented Constraint(validatedBy PhoneValidator.class) Target({ElementType.FIELD, ElementType.PARAMETER}) Retention(RetentionPolicy.RUNTIME) public interface Phone { String message() default 手机号格式不正确; Class?[] groups() default {}; Class? extends Payload[] payload() default {}; }再写对应的校验器public class PhoneValidator implements ConstraintValidatorPhone, String { Override public boolean isValid(String value, ConstraintValidatorContext context) { return value ! null value.matches(^1\\d{10}$); } }然后在DTO字段上加上Phone并且Controller入参处必须加Valid或ValidatedPostMapping(/user) public Result createUser(Validated RequestBody UserDTO dto) { return Result.ok(); }自定义校验不触发第一个原因就是Controller参数上少了Valid或Validated。第二个原因是在Service层校验但忘了在Service类上加Validated。想在Service方法参数上校验类上必须有Validated参数上再加Valid。还有一个容易踩的坑Constraint里的validatedBy写错类名时启动阶段不一定报错运行期才提示找不到校验器。另外Target里如果没有ElementType.PARAMETER那它就不能用在方法参数上你会拿到一个非常隐蔽的编译错误。校验失败后的异常也不要忘了全局处理不然前端拿到的是一个不太友好的500而不是参数错误提示。7. Spring Cloud微服务从体验到快速上手的坑7.1 快速上手的服务注册与发现配置“Spring Cloud微服务快速上手PDF”是很多人会搜的资料但PDF只能告诉你概念真正上手时会卡在版本兼容和注册中心配置上。Spring Cloud的版本和Spring Boot版本强绑定。Spring Boot 3.x要用Spring Cloud 2022.0.x以后的版本DependencyManagement版本对应不上启动就会报各种ClassNotFound。建议去 start.spring.io 直接选Cloud相关依赖不要自己手拼坐标。服务注册最朴素的一段配置长这样spring: application: name: order-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848一定要有spring.application.name注册中心里显示的服务名就是它也是后续Feign调用时的名字。如果服务注册不上先看注册中心里面的服务列表再去调服务提供者的/actuator/health接口确认健康状态。注册中心只要拉不到服务健康信息就会一直把服务踢下线。7.2 Feign调用失败和网关404的排查清单Feign是微服务之间调用的利器但报错时排查起来也很典型。Feign调用失败第一件事看两端服务提供者有没有启动FeignClient(name order-service)里的name是不是和注册中心的服务名完全一致只看一个小写一个横杠都会导致找不到实例。第二件事看有没有EnableFeignClients这个注解要放在启动类上或者指定扫描的包路径。第三件事看负载均衡依赖Spring Cloud 2020版本之后把Ribbon移除了必须额外引入spring-cloud-starter-loadbalancer否则调多实例服务时会报“No instances available”。网关404的症结往往在路由配置。一个常见路由配置是spring: cloud: gateway: routes: - id: order-route uri: lb://order-service predicates: - Path/api/order/**这里最容易被忽视的是服务端接口实际路径是/order/info但网关断言是/api/order/**那就要在过滤器里重写路径比如用StripPrefix1去掉一层前缀。路由URI必须写成lb://服务名表示从注册中心按负载均衡找实例如果写成了http://localhost:8080那就完全绕过了注册中心还叫什么微服务。7.3 学习资料怎么选源码、视频还是PDF回到“Spring实践视频”“手写Spring”这类搜索词。我的判断标准其实很简单你正在解决的问题类型决定了该看什么资料。学习新框架直接跑一个完整项目源码比任何视频都快。网上的多商户商城源码、仿天猫购物系统源码下载后先不看代码而是看README、看application.yml把项目拉起来再说。能把一个别人的项目在自己电脑上跑通胜过你刷十节视频课。遇到某个具体技术点不懂比如AOP为什么没执行、OAuth2为什么报错这种时候适合看短视频或文章因为问题太具体长视频反而浪费时间。PDF适合系统化阅读比如Spring Cloud架构设计、状态机原理这类偏基础理论的内容用PDF或官方文档来啃更合适。还有一类资料是源码本身。比如“手写Spring”的教程哪怕你只看懂一小段也会对Bean生命周期豁然开朗。资料不是越贵越好而是越贴合你当前的问题越好。我自己的习惯是项目跑不起来的时候不读书先查配置配置对了代码还是不对时再去看原理书带着问题读书才有效果。上面这些排查方式是我在实际项目里反复用过很多遍的路径环境、Bean、AOP、配置、数据、安全、微服务按这条线走一遍大部分Spring问题都不会纠缠太久。养成这个顺序习惯之后你再碰到新问题第一反应会是“我去确认一下具体配置”而不是“我又要开始玄学调参了”。
延伸阅读

更多相关文章

2026/10/8 18:47:31

基于SpringBoot的遥感影像共享系统-springboot

本项目为前几天收费帮学妹做的一个项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 基于SpringBoot的遥感影像共享系统通过Mysql数据库连接数据库 http://localhost:80…

2026/10/8 18:42:31

越华环保集团碳惠小屋:数字化碳普惠载体,构建绿色循环智慧体系

1. 行业技术痛点:线下碳普惠落地存在多重瓶颈国内碳普惠数字化建设已进入快速发展阶段,线上碳账户体系日趋成熟,但线下实体场景仍存在明显技术短板。传统回收终端普遍存在识别精度低、称重误差大、弱网数据丢失、无标准化碳核算能力、数据无法…

2026/10/8 18:42:31

SMT贴片加工怎么选?采购最容易忽略的四个判断点

找SMT贴片加工厂,很多采购的第一反应是比价。报价单拉出来,逐项对比单价、贴片费、钢网费,谁便宜选谁。这个逻辑不能说错,但实际合作下来会发现,价格只是结果,真正决定合作顺不顺的是另外几件事。这篇文章从…

2026/10/8 21:13:12

OpenCvSharp滤镜实现:C#调整饱和度、对比度与锐化的完整指南

简介:一份面向C#开发者的OpenCvSharp图像滤镜Demo,演示如何通过OpenCV的.NET封装实现饱和度、明度、对比度、锐化、阴影、高光及色温等常见图像处理效果。资源以完整Visual Studio解决方案形式提供,包含核心窗体代码、界面设计文件和项目配置…

2026/10/8 21:13:12

Mac Mini 跑 OpenClaw 本地智能体:部署、Ollama 推理与成本避坑指南

1. 为什么我最终选了 Mac Mini 而不是云主机来跑 OpenClaw先说结论:如果你打算长期折腾 OpenClaw 这类本地智能体框架,Mac Mini 是目前性价比最均衡的一台"常驻机"。我自己前前后后试过三种方案——云服务器、旧笔记本、Mac Mini,最…

2026/10/8 21:13:12

context-mode:现代工具链中的上下文协商机制解析

1. “context-mode”不是功能开关,而是现代工具链中隐性存在的上下文协商机制你第一次在终端里敲下mcp --help,看到--context-mode这个参数时,大概率会愣一下:它没出现在主流文档首页,不带示例,甚至没有默认…

2026/10/8 21:13:12

dump1090-win Windows ADS-B接收实战指南

简介:本资源是面向Windows平台的ADS-B航空信号接收与解析工具包,专为无线电爱好者、航空监测初学者及嵌入式/SDR实践者设计,解决在Windows环境下快速部署RTL-SDR飞行追踪系统的实际需求。压缩包共18个文件,含2个核心可执行程序&am…

2026/10/8 21:13:12

涨跌预测实操指南:从数据清洗、特征工程到严谨回测

简介:一份名为“涨跌预测高质量精讲”的压缩包,是一套面向金融时序预测初学者的机器学习与深度学习实战资料,聚焦股票等市场价格涨跌趋势的建模流程。包内共七个文件,涵盖四个脚本、两张数据表和一个模型文件,整体体积…

2026/10/8 21:08:11

marketingskills:AI营销技能库实战指南,从SEO到CRO全流程拆解

1. 从“marketingskills”说起:一个被低估的AI营销技能库第一次看到marketingskills这个词,是在一个做独立站的朋友群里。有人甩了个链接,说“这套东西把SEO和CRO的活儿全拆成AI能执行的技能了”。我当时没太在意,直到自己手头一个…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑