多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

IDEA中创建Spring项目全攻略:从Spring Boot到纯手写工程

IDEA中创建Spring项目全攻略:从Spring Boot到纯手写工程 作为一个天天跟Spring打交道的开发者我几乎每周都要在IDEA里创建新的Spring项目。很多人觉得这就是个“下一步下一步”的体力活没什么技术含量但实际上我见过太多人在这一步就掉坑里了用社区版找不到Spring Initializr、选错JDK版本导致项目起不来、创建完Spring Boot项目却不知道入口在哪、甚至有人折腾半天连个Hello World都没跑通。这篇就从我实际操作的视角出发把IDEA中创建Spring项目这件事讲透覆盖两种经典姿势用Spring Initializr快速生成Spring Boot项目以及在IDEA社区版里手写一个Spring项目。不管你是刚入门想跑通第一个接口还是老手想理清背后的机制这篇都值得看完。1. 先弄明白你要创建的是哪种Spring项目很多初学者一上来就卡住了因为“Spring项目”这个概念本身就太宽泛。我在指导新人的时候经常被问到“为什么我在IDEA里新建项目没看到Spring选项”或者“别人说用Spring Boot很简单怎么我这儿这么费劲”。这类问题的根源就在于没有先分清楚项目的类型和创建工具的差异。1.1 Spring Boot项目与经典Spring项目到底差在哪简单粗暴地理解经典的Spring项目指的是用Spring Framework核心模块搭起来的工程你需要手动配置很多东西比如把spring-context、spring-webmvc这些依赖一条条加进pom.xml自己写配置类、自己配置DispatcherServlet甚至还要考虑怎么把项目部署到Tomcat。这种方式的优点是你能清楚地看到Spring容器是怎么一步步建立起来的对理解底层机制非常有帮助。而Spring Boot是在Spring之上做了大量自动配置的框架它内置了Tomcat你只需要引入spring-boot-starter-web这个依赖就能用main方法直接启动一个Web应用完全不用关心传统部署那套流程。所以Spring Boot项目本质上还是Spring项目只是它把很多繁琐的配置工作替你完成了。我在实际工作中几乎都是用Spring Boot来写业务代码但学习的时候一定要先动手写过纯Spring项目否则你对IoC容器、Bean的生命周期、包扫描这些概念的认知会很虚。1.2 用什么方式创建取决于你这台IDEA是什么版本这是很关键的一点。IntelliJ IDEA分社区版Community和付费版Ultimate两个版本在新建Spring项目时的体验完全不同。付费版Ultimate在新建项目向导里直接内置了Spring Initializr你可以在IDEA界面里勾选依赖、选择Spring Boot版本一键生成完整的Spring Boot工程。社区版Community是完全免费的但代价是新建项目向导里没有Spring Initializr也没有内置的Spring/Spring Boot模板。不过这不代表社区版就不能建Spring项目你有两条路可以走一条是去Spring官网的start.spring.io这个在线初始化服务生成一个工程压缩包下载后导入IDEA另一条是直接创建一个空白Maven工程手动把Spring依赖写进去从零手搭。我自己在社区版上练习过无数次手写Spring项目其实体验不比付费版差反而更清楚整个工程是怎么组装起来的。很多新手看到网上的教程用的是付费版界面就以为社区版建不了Spring项目这是个很大的误解。对比项IDEA UltimateIDEA Community获取方式付费订阅可试用完全免费开源Spring Initializr内置在新建向导没有需用在线start.spring.ioSpring Boot运行配置内置支持可通过Maven插件运行Tomcat/应用服务器集成内置需要借助Smart Tomcat插件或Maven插件适合谁日常开发主力、企业办公学习、练习、轻量开发我在给新人的建议里最常说的一点是如果你还没毕业或者刚入行完全可以用社区版学Spring别把时间浪费在找激活码这件事上把精力放在理解工程本身才是正路开发工具这块不用省但也不是非付费版不可。2. 用Spring Initializr生成Spring Boot项目Ultimate版最快的路径如果你用的是IDEA Ultimate版创建Spring Boot项目确实很省心。我就按平时操作的顺序把每一步拆开讲顺便把为什么这么选的原因也摆出来。2.1 新建项目时的关键参数怎么选在IDEA里依次打开File → New → Project左侧选择Spring Initializr接下来你会看到一堆需要填写的参数。这里我逐个说下实际项目里我一般怎么填Name项目名称一般用小写字母加连字符比如demo-service。Location项目存放路径这个没什么讲究但不要放在含中文、空格和特殊字符的目录下否则后面Maven打包很可能报一些奇怪的路径错误。Language选择Java。虽然IDEA也支持Kotlin和Groovy但绝大多数Spring项目还是Java为主。Type选择Maven。Gradle适合复杂构建和Android系项目但国内Java生态里Maven的通用性更高团队协作时用Maven也更保守稳妥。Group一般写成公司/个人域名的倒序比如com.example。它和Artifact一起构成Maven坐标也就是这个项目在仓库里的唯一标识。Artifact通常和项目名保持一致。如果你想让生成的jar包名更简短这里可以直接改但Maven坐标和项目名不一致有时候会引起混淆我习惯保持一致。JDK版本这一步很关键。Spring Boot 2.x一般要求JDK 8或11Spring Boot 3.x则必须JDK 17及以上。我现在的开发环境默认用JDK 17对应的Spring Boot版本选3.x系列。版本不匹配是新人最容易踩的坑经常看到有人Spring Boot 3.x配JDK 8项目一跑就报错报错信息还看不明白。2.2 依赖怎么勾选新手的第一个项目尽量克制在向导里进入Dependencies这一步时很多人恨不得把所有勾选框都勾上看到Spring Web、Security、JPA、Redis都想加觉得加上以后功能就齐全了。我真心建议第一次练手就只选一个Spring Web最多再选Spring Boot DevTools。原因很简单每多一个依赖就多一堆自动配置和潜在的问题概率。你还没跑通Hello World就先被Spring Security的登录拦截搞得怀疑人生没必要。我这里拿“我要建一个供第三方调用的接口服务”来举例。你若真要做对第三方提供的接口服务我建议的方式也不是把所有接口堆在一个大而全的工程里而是按照业务边界拆分核心能力沉淀成内部服务对外暴露的接口单独做一个薄薄的适配层服务。这个思路在新建项目的时候就要想清楚否则后面代码一多你想拆都拆不动。2.3 项目生成后的第一眼检查点击Create之后IDEA会花点时间下载依赖第一次通常比较慢因为要把Spring Boot相关的jar包都拉到你本地的Maven仓库。等待期间观察左下角进度条如果长时间卡着不动大概率是网络问题可以考虑给Maven配置阿里云镜像这个我在后面问题排查里再详细讲。依赖下载完成后你会看到一个标准的Spring Boot工程结构。我第一眼会先看src/main/java下有没有一个带SpringBootApplication注解的启动类比如DemoApplication。这个东西就是整个项目的入口记住一个规律SpringApplication.run(DemoApplication.class, args)这行代码一执行内嵌的Tomcat就启动了你的Web服务就在8080端口开始监听了。为了验证项目是不是真能起来我会在项目里快速写一个测试接口package com.example.demospring; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; RestController public class HelloController { GetMapping(/hello) public String hello() { return Hello, Spring!; } }写完直接运行启动类的main方法等控制台出现Started DemoApplication这样的日志后浏览器访问http://localhost:8080/hello能看到返回的Hello, Spring!这个Spring Boot项目就算真正创建并验证成功了。注意这个小接口帮你验证的是“项目创建对不对、环境通不通”它不值得保留在你的正式代码里跑通以后就该把它删掉。我见过有人把HelloController留在生产项目里几年不删的虽然不影响功能但很不专业。3. IDEA社区版创建纯Spring项目一步不落的手工搭建接下来这部分是重头戏因为我身边不少朋友用的就是社区版而且很多人想学的其实是“怎么在不依赖Spring Boot的情况下手动搭一个Spring项目”。这个需求太真实了我自己刚学Spring的时候就是这么干的。下面我把完整过程写出来每一步都给出明确的代码和理由。3.1 创建空Maven工程并引入Spring核心依赖在IDEA社区版里打开File → New → Project选择Maven不勾选任何骨架模板直接创建一个空的Maven工程。创建完之后IDEA会生成一个最基本的pom.xml。接下来手动把Spring依赖加进去。我推荐的最小可用依赖配置是这样properties maven.compiler.source17/maven.compiler.source maven.compiler.target17/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding spring.version5.3.41/spring.version /properties dependencies dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency /dependencies这里我特意把spring-context单独拎出来是因为它包含了Spring IoC容器的核心实现。只加这么一个是刻意为之让案例足够简单因为我们的目的不是堆功能而是验证Spring能不能把Bean管理起来。如果你要做的是Web项目还需要额外引入Spring MVC相关的东西比如spring-webmvc。但对于刚创建项目、先验证容器能不能用来说spring-context已经足够。3.2 写配置类、定义Bean和测试容器依赖加好以后在src/main/java下创建一个包比如com.example.demo。然后写一个最普通的类业务上完全没有什么技术含量就是验证用的package com.example.demo; import org.springframework.stereotype.Component; Component public class GreetingService { public String greet(String name) { return Hello, name !; } }再写一个配置类用来告诉Spring去哪里扫描组件package com.example.demo; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; Configuration ComponentScan(com.example.demo) public class AppConfig { }Configuration这行注解的作用是把这个类标记为Spring的配置类ComponentScan则指定了扫描路径。Spring启动的时候会扫描这个包下面所有带有Component、Service、Repository等注解的类把它们注册成Bean。最后写一个入口类用AnnotationConfigApplicationContext来测试package com.example.demo; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class DemoApplication { public static void main(String[] args) { try (AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class)) { GreetingService greetingService context.getBean(GreetingService.class); System.out.println(greetingService.greet(Spring)); } } }运行这个main方法控制台如果输出Hello, Spring!说明你的手写Spring项目已经创建成功容器能正常扫描、注册并获取Bean了。这个小例子别看简单它把IoC容器的工作过程完整走了一遍比直接拉一个Spring Boot项目跑起来所理解到的东西要深刻得多。3.3 让手写的Spring Web项目在Tomcat里跑起来上面那个例子验证了IoC容器但很多人的目的是做Web开发所以需要跑出一个能被浏览器访问的页面。如果是Spring Boot项目内嵌Tomcat已经帮你解决了一切但社区版里纯手写的Spring MVC项目还需要想办法配一个Servlet容器。我的经验是做Web项目时直接引入spring-boot-starter-web依赖然后用手写Configuration而不是使用被广泛提及的自动装配这样既能感受Spring Boot的便利又能保持手动创建项目的感觉。具体做法是保留前面工程的基础上在pom.xml里增加dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId version2.7.18/version /dependency然后写一个Controller和一个带EnableAutoConfiguration注解的启动类package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; EnableAutoConfiguration ComponentScan(com.example.demo) RestController public class ManualSpringApplication { public static void main(String[] args) { SpringApplication.run(ManualSpringApplication.class, args); } GetMapping(/manual) public String manual() { return Manual Spring Project is running!; } }运行main方法后访问http://localhost:8080/manual看到返回字符串就说明成功了。这种方式的好处是你没有用IDEA内置的Spring Initializr但依然靠着Spring Boot自动配置和内置Tomcat把Web项目跑了起来。如果你希望走更经典的纯Spring MVC路线可以在pom.xml里配置tomcat7-maven-plugin然后用mvn tomcat7:run命令启动。但说实话这样既绕远又容易出现插件版本兼容问题我现在给朋友推荐的都是上面这种“手动写配置类 Spring Boot启动器”的方式兼顾学习意义和实际效率。4. 项目创建出来之后骨架为什么会是长这样很多人创建完Spring项目看一眼目录结构就赶紧写代码去了根本不思考这个骨架是怎么来的。我觉得这很可惜因为骨架里每个目录、每个文件的摆放都有讲究把这些弄明白了你对项目的掌控力会高一个档次。4.1 Maven目录结构与分层职责标准Maven工程的目录结构长这样src/main/java 放Java源代码 src/main/resources 放配置文件、静态资源、模板文件 src/test/java 放单元测试代码 target Maven构建输出目录编译后的class文件、打好的jar包都在这我经常被问到一个问题为什么IDEA里看不到target目录其实不是没有而是IDEA默认会过滤掉这个目录因为它是构建产物一般不需要纳入版本管理也不该出现在代码审查里。真要看的话可以在IDEA的设置里取消对该目录的过滤或者直接在磁盘上打开工程文件夹查看。分层这块我一般建议在src/main/java下按照包名区分业务层次比如controller、service、repository、entity、config等。这样做让代码职责清晰也是Spring项目最主流的风格。不要把所有类都堆在同一个包下面那是给自己找麻烦。4.2 从启动类到Bean注册一个请求是怎么走起来的我拿一个标准的Spring Boot项目来拆解。启动类DemoApplication上的SpringBootApplication是一个组合注解它相当于Configuration EnableAutoConfiguration ComponentScan这三个注解的集合。也就是说启动类本身就标记了扫描范围和自动配置的开关。当程序运行时Spring Boot会先启动内嵌Tomcat然后根据你在pom里引入的依赖执行对应的自动配置。引入spring-boot-starter-web就自动配置了DispatcherServlet和Spring MVC相关组件引入spring-boot-starter-data-jpa就自动配置数据源和ORM映射。接着ComponentScan会扫描当前启动类所在的包和所有子包把标有RestController、Service、Repository等注解的类都注册进容器。你写一个GetMapping(/hello)的接口Spring MVC框架接收到外部HTTP请求后就是根据这个注解做路由匹配找到对应的方法去执行的。4.3 顺便说说Spring三级缓存和Bean创建既然热搜词里反复出现“Spring三级缓存原理”这里就借着“项目创建后容器是怎么管理Bean的”这个话题把它说清楚。所谓三级缓存的本质是Spring在处理Bean循环依赖时的三个缓存集合一级缓存保存完整创建好的单例Bean。二级缓存保存提前暴露的早期Bean引用尚未完成全部属性赋值的对象。三级缓存保存一个对象工厂这个工厂能在需要的时候生成早期Bean引用。循环依赖的场景就是A依赖B、B依赖A。容器创建A时发现需要B就去创建BB又要依赖A这时候容器从三级缓存里找到A的工厂提前拿到A的早期引用先塞给B等B创建完后A再拿到完整的B。整个过程靠这三层缓存兜底既绕开了“鸡生蛋蛋生鸡”的死循环又确保最终拿到的是完整对象。我刚学的时候总觉得这是很高深的原理直到自己在手写Spring项目、调试Bean创建日志的时候才彻底理解它其实就是一套为了解决循环依赖而设计的“先给引用、后补完整”的机制。你不需要背概念等项目创建多了、看多了启动日志自然就懂了。提示Spring Boot 2.6版本之后默认把循环依赖的允许开关关掉了你如果新建项目遇到Consider defining a bean of type这类报错优先想想是不是循环依赖导致的而不是急着改配置强行放行。5. 实操中的高频问题与排查速查表这部分全是干货。我这些年创建、维护Spring项目踩过无数回坑这里挑出现频率最高的几个做成速查表你们遇到类似的问题直接照着定位就行。5.1 创建阶段最常见的问题问题现象直接原因解决办法新建项目时没有Spring Initializr选项使用的是IDEA社区版去start.spring.io在线生成后导入或参照第3章手动搭建项目启动报Invalid source release: 17项目编译级别和JDK不匹配检查Project Structure里的SDK和Java版本确保统一依赖下载失败或超时访问中央仓库慢/被限制在Maven的settings.xml里配置阿里云镜像运行启动类报Port 8080 was already in use8080端口被其他进程占用换端口在application.properties中配置server.port8081Failed to configure a DataSource引入了数据库依赖但没有配置连接信息去掉不需要的数据库依赖或配置数据源信息这里特别展开说下Maven阿里云镜像怎么配置。打开你本地的Maven安装目录下的conf/settings.xml在mirrors节点里加mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror加了之后依赖下载速度会明显提升这是国内开发者必做的一步我不管在哪个电脑上配Maven都会顺手配上。5.2 IDEA使用中的几个疑难症状这里说几个IDEA使用过程中常见的诡异问题虽然不是创建项目时必踩的但特别容易让人烦躁。第一代码格式化失效。新手经常碰到“按了CtrlAltL没反应代码缩进乱糟糟”的情况。这时候优先检查File → Settings → Keymap里快捷键有没有被别的插件占用然后再检查Editor → Code Style里的格式化配置是不是被改动了。我印象里换过IdeaVim插件后格式化就会冲突禁用插件或者改掉快捷键就恢复正常了。第二target目录不显示。新建项目后默认确实不显示这在前面提到过。但有一种情况是你明明在磁盘上看到target里有编译好的class文件IDEA项目树里不显示。解决办法是File → Settings → Editor → File Types看看有没有把target目录误认成忽略项或者在Project Structure → Modules里把target目录标记为普通目录刷新一下就好了。第三项目跑不起来但代码看着完全没问题。这种时候我建议先执行一遍mvn clean compile看Maven输出的具体报错。IDEA的缓存有时候会跟实际依赖不同步执行File → Invalidate Caches and Restart清一次缓存能解决大部分莫名其妙的编译问题。我保持一个习惯换分支、拉代码、改完pom.xml后都会先执行一次mvn clean package通过后再用IDEA跑。5.3 如何避免创建一个“跑不起来的项目”我在团队里带过不少新人总结下来“跑不起来”的主要原因就三个版本不匹配、依赖堆积、不看日志。版本不匹配我已经反复强调了Java版本、Spring Boot版本、Maven编译级别必须匹配。依赖堆积就是指看到什么依赖都往上加加了又不用最后版本冲突、自动配置打架项目自然起不来。不看日志则是最要命的很多新人一看到控制台飘红就慌把报错信息略过直接截图问人。我建议训练自己先读第一行报错大多数情况下报错里已经写清楚了原因和解决方法。我这里还有一个非常管用的经验创建一个新Spring项目后第一件事不是写业务代码而是先把项目跑起来一次再往上加东西。如果基础工程都跑不起来后面叠加任何代码都会让你分不清问题出在业务逻辑还是工程配置上。收尾的几句实在话写到这里常见的创建Spring项目方法和问题都聊得差不多了。我个人这几年下来的体会是创建项目这件事熟练以后三分钟内搞定但真正值钱的能力是你不依赖工具也能搭出来理解Spring容器在背后做了什么出了问题能顺着日志和配置找到原因。尤其是初学者我强烈建议你去IDEA社区版里手写一个带Configuration和ComponentScan的纯Spring工程别看它麻烦这一趟走下来你对IoC的理解绝对比直接套Spring Boot模板要扎实得多。最后再分享一个小技巧每次新建Spring项目的时候都把Spring Boot版本和JDK版本固化下来写成一个团队层面的模板或笔记。我自己的标准是新项目一律JDK 17 Spring Boot 3.2.x除非遇到兼容限制否则不降级。这样你在不同项目、不同电脑之间切换的时候踩坑的概率会大大降低也让整个团队的技术栈保持稳定。
返回列表