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

文章详情

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

IDEA 2017版Tomcat部署实战:从Artifact到热调试

IDEA 2017版Tomcat部署实战:从Artifact到热调试 拿2017版的IntelliJ IDEA去配Tomcat很多人第一反应是这还用写但真到自己上手十个有八个卡在不知道从哪一步点起。当时IDEA 2017.3刚发布界面风格和现在的版本差别不算大但和Eclipse完全是两个思路。身边不少朋友从Eclipse转过来第一件事就是把项目import进来然后到处找“Deploy to Tomcat”按钮结果找了一圈什么都没有——其实IDEA压根就不提供这种按钮它的Web项目部署逻辑是先定义Project Structure里的Artifact再在Run/Debug Configuration里挂到Tomcat上。这篇文章就是把这一整条链路从零到一拆开讲适合刚学Java Web、或者从Eclipse迁移到IDEA的同学直接照抄。1. 为什么2017版IDEA配Tomcat总让人抓狂1.1 先搞清楚IDEA和Tomcat到底是怎么配合的要理解配置先得理解角色分工。Tomcat本质上是一个Servlet容器负责监听端口、接收HTTP请求、调用Servlet和JSP然后返回响应。它不关心你的Java代码怎么编译不在乎IDEA里有哪些Module只要最终有一份“可运行的Web应用目录结构”出现在它管理的webapps或者被虚拟映射的路径下它就能跑起来。IDEA负责的则是另一头把你的源码编译成classes把依赖打成lib把静态资源归位最终形成这个标准的目录结构再告诉Tomcat去加载它。这个“最终形成目录结构”的产物就是Artifact。所以配置Tomcat的核心动作可以压缩成三句话在IDEA里登记Tomcat告诉IDEA你要构建一个Web Artifact把这个Artifact挂到Tomcat的运行配置里。后面所有点来点去的菜单都在为这三句话服务。1.2 社区版和Ultimate版在Web开发上的分水岭这里有个新手最容易忽略的前提IDEA社区版虽然是免费的但它没有Java Web开发相关的功能。2017版也一样Application Servers面板、Web Facet、Run Configuration里的Tomcat Server选项全是Ultimate版才有的功能。很多人在社区版里按着教程找Tomcat找半天找不到不是步骤错了而是版本根本不含这套功能。如果手里只有社区版要么换Ultimate版并完成正式授权要么换其他方式比如用Maven的tomcat插件、Jetty插件来跑Web项目。这篇文章默认你用的是Ultimate版下面所有菜单路径也以Windows下的IDEA 2017.3为例。Mac版只是入口从File Settings变成了IntelliJ IDEA Preferences其余完全一致。2. 动手前准备JDK、Tomcat和路径选择2.1 JDK与Tomcat的版本搭配2017版的IDEA最舒服的组合是JDK 8加Tomcat 8.5.x。JDK 8和IDEA 2017、Tomcat 8.5的兼容性都很好不会出现版本识别问题。Tomcat 9当时也算稳定但和2017版IDEA集成时偶尔会有提示警告而且新手更容易把低版本和高版本的概念弄混所以不建议首选用Tomcat 9或更高版本。下载Tomcat时要去Tomcat官网的“Archives”区域拿对应版本Windows下直接下载zip压缩包解压后就是绿色目录。这里有一个我特别想强调的路径问题解压目标目录不要带中文、不要带空格也不要用太深的层级。比如D:\tools\apache-tomcat-8.5.85就比C:\Users\张三\Desktop\新建文件夹\Tomcat 8.5要省心得多。IDEA和Tomcat内部处理路径时对空格和中文的容忍度比Linux差很多别在这种地方浪费半小时。这里还要补一个小小的背景知识Tomcat的类加载架构和普通Java程序不一样它没有完全走双亲委派机制——Web应用自己的classes和lib会被优先加载这样两个项目各自带了不同版本的同名依赖才不会互相污染。这也是为什么Tomcat能在一个实例里跑多个Web应用。2.2 先手工启动Tomcat验证环境拿到Tomcat后别急着进IDEA先手工启动一次。进入Tomcat的bin目录Windows下双击startup.bat或用命令行执行正常的话会弹出一个命令行窗口最后出现“Server startup in [xxx] milliseconds”这样的字样。这时浏览器访问http://localhost:8080能看到Tomcat默认首页说明JDK和Tomcat本身都是好的。这一步的作用是隔离问题域。如果Tomcat手工都起不来大概率是JAVA_HOME没配好或者根本就没装JDK这种问题如果在IDEA里才暴露新手会以为是IDEA配置错了来回折腾浪费很多时间。看完首页后记得运行shutdown.bat把Tomcat关掉避免后面IDEA启动时端口被占。手工能起来再进IDEA就只剩“怎么把项目挂上去”的问题了。3. 在IDEA 2017里添加Tomcat和创建Web项目3.1 在Application Servers里登记Tomcat打开IDEA进入File SettingsMac是IntelliJ IDEA Preferences找到Build, Execution, Deployment Application Servers。在右侧面板点“”号选择Tomcat Server然后在Tomcat Home那一栏填Tomcat解压目录。下方如果看到“Tomcat 8.5.x”被正确识别点OK保存。这一步做完以后IDEA只是在“服务器列表”里认识了Tomcat并不代表项目就能跑。它更像是在系统里先装一个“可用的运行环境”后面创建Run Configuration时可以从下拉框里直接选。如果点时选项是灰的或者没有Tomcat Server选项基本可以断定你用的是社区版回到上一节处理版本问题。3.2 用Maven archetype创建Java Web项目项目怎么建直接决定后面要不要补大量手动配置。我最推荐的方式是直接用Maven骨架建New Project Maven勾选Create from archetype在archetype列表里找到maven-archetype-webapp如果列表里没有点Add Archetype填上GroupId: org.apache.maven.archetypesArtifactId: maven-archetype-webappVersion选一个稳定版即可。骨架建好后IDEA会生成一个标准的Maven Web项目结构src/main/resources、src/main/webapp等。特别要注意这个骨架默认并不会生成src/main/java目录需要你手动在src/main下建立java目录然后在IDEA里右键这个目录Mark Directory As Sources Root。别小看这一步很多同学项目建完发现没地方放Java源代码或者放了Java文件但IDEA不编译都是因为没把目录标记为Source Root。3.3 手动项目的补课添加Web Facet如果你不是用Maven骨架而是从一个普通Java项目“强行”改成Web项目那还需要补一个关键配置添加Web Facet。进入Project Structure快捷键CtrlShiftAltS选择Facets点“”号选Web在弹出框里选对应Module然后指定Deployment Descriptor一般指向src/main/webapp/WEB-INF/web.xml和Web Resource Directory指向src/main/webapp。这一步等于明确告诉IDEA这个Module不是一个普通的Java库而是一个Web应用源码里有web.xml、有静态资源。不添加Web Facet后面创建Artifact时你会发现“Web Application”选项是灰的或者根本找不到因为IDEA根本不知道这个模块具备Web属性。Facet、Artifact、Run Configuration这三件套里Facet是最容易被遗漏的一环。4. 配置Artifacts与Tomcat运行配置核心环节4.1 Artifact先告诉IDEA要部署什么东西现在进入整个流程最关键的部分。Project Structure里切到Artifacts页签点“”号选择Web Application: Exploded再选From Modules把刚才的项目模块加进去。IDEA会自动生成一个名为“项目名_war_exploded”的Artifact输出目录默认在out/artifacts/项目名_war_exploded。这里需要理解为什么选Exploded而不是Archive。Exploded是“解压后的目录”IDEA会把classes、lib、静态资源全部以散装文件形式放到输出目录里修改后可以增量更新非常适合开发调试Archive则是把整个应用打成一个war包再扔给Tomcat每次改动都要重新打包、重新部署效率低很多。做日常开发除非是为了模拟线上环境否则一律选Exploded。创建完Artifact后建议顺手展开它检查一下Available Elements里有没有需要的依赖比如lib下的jar包。有些时候Artifact建完依赖并没有自动带全可以右键通过Put into Output Root把目录加进去。这一细节在多人协作项目里尤其常见。4.2 新建Tomcat Local运行配置Run Edit Configurations点左上角“”号在列表里找到Tomcat Server Local。进入配置页后有两个Tab必须看Server和Deployment。Server页里Application server下拉框选第3节登记好的Tomcat。HTTP port默认8080如果这个端口有其他程序在用可以改成8081、8082等。JMX port默认1099这是IDEA用来和Tomcat进程通信做热部署、Debug的专用端口千万不能和HTTP port搞混。Start Browser那块开发期我建议留空不勾选Open browser否则每次启动都弹出一个浏览器标签页挺烦的。到这里先别急着点Run因为Deployment还没配直接启动会得到一条著名警告No artifacts marked for deployment。别慌回到Deployment页把它加上就好了。4.3 Deployment页把Artifact挂到Tomcat上切到Deployment页签点“”号选Artifact弹出框里选择刚才创建的“项目名_war_exploded”。下方会生成一个Application Context输入框默认是/项目名这决定了浏览器访问时的根路径。如果你想访问http://localhost:8080/就能打开首页就把Application Context改成“/”如果改成/项目名那首页地址就是http://localhost:8080/项目名/。这里要注意一个坑如果改成“/”后面项目里有静态资源或接口路径时所有请求都要从根路径出发不会自动带上项目名。很多同学在部署后访问自己的Servlet发现404十有八九就是Context Path和预期对不上。4.4 热部署与调试配置Deployment配置好之后回到Server页往下看有一组和热部署直接相关的选项On Update Action和On Frame Deactivation。On Update Action指你手动触发热更新时快捷键或用CtrlF10执行什么操作On Frame Deactivation指IDEA窗口失去焦点时执行什么操作。我个人建议On Update Action选Update classes and resourcesOn Frame Deactivation选Do nothing。这样改Java方法体、改JSP、改静态资源后按一下CtrlF10或者切回浏览器改动就生效了不用每次重启Tomcat。但如果你改了方法签名、新增了Servlet映射这类结构级变动还是要Redeploy或重启。把这两个选项理解成“轻量更新”和“重量重新部署”的开关就不会被各种教程弄晕。5. 第一次启动观察日志、调整参数5.1 跑起来要看到哪些日志才算真正成功点右上角的绿色Debug小虫子如果要调试或Run按钮IDEA会启动Tomcat。启动过程不用干等看Console输出就行。正常情况下前面日志会刷出一堆加载上下文、初始化Spring如果有之类的信息最后几行一定有类似这样的关键输出[2024-01-01 12:00:00,123] Artifact 项目名_war_exploded: Artifact is being deployed [2024-01-01 12:00:00,456] Artifact 项目名_war_exploded: Artifact is deployed successfully [2024-01-01 12:00:01,001] Deployment of web application archive 项目名_war_exploded has finished [2024-01-01 12:00:01,002] Starting ProtocolHandler [http-nio-8080] [2024-01-01 12:00:01,003] Server startup in [500] milliseconds看到“Server startup”字样说明Tomcat彻底起来了。浏览器这时如果没自动开就手动输入你配置的地址比如http://localhost:8080/项目名/。能看到页面整个配置链路就全部打通了。如果只看到前一部分、没有“Server startup”说明Web应用部署过程中抛了异常控制台通常会有红字堆栈优先看第一条异常信息。5.2 端口冲突和调试端口问题的处理第一次启动最常见的失败原因是端口被占。报错信息如果包含“Address already in use: JVM_Bind :8080”是HTTP端口被占了如果包含“Error running Tomcat: Unable to open debugger port (localhost:1099)”是JMX调试端口被占了。这两个端口都要检查。Windows下用netstat -ano | findstr 8080Linux和macOS用lsof -i :8080或netstat -an | grep 8080。查到占用PID后要么任务管理器结束掉对应进程要么在IDEA的Run Configuration里换一个端口。我个人的习惯是调试端口直接改成一个少见的高位端口比如58731这样能避免其他开发工具也默认占用1099时反复冲突。改完端口重新启动就没问题了。5.3 启动后的部署检查启动成功后如果页面空白或者看不出效果可以再看两个位置。一是IDEA底部Event Log它会明确记录Artifact是否部署成功二是Tomcat安装目录下的logs子目录里面catalina.yyyy-MM-dd.log会以文件形式保留完整日志很多时候控制台被刷屏看不到关键信息去这里翻反而最快。环境越复杂日志文件的排查价值就越高。6. 常见问题排查速查表6.1 从报错信息反推原因对照表把一段时间里被问得最多、自己踩过的场景整理成一张表遇到问题时照着对一下效率最高报错信息或现象根因解决办法Warning: No artifacts marked for deploymentDeployment页里没挂Artifact按4.3节把Artifact加进来Address already in use: JVM_BindHTTP 8080或JMX 1099端口被占netstat查PID并结束进程或换端口Unable to open debugger portJMX调试端口被占换一个高位端口比如58731首页404控制台却正常启动Application Context路径和访问路径不一致确认Context是/还是/项目名访问时带上浏览器访问不到localhost:8080代理、防火墙或hosts问题关掉代理检查系统防火墙修改Java代码后刷新不生效没有使用Update或RedeployOn Update Action设为Update classes and resources运行按钮是灰色没有可运行的Run Configuration确认已建Tomcat Local配置找不到Tomcat Server选项社区版没有此功能使用Ultimate版Artifact选项是灰色模块没有Web Facet按3.3节添加Web Facet页面提示源码找不到HttpServlet缺少Servlet API依赖Project Structure里给Module添加Tomcat库或servlet-api.jar这张表覆盖了我见过的大多数问题。还有一个冷门但真实存在的情况IDEA运行的是out/artifacts目录而不是Maven的target目录所以不要老盯着target目录看文件有没有更新。6.2 404背后的几个隐藏原因网上关于IDEA配Tomcat的报错问得最多的是“明明启动了页面却404”。除了Application Context没对上之外还有一个常见原因Artifact里没有把编译后的classes输出进去。打开Project Structure里的Artifact检查Output Layout里有没有WEB-INF/classes这个目录如果有还要确认里面有没有对应的class文件。如果没有classes目录就在Output Layout里右键“项目名_war_exploded”选择Create Directory做成WEB-INF/classes再把Module的Compile Output路径指到它上面。这个操作偏底层新手一般不会主动去碰但遇到404时一定要想起来。另外Servlet类记得在web.xml里配映射或者用WebServlet注解项目刚跑起来时是没有路由自动帮你认识你的Java类的。6.3 项目停不掉、端口一直占用的处理技巧不少同学点完停止按钮发现浏览器还能访问localhost:8080或者下一次启动时报端口占用。这是因为IDEA的停止按钮发送的关闭命令没能把Tomcat进程彻底杀干净尤其在高版本JDK下偶尔会出现。遇到这种情况不要反复点启动先找到残余进程并结束掉。Windows下可以打开任务管理器找到Java进程看命令行参数里有没有catalina字样这就是Tomcat残留。另一种更稳的办法是在Run配置的Server页里把右侧那个红色停止按钮对应的Shutdown connection参数改成Socket并把Shutdown port设为8005。IDEA停止时会先连这个端口发SHUTDOWN命令比直接kill进程温柔得多也能避免端口迟迟不释放。7. 一些让Tomcat跑得更顺手的配置习惯7.1 开发期我习惯这样配置整套流程跑通之后有几个小习惯让我后来少踩很多坑。Run配置里我会把HTTP port固定成8080但不勾选Open browser手动开浏览器按F12看Network这样方便看清资源请求路径。JMX debug port固定成一个生僻端口避免和其他本地服务撞车。项目根路径尽量用/少用带项目名的Context Path因为HTTP接口一旦设计成/开头联调时不带项目名更省事。还有一点比较容易被忽略2017版IDEA对Tomcat的识别本质上是靠读取Tomcat的lib目录里的版本文件来完成的所以别随便删Tomcat目录里的文件。也不要图省事直接把war包塞进Tomcat的webapps目录然后再用IDEA启动它——那样会让IDEA和Tomcat的部署方式互相干扰报错反而更难排查。IDEA负责部署Tomcat就负责运行边界划清楚。7.2 和Maven插件方式的取舍如果你之后想更进一步可以把项目里的Tomcat依赖交给Maven管理用tomcat7-maven-plugin或tomcat9-maven-plugin在命令行里跑。这种方式的优点是可以脱离IDE完成部署CI里方便缺点也很明显Debug单步调试要额外配置JFork热部署能力又弱一些JSP修改经常要手工重启。所以日常开发里我至今仍然优先用IDEA集成的Run Configuration至少在2017版IDEA下它是最直接、最不容易出错的选择。用熟以后整个过程加起来的点击量不到二十次性价比非常高。
返回列表