Java – 透过maven理解servlet程序

本文的目的是基于Idea IDE,利用maven创建webapp,自己实现一个简单的servlet,将其运行到tomcat中。

希望透过这个过程可以理解一些关键内容:

  • maven的基本目录规范
  • maven编译源码的原理
  • maven对webapp的目录规范
  • maven生成war包的原理

学习前提是你懂classpath,如果不懂翻一下我之前的一篇博客。

配置阿里云的maven源

idea如何配置阿里云的maven源头自己了解一下即可,否则maven用起来会很慢。

创建maven项目

选择archtype是webapp,这样maven会初始化一个目录结构,符合maven制作web应用的目录规范。

所谓规范,就是我们把代码和前端资源放到指定路径,maven就帮我们打包war。

让maven自动导入pom.xml中配置的包。

webapp目录结构

maven会递归扫描src/main下面的java代码。

对于webapp来说,会规范放置一个webapp目录,里面规范有一个WEB-INF目录存放servlet配置,稍后会讲。除此之外,webapp目录下可以放置要打包发布的前端资源,这里我没用到。

pom.xml在项目根目录,用于配置maven项目。

引入依赖

为了开发servlet提供HTTP接口服务,需要引入包依赖。

maven会识别到新依赖,并下载。

创建source root

为了项目结构好看一点,我们创建一个和webapp平行的java目录作为source root,简单的说就是作为classpath,在其下面创建的类使用相对路径作为package名字。

java目录显示蓝色是因为我右键mark as source root,这个信息仅仅对IDE和开发者有用(相当于告知IDE classpath),对maven没有用(稍后解释),仅仅是帮助IDE正确进行package和classname的索引用的。

开发servlet

没啥好说的,servlet就是java web开发的规范,1个servlet相当于实现一个接口。

大家可以类比python中的wsgi规范,我觉得套路都是一码事。

配置web.xml

web.xml相当于配置路由,这个文件也是java servlet规范的一部分,稍后我们用tomcat去加载这个webapp的时候web.xml就是要被tomcat读取的。

首先要配置有哪些servlet类,因为我们把ServletDemo类放在source root下面,也就是没有包名(也叫默认包,或者说直接放在了classpath目录内),所以servlet-class就是ServletDemo,没有包名前缀即可加载到该类。

servlet-mapping配置/hello的URI请求交给ServletDemo处理,仅此而已。

maven编译项目

通过maven package命令可以编译项目。

maven扫描src/main目录下所有.class文件,根据其.class文件中的package名,将其编译后的.class放置到了target/classes中。

另外还有一个servlet-demo目录(这是我的项目名),里面拷贝过来了WEB-INF目录(包括里面的web.xml),但是额外的还把classes目录也拷贝了进来,以及我们透过maven安装的servlet-api依赖jar包也拷贝了进来。

这个servlet-demo目录可不得了,它包含了要启动这个webapp所有的东西,包括项目class、依赖class、web.xml,其实这个目录压缩一下就是servlet-demo.war包的由来了。

war包是一个可以直接部署到tomcat的完整应用环境,我猜测war包内的结构都是遵循servlet规范的固定摆放方式,这样tomcat会将war内的classes和lib下的jar包都作为classpath,并且根据web.xml的路由加载对应的servlet class(透过Class.forName()方法)处理HTTP请求。

pom.xml的打包类型

对于webapp来说,打包的是包含了class、web.xml、前端资源的一个war包,所以我们看pom.xml中packaging是war而不是jar。

下载tomcat

各位去官方下载tomcat后,解压到磁盘上某个地方就行。

配置tomcat

点击edit,找到tomcat server -> local,然后点上方的+号。

配置一下tomcat的路径:

把tomcat的目录配置进来,idea就识别了。

把war包指定为要部署的东西,并且把该应用的URL根路径设置为/。

运行tomcat

现在点运行,idea会帮我们先maven package,再把编译出来的war包丢到tomcat下拉起。

访问http://localhost:8080/hello,可以看到我们实现的servlet的应答:

我还没仔细研究代码自动热加载,目前我是通过这个按钮重新触发代码编译和tomcat重新部署的:

关于源码目录

在前面的部分我说过,source root仅仅是给IDE还有开发者看的,这是啥意思?

JAVA都是基于classpath定义packge路径的,package名是相对于classpath的,并且对应相同的目录结构,这里source root就是告诉IDE我把这个目录作为classpath。

但是maven并不知道这个事情,maven是扫描src/main下面所有.java文件,根据.java中的package名反推出classpath是哪一层目录,怎么证明这个事情呢?

ServletDemo类直接放在source root下,本应该属于默认包,不能写包名。

我强行给它写了一个package noexist,IDE自然会给出错误提示,因为noexist包应该对应java/noexist目录才对。

但是这并不影响这个类的编译,并且javac会将该类编译放到target/classes/noexist/目录下:

这足以证明,source root只是给IDE和人看的,maven根本无从知晓这个信息,它只是根据package去推断classpath是哪个目录。

当然,实际我们不需要考虑这么复杂。我们要做的就是在src/main下,随便找一个目录(无论多深)作为source root,然后编写的类都相对于source root指定package名就行,大家理解上述解释就不会觉得这是什么奇怪的事情,太平常了。

最后

掌握classpath和maven的原理非常重要,其实学什么语言都差不多,先明白类是如何查找的,再明白如何使用包管理工具,也就有了继续深入学习开发框架的基础。

上述demo的地址:https://github.com/owenliang/servlet-demo

如果文章帮助了你,请帮我点击1次谷歌广告,或者微信赞助1元钱,感谢!

知识星球有更多干货内容,对我认可欢迎加入:

发表评论

电子邮件地址不会被公开。