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

文章详情

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

Eclipse中搭建Spring框架全流程:从环境配置到IoC与DI实战

Eclipse中搭建Spring框架全流程:从环境配置到IoC与DI实战 刚入行那阵子我花了不少时间折腾Spring。那时候网上资料远不如现在丰富大部分教程都是基于IDEA的用Eclipse的教程要么太老要么讲得云里雾里。做Java开发这些年从SSH到SSM再到Spring BootSpring这个框架始终是绕不开的核心。如果你还在用Eclipse或者公司项目强制要求Eclipse这篇文章就是为你准备的——我会带你从零开始在Eclipse里装好Spring、跑通第一个程序顺便把IoC、DI这些核心概念讲清楚最后再附上我这些年积累的排错经验帮你少走弯路。很多新手包括当年的我最容易犯的错误是一上来就直奔框架的高级特性结果连环境都没搭明白。Spring说到底是一个轻量级的容器框架它的核心思想就两个控制反转IoC和面向切面编程AOP。在Eclipse里把Spring跑起来其实只需要三个东西JDK环境、Eclipse IDE、Spring相关的jar包。但恰恰是这三个东西的版本搭配就能劝退一大批人。这篇文章适合Eclipse使用者、Spring初学者也适合那些想在Eclipse里快速搭建Spring项目但总被各种报错卡住的人。看完你会对整个流程有个清晰的认知每一步怎么做、为什么这么做我都会掰开揉碎讲清楚。1. 准备工作工具链的选择比想象中重要1.1 JDK、Eclipse和Spring的版本怎么搭先说JDK。这里我强烈建议新项目直接用JDK 8或者JDK 11不要一上来就追最新的JDK 17甚至更高。原因很简单Spring Framework 5.x对JDK 8的支持非常成熟稳定你在网上搜到的大部分教程、遇到的报错解决方案基本都基于这个组合。如果你用的是Spring 6.x那需要JDK 17以上但Spring 6带来的变化对新手来说意义不大反而会增加配置难度。Eclipse版本方面建议选择Eclipse IDE for Enterprise Java and Web Developers也就是我们常说的Java EE版本。这个版本内置了Web开发相关的插件后面如果你要从Spring Core升级到Spring MVC会省掉很多麻烦。Eclipse 2020-06到2022-09之间的版本我都用过说实话差别不大选一个你顺手的即可。但有一点要特别注意Eclipse和JDK的位数必须一致都是64位或者都是32位否则可能出现一些莫名其妙的问题。Spring的版本选择有一个小经验不要使用最新的release版本尤其是刚发布的那种。Spring Framework的版本迭代非常稳定没必要追求新5.2.x或者5.3.x系列都很好用网上资料也最多。记得有一次我手贱用了当时刚出的5.3.0结果一个和CGLIB相关的兼容性问题折腾了整整一个下午最后老老实实退回5.2.9世界安静了。1.2 提前装好Maven省掉手动找jar包的麻烦以前我们学Spring的时候第一步是上官网下载jar包然后用Eclipse手动Add External Jars一个个往上加。现在有Maven或Gradle这个好用的工具千万别再手动管理jar包了。Maven能自动帮你下载Spring及所有依赖的jar包什么spring-core、spring-beans、spring-context、spring-aop它全都会处理好。如果你之前没装过Maven可以去Apache官网下载一个解压版然后配一下环境变量新建MAVEN_HOME指向Maven目录再把%MAVEN_HOME%\bin加到Path里。配好后在命令行敲一下mvn -v能正常输出版本号就算成功了。Eclipse里集成Maven很简单Eclipse较新版本已经内置了Maven插件m2e不需要额外安装。我们只需要在Eclipse里关联好自己下载的Maven打开Window - Preferences - Maven - Installation点Add指定你下载的Maven目录即可。再设置一下Settings指向你本地Maven的settings.xml。这里有个国内开发者的痛点Maven默认从中央仓库下载jar包速度像老牛拉破车。强烈建议修改settings.xml添加阿里云镜像这是开发中正常的加速手段和网络代理完全是两码事。配置大致长这样mirror idaliyunmaven/id mirrorOfcentral/mirrorOf nameAliyun Maven Mirror/name urlhttps://maven.aliyun.com/repository/central/url /mirror配置好之后下载速度会有质的飞跃。这一步是很多新手容易忽略的等真正开始建项目时才意识到jar包下载慢到让人怀疑人生。2. Eclipse里搭建第一个Spring项目2.1 新建项目选择正确的工程类型打开EclipseFile - New - Maven Project在弹窗里勾选Create a simple project跳过骨架选择然后填上Group Id一般用公司域名倒写比如com.example和Artifact Id项目名比如spring-demoPackage那栏填成com.example.demo。到这里一个干净的Maven项目就建好了目录结构里有src/main/java、src/main/resources和pom.xml。这一步很容易踩一个坑默认的Maven项目没有src/main/resources这个目录。你需要在项目上右键 - New - Source Folder手动创建一个路径填src/main/resources。很多教程会默认你有这个目录结果你照着教程写代码发现ClassPathXmlApplicationContext一直报找不到配置文件原因就是配置文件没放在资源目录下。pom.xml是整个项目的核心Spring的相关依赖都写在这。我们先加最基础的两个dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.2.9.RELEASE/version /dependency只需要加spring-context这一个就够了因为它会把spring-core、spring-beans、spring-aop这些核心依赖一起拉下来。这是Maven的好处不用你手动去算哪个依赖依赖哪个。2.2 引入Spring依赖三种方式的取舍在Eclipse里给Spring项目添加依赖大致有三种方式我三种都试过体验差别非常大。第一种就是上面说的Maven依赖管理这是最推荐的方式。你的pom.xml里写了什么依赖Maven会帮你下载好Eclipse的Maven插件会自动把jar包加到项目的ClassPath里。这种方式的好处是依赖版本清晰、传递依赖自动处理、项目换电脑重建时不需要保存一堆jar包。第二种是手动下载jar包然后Build Path。这种方式特别坑因为Spring各个模块之间还有依赖关系你少一个jar包它就可能报某个ClassNotFound你能做的只能是一个个试。更麻烦的是Spring还依赖commons-logging、CGLIB等第三方库少了任何一个都会出问题。除非你的网络环境实在下载不了Maven依赖否则我不建议你这么做。第三种方式是用Eclipse里的Spring Tools插件STS来快速创建项目它会自动帮你生成Spring项目骨架和一些配置模板。但我不太推荐新手在第一步就使用STS因为插件会隐藏太多细节导致你可能根本看不懂项目是怎么跑起来的。就像学开车手动挡可能会熄火但你能理解离合原理自动挡虽然省事但出了问题你完全不知道从哪儿排查。2.3 第一个Spring应用从配置文件到运行依赖配好了接下来就是写一个能运行的Demo。步骤非常简单但有三个环节缺一不可。第一步创建一个普通的Java类就叫UserService吧里面写一个简单方法package com.example.demo; public class UserService { public void sayHello() { System.out.println(Hello, Spring!); } }这个类没有任何Spring的痕迹就是一个普通的POJO。这也是Spring的一个优点非侵入式设计你的业务类不需要继承任何父类或者实现任何特定接口。第二步在src/main/resources下创建一个Spring的配置文件一般命名为applicationContext.xml?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd bean iduserService classcom.example.demo.UserService / /beans这个配置的意思很直白告诉Spring容器帮我创建一个UserService的实例并给它起个名字叫userService。Spring读取到这个配置后会自动去实例化这个对象把它放进容器里。第三步写一个带main方法的测试类来运行package com.example.demo; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringDemo { public static void main(String[] args) { ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml); UserService userService (UserService) context.getBean(userService); userService.sayHello(); } }右键 - Run As - Java Application控制台如果输出Hello, Spring!说明你的Spring环境已经成功跑起来了。听上去很简单对不对但就是这么简单的流程当年我身边还是有好几个同事卡在配置文件上不是namespace没写全就是找不到XML文件的路径问题。所以这个Demo虽然基础却能帮你验证整个工具链是否通畅。3. 搞清楚Spring在背后做了什么3.1 IoC容器对象不再由你new刚才的Demo能够运行你可能觉得平平无奇不就new了一个对象吗但实际上userService这个对象并不是我们主动new出来的而是Spring通过读取applicationContext.xml后帮我们创建出来的这就是控制反转IoC最直观的体现。传统开发模式下对象之间的依赖关系是由代码自己维护的A要使用B就在A里new一个B出来。这会导致什么后果如果B的构造函数变了或者B需要依赖C那所有new了B的地方都要改代码耦合度极高。而IoC的思想是把对象的创建和管理交给容器谁需要什么就向容器要容器负责把该对象需要的依赖也一并注入进去。ApplicationContext就是容器的核心接口。在Eclipse里编写时你会发现applicationContext.xml被加载之后我们其实有多种获取Bean的方式按id获取、按类型获取、按id类型获取。在实际开发中推荐按类型获取这样连强转都省了UserService userService context.getBean(UserService.class);当然前提是这个类型在容器中只注册了一个实例否则Spring会直接抛出NoUniqueBeanDefinitionException告诉你这个类型的Bean有歧义这就是检查依赖是否重复定义的很好的机会。3.2 依赖注入的两种落地方式IoC解决了对象创建的问题依赖注入DI则解决对象之间怎么协作的问题。最常见的两种方式是构造函数注入和setter注入。我写个示例说明public class OrderService { private UserService userService; // 构造函数注入 public OrderService(UserService userService) { this.userService userService; } }对应XML配置bean idorderService classcom.example.demo.OrderService constructor-arg refuserService / /bean也可以改成setter注入public class OrderService { private UserService userService; public void setUserService(UserService userService) { this.userService userService; } }对应XML配置bean idorderService classcom.example.demo.OrderService property nameuserService refuserService / /bean你可能会问这两种注入方式到底有什么区别在早期Spring版本中setter注入是主流因为灵活但在现在的Spring 4.x、5.x中官方更推荐构造函数注入因为这种方式能保证依赖的完整性——对象一旦创建成功它的依赖就已经就绪不会出现某个依赖还没set就半初始化的情况。而且构造函数注入对不可变对象支持更好也更方便做单元测试。我自己的习惯是核心依赖必须存在用构造函数注入可选依赖可能有默认值用setter注入。时间久了你会发现这个习惯能帮你在代码review里省掉不少麻烦。3.3 Bean的生命周期与scope选择不管是XML配置还是注解配置每个Bean在容器中都有明确的生命周期实例化、属性填充、初始化、使用、销毁。Spring允许你在初始化和销毁时挂上自定义逻辑XML里可以配置init-method和destroy-method注解方式可以用PostConstruct和PreDestroy。关于Bean的作用域scope这是新手特别容易搞混的概念。Eclipse下右键查看spring的xsd你就明白了Spring中Bean默认是singleton单例的也就是整个容器中只有一份实例所有地方拿到的是同一个对象。另外一种常见的是prototype原型每次getBean都会创建一个新实例。怎么选择呢拿我实际开发中的例子来说无状态的Service、DAO层全部用singleton就够了因为Spring容器自己会处理线程安全问题。但如果你有一个类内部维护了状态比如计数器、临时缓存那还当单例用就可能出问题这时候就应该考虑prototype或者干脆你换个思路不要在单例Bean里维护会变化的状态。bean iduserService classcom.example.demo.UserService scopesingleton / bean idtaskService classcom.example.demo.TaskService scopeprototype /搞清楚lifecycle和scope之后你对Spring的掌控才算是真正上了一层楼。4. 从Spring Core走向Spring MVC4.1 引入spring-webmvc需要什么跑通Core只是第一步开发Web应用时你真正天天打交道的其实是Spring MVC。在Eclipse里从Core往MVC过渡其实就是一句话的事在pom.xml里再加一个依赖。dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.2.9.RELEASE/version /dependency这个依赖会把你Web开发所需的大部分Spring模块都引进来。然后再加一个Servlet API这里要注意一定要用provided scope因为Tomcat里已经自带Servlet容器了你再加一遍会导致jar包冲突dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency如果你想在Eclipse里直接运行Web项目还需要把项目转成Dynamic Web Project。具体操作是右键项目 - Properties - Project Facets勾选Dynamic Web Module并设置好WebContent目录。这一步在Maven项目中会自动生成src/main/webapp你的JSP、HTML就放在这里。4.2 配置DispatcherServlet和注解驱动Spring MVC是基于前端控制器模式设计的所有请求先到达DispatcherServlet再由它分发到具体的Controller。说句大白话DispatcherServlet是整个Web应用的入口和交通警察。它的配置在web.xml中servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcher/servlet-name url-pattern//url-pattern /servlet-mapping这里有个细节load-on-startup必须设为1否则容器启动时不会初始化DispatcherServlet你可能等请求访问了才去加载到时候各种奇怪问题都来了。我在调试老项目的过程中发现这个坑真是经典值得记下来。然后在spring-mvc.xml里开启注解驱动和组件扫描context:component-scan base-packagecom.example.demo.controller / mvc:annotation-driven /有了这两行配置你就可以直接用Controller和RequestMapping写接口了Controller public class HelloController { RequestMapping(/hello) ResponseBody public String hello() { return Hello Spring MVC; } }在Eclipse里配置好Tomcat服务器Run on Server浏览器访问http://localhost:8080/项目名/hello看到Hello Spring MVC出现在页面上的那一刻你基本已经摸到Spring Web开发的门儿了。5. 常见问题与排查技巧实录5.1 问题速查表我在写Spring项目的过程中被各种报错折磨的次数太多了。这里把出现频率高的几个都拉出来方便你直接对号入座。报错信息常见原因排查思路ClassNotFoundException: org.springframework.context.ApplicationContext缺少spring-context依赖检查Maven的pom.xml是否配置正确右键Maven - Update Project刷新依赖ClassNotFoundError: org.apache.catalina.startup.BootstrapTomcat类找不到检查项目是否配置了Server Runtime右键Properties - Targetted Runtimes勾选TomcatNoSuchBeanDefinitionExceptionBean没有注册或者id写错检查XML中bean定义是否存在用Autowired时检查类是否被扫描到NoUniqueBeanDefinitionException同一类型有多个Bean加上Qualifier指定具体bean名称或xml中使用primary属性BeanCreationExceptionBean创建失败属性注入不了看Caused by的详细堆栈重点排查构造函数参数有没有匹配的Bean配置文件找不到XML路径写错ClassPathXmlApplicationContext用的是classpath相对路径别把src/main/java下的文件路径当classpath中文乱码编码不一致统一Eclipse的Workspace编码为UTF-8XML文件头部也要声明UTF-8这张表是我精简后保留下来的实际上还有很多细碎的问题。遇到任何报错记住一条万能法则先看最底下那个Caused by前面的信息往往都是包装过的最底下的才是真正的原因。Eclipse的控制台不会说谎只是你需要习惯它的表达方式。5.2 我踩过的那些坑和排查思路第一个坑Eclipse里明明Maven依赖都引入了代码里却不报错但不显示Spring的Maven Dependencies库。这种情况通常是你只写了pom.xml但没触发Eclipse的Maven插件去解析它。解决办法右键项目 - Maven - Update Project弹窗里勾选Force Update of Snapshots/Releases点OKEclipse就会强制刷新依赖。第二个坑ClassPathXmlApplicationContext在启动时一直提示找不到applicationContext.xml。原因多半是你把XML放错目录了。在Maven项目中配置文件必须放在src/main/resources下不能放src/main/java下。前者会编译到classpath根路径后者是Java源码目录编译器不会把它当资源文件拷贝过去。第三个坑Spring和CGLIB版本不匹配。这种报错在你的代码反复检查都正确时会让人特别抓狂。我的经验是如果你用了XML配置的aop:aspectj-autoproxy或者手动写了CGLIB代理相关代码需要确认spring核心依赖里引入的cglib版本本身没问题不要自己去手动添加cglib依赖让Maven管理传递依赖反而更可靠。第四个坑是Tomcat启动时报端口被占用。这个和Spring本身关系不大但很常见。在Eclipse里改一下Server配置即可双击Servers视图里的Tomcat实例在Ports那一栏把8080改成8081。如果还不行Windows下可以打开任务管理器把占用端口的java进程结束掉再试。第五个坑很隐蔽Eclipse的小版本、插件版本和Spring的jar包版本三者对不上。比如你的Eclipse是2019版本的用了较新的插件解析不了Spring 5.3中某些新引入的XML schema定义启动时报sax解析错误。这种问题基本只能靠回退版本解决要么升级Eclipse要么退回Spring旧版本。我的建议是保持Spring版本相对稳定不要频繁跟着升级稳定性大于新鲜感。6. 一些用得上的开发习惯与建议6.1 Eclipse里调试Spring项目的实用技巧写Spring代码离不开调试而Eclipse的调试功能其实相当强大。我常用的方式是打断点然后以Debug模式启动。在Eclipse的Debug视图中你可以看到当前调用栈、所有变量的值甚至可以直接选中一个表达式右键-Inspect快速查看表达式的值。调试Spring项目还有一个窍门在Eclipse的Preferences里搜索Java - Debug勾选Show Variable Details的选项可以让调试器展示变量内部详细结构。当你调试IoC容器初始化的代码时能看到Spring创建的Bean对象以及它们之间的引用关系那种豁然开朗的感觉比看十遍文档都管用。另外强烈建议设置Eclipse自动编译并且在Project - Build Automatically上打勾。Spring项目很吃编译路径漏编译会导致代码明明改了却不生效。如果是Web项目更新了代码右键Tomcat - Clean再把项目同步到Server能有效避免某些旧代码残留的问题。6.2 XML配置和注解配置怎么取舍虽然Spring现在推荐全注解但在Eclipse维护老项目时你大概率还是要读懂XML。我个人的建议是小项目、临时Demo用注解以速度和直观为主大型项目、团队协作建议XML与注解混用核心数据源、事务管理用XML统一管理、不易分散业务Bean用注解开发快、代码简洁。举个实际的例子数据源的配置如果写在XML里运维或其他人接手时能快速看到数据源连接信息不用一个类一个类翻。而Controller、Service这类业务组件写注解既效率高又方便类内部逻辑的阅读。两者结合才能算真正的生产级实践。如果你正在做的项目还是全XML也别急着推翻重来老项目稳定性永远是第一位的。还要聊一下scope的选择。在Eclipse的Spring视角下你可以用Spring的Bean Graph工具直观地看到所有Bean之间的依赖关系如果发现Bean比较多可以按模块分组来管理。这在排查循环依赖的时候很有用一眼就能看出A引用B、B又引用了A这种问题。Spring三级缓存能解决大部分循环依赖问题但那是框架层面的兜底业务层面尽量别自己制造循环依赖这是设计问题不是框架问题。这个标题虽然只是个起点但它确实是每个Java工程师都会经历的一步。现在回过头看Eclipse搭配Spring的环境搭建过程算不上复杂无非是版本匹配、依赖管理、配置文件三件事。但只要这三件事有一条线没理清就会卡住你很久。我也一直在用Eclipse做一些小工具和原型验证快速跑通想法的效率确实高。Spring作为一个优秀且庞大的生态它的价值远不是IoC容器这么简单但每一个框架都是从第一个Hello Spring开始的。你在Eclipse里踩过的每一个坑都会变成你理解Spring深度的垫脚石。
返回列表