写点什么

玩转 IDEA 项目结构 Project Structure,打 Jar 包、模块 / 依赖管理全搞定

用户头像
YourBatman
关注
发布于: 2021 年 02 月 02 日
玩转IDEA项目结构Project Structure,打Jar包、模块/依赖管理全搞定

你好,我是 A 哥(YourBatman)。


如何给 Module 模块单独增加依赖?

如何知道哪些 Module 模块用了 Spring 框架,哪些是 web 工程?

IDEA 如何打 Jar 包?打 War 包?


熟练的正确使用 IntelliJ IDEA,是一个“高手”该有的样子,因为那是你的门面上篇文章 重点介绍了 IDEA 里最为重要的两个概念:Project 项目和 Module 模块。相信你看完后再也不会把 IDEA 的 Project 比作 Eclipse 的 Workspace,并且对 IDEA 有了一份更深的了解。


本文继续理解 IDEA 对项目、模块的管理。管理项目是一个 IDE 的基本功能,但往往最基础的是最重要的更是最容易被忽略的。因此本文是你更好去理解 IDEA 管理 maven 结构、gradle 结构、Spring Boot 项目结构的基础,万丈高楼平地起,它就是这个地基。上层结构再怎么繁繁多变,殊途同归最终都由 Project Structure 来体现,从而给开发者以几近相同的编码体验。



本文提纲



版本约定

  • IntelliJ IDEA:2020.3.1


正文

Project Structure 是一个你开发过程中偶尔/经常会打开,但却很少用心留意的窗口。不同于一般设置窗口,它和项目的紧密度非常的高且有一定理解难度,若设置不当项目可能无法运行甚至无法编码(比如编译报错、jar 包找不着等),为此我做件一般人都不愿意做的事,对它进行详解,相信做难事必有所得。


本文基于上文已搭建好的 hello 项目案例,继续研究其项目结构 Project Structure 的管理。从结构查看,到修改定制,那么问题来了,如何打开一个 Project 项目的结构页呢?


如何打开 Project Structure?

看似一个简单的操作,里面其实蕴藏着你对 IDEA Project 和 Module 的理解,否则势必不知从哪下手。据了解,也许你是多年的程序员,也未必知道从哪下手。


按照一般思维,会鼠标选中 hello,然后右键:


但对不起,右键菜单里并无Project Structure选项。Project Structure 顾名思义,是针对 Project 维度的结构视窗,而你鼠标选中的 hello 只是个 module,所以自然弹出的是对此 module 的操作菜单喽,而非 Project 的。也许你可能会讲:我点击了Open Module Settings也打开了 Project Structure 视窗呀,是的效果上你可能是打开了但道理并非如此,而仅仅是因为把它俩放在了一起(同一视窗)而已。

说明:理解 IDEA 的 Project 和 Module 两大概念,是对 IDEA 进行一切操作的基础。前文已非常详细(可能是全网最全)的介绍了它俩,可花几分钟前往学习。点这里电梯直达


三种打开方式

要打开一个 Project 的结构展示窗口,至少有如下三种办法,本文都例举给你。

  1. 顶部菜单File -> Project Structure


  1. 点击右上角的快捷按钮


  1. 快捷键方式(推荐)


这是我本人最喜欢的方式,至于快捷键是哪个就看你是如何设定的喽,我的快捷键是 ctrl + shift + alt + s。

啰嗦一句:建议你操作 IDEA 多用快捷键,那会大大提高编码的效率,并且看起来像高手。基本上记住50个左右快捷键就够用了,长期以往成了肌肉记忆后这就是你的核心竞争力之一了




打开 hello 项目的结构页如下图所示:



解释:为何不需要鼠标选中项目?

对于这个动作,敏感的你是否有发现:打开项目结构并不需要鼠标选中任何东西(快捷键随意使用),也就是说鼠标失焦状态都没问题,何解呢?


回答这个问题并不难,前提是你已经对 IDEA 的 Project 概念烂熟于胸。一个 Project 对应一个视窗,它们是严格 1:1 的关系。换句话讲,当前视窗就代表着 Project,因此操作本视窗顶部菜单栏就肯定是作用在该 Project 上,又何须专门选中什么呢?再者,Project 只是个逻辑概念,你想选都没得选中的,所以把视窗当作它就好。有没有觉得,这和 Java 中的this关键字调用特别像?


最后,这个问题的答案是:只要鼠标还在 IDEA 视窗内(该视窗是活跃窗口),那么对 Project 就永远就是“选中”状态。


Project Structure 项目结构剖析

项目结构视窗已打开,那接下来重点来喽。可以看到它左边的“菜单栏”,共分为三个 part:

  • Project Settings:项目设置(最重要),本文详解

  • Platform Settings:平台设置,也叫全局设置。用于管理 SDK 们(如 JDK、Kotlin 的 SDK 等)、全局库。

- 一般来讲,全局的 JDK 都会配置在此处,比如我因为经常要做多版本尝试,就管理了多个 JDK 版本


  • Problems:问题。一般项目出现了问题都会在此体现(如依赖不一致问题等等),总之问题数量一致让它是 0 是最优的


其中 Project Settings 里面的每个标签页是最常用,最关心的。下面就对它的每个 tab 页作出解释和使用说明。

Project 页情况



此视窗可以看到 Project 本身的基础信息。如:名称、SDK 版本、语言等级等等,比较简单。


对于此页面的元素,多啰嗦几句:

  1. 为何是 SDK 版本而不是 JDK 版本?答:因为 IntelliJ IDEA 是 JVM 平台 IDEA,不仅仅支持 Java 还有其它语言如 Kotlin,所以写成 SDK 更抽象

  2. 为何指定了 SDK 还要指定语言等级?答:因为 SDK 版本并不直接决定语言等级。如你用的 JDK 11,但依旧可以把语言等级调为 8 来进行编译/运行

1. 这是集成开发环境的优势所在,轻松对多环境进行定制化支持

  1. SDK 和语言等级 Project 都可指定,作为全局默认

1. 这些配置 Module 默认集成,但可自行修改自己的。比如 module 1 使用 Java 5 编译,module 2 使用 Java 11 编译,这是允许的


Module 页情况

Module 页可谓是重点中的重点,甚至是最重要。毕竟 Module 作为实际存在形式,所有的源代码、配置、依赖等都在这里,因此大有可学呀。



值得注意:Tests 测试包里面的是可以访问 Sources 源码的,但反过来不行。




每个模块都能独立管理着自己的依赖,这种关系在模块自己的.iml 文件中记录着。


知识点:

  1. Project 创建时默认会创建一个同名的 Module 模块

  2. Module 默认沿用 Project 的 SDK、语言等级等设置,当然也可自己指定

  3. 每个 Module 可自行管理依赖,可以是二方库、三方库......

  4. 本模块的依赖情况默认存储在项目的{moduleName}.iml文件里


新增依赖

既然 Module 可以自行管理依赖,那么如何给该模块新增依赖呢?


举个例子,现在需要向 hello 模块增加一个commons-io jar 包依赖,可以点击 Dependencies 标签页左下角的+号,选择 Library:



然后选择,如果没有就选择New Libarary...创建一个呗(有就直接用就成):



下面分别演示选择 Java 和选择 From Maven 两种不同库的方式:


新建 Java 依赖库

New Library 新建菜单选项中选择Java选项:




这种方式简单的讲:从你本机里选择一个 jar(或者一个目录里面包含 jar、文档)就成。优点是非常轻便,不依赖网络,缺点是这些 jar 必须是你本机已实际存在的。


新建 Maven 依赖库

New Library 新建菜单选项中选择From Maven选项:



输入 GAV(或者关键字查找)就能定位到 jar,此种方式使用起来其实非常方便,毕竟 maven 非常好用嘛。缺点自然就是一般情况下需要都需要依赖于网络喽,除非你本地仓库已存在对应的 jar。




通过这两种方式各执行一次添加新的依赖完成后,再看 hello 模块的依赖情况,效果如图:



既然依赖变化了,自然而然的也会体现在 hello.iml 文件里喽,来看看:



依赖添加进来,源代码里就可以正常使用啦:



依赖作用范围

在 New Library 创建依赖的时候,不管用哪种方式选中后,它都会弹出这个窗口让你选择此依赖的作用范围



  • Module Library:模块级别,只能本模块使用,别的模块看都看不见

  • Project Library(默认选中):项目级别,该项目下所有的模块均能看见和选中使用

  • Global Library:全局级别,任何项目均可看见和使用


在本例中 commons-io 是模块级别,commons-lang3 是项目级别。因此 hello-client 模块添加依赖时也是能够看到 commons-lang3 这个依赖的(但看不见 commons-io):



Libraries 页情况



当某 Library 是所有/大部分模块都需要的依赖时,就可以上升为 Project 级别的依赖,抽取到 Libraries 标签页来统一管理。如图,因为上面步骤创建的 commons-lang3 是项目级别的,所以也会出现在这里。


至于如何创建/添加 Project 级别的依赖,这里就不用再赘述了吧,上面【新增依赖】章节已讲得很明白。唯一区别在该页面选好后不用再选择 Library 的作用范围了(因为就是 Project 级别的嘛),取而代之的是让你选择作用的模块:



当然喽,你也可以一个都不选(点击 cancle),那么该 jar 只是被创建了,而不作用于任何 module 模块。

说明:对于一个多模块的 Project 来讲,建议项目使用的所有 Jar 都放在这里统一管理,模块要使用时直接按需 choose 就成,而不需要自己再单独 add,方便统一管理


Facets 页情况



Facets 可理解为用于配置 Project 项目的框架区,它能看到项目的每个 Module 模块使用的框架、语言等情况,并且还可以对它们进行配置。


比如 Spring 框架,如果某个模块使用了它就可以来这里统一配置。优点是你会发现借助 IDEA 强大的功能它都给你想好了哪些地方可配置,你可以更改,让你实现配置界面化。除了 Spring,其它框架如 Hibernate 也是如此~


目前支持的 Facets(语言/框架)类型有:



模块对应的 Facets IDEA 会自动 Detection 探测,若没有你也可以手动添加。


为了更形象的描述此 tab 页的作用,这里搬一个我自己生产项目来看看实际效果:




说明:不同的 Facet 对应的最右端窗口内容配置项是不一样的。


通过此视窗,可以看到你当前 Project 项目,哪些模块使用了 Spring 框架,哪些是 web 项目,一目了然。它有个非常大的作用就是站在 Project 的视角对每个模块进行整体把控,比如若你发现有个模块不需要是 web 项目(并不需要对外提供服务接口),那铁定就是多引包了或者职责不清晰导致的,就可立马针对性解决,消除隐患。


在实际工作中我自己比较频繁的使用这个功能,用于对模块性质的定位,比如如果是普通模块,绝对不允许是 web 工程,如果不需要依赖 Spring 绝对不允许成为 Spring 工程。因为严格控制 Jar 包依赖、工程性质是应对大型项目的有效手段。


当然喽,Facets 还有个作用是让 IDEA 编译器认识你的模块,比如如果你是个 web 模块,若没有在 Facets 里体现出来,那 IDEA 就不认识你,就无法给你提供 web 的一些便捷操作了。


Artifacts 页情况

IDEA 如何打 Jar 包?如何打 War 包? 来,上菜~



在 Maven 大行其道的今天,虽然用 IDEA 打包很少使用了,但是有些时候它对你本地调试还是蛮有用的,并且对理解 maven 的打包依旧有效,来,了解一下。


Artifacts 这个概念不是特别好理解,artifact 是 maven 里的一个概念,被 IDEA 借鉴过来。表示某个模块要何种打包形式,如 jar、war exploded、war、ear 等等。Artifact 是一个项目资源的组合体,整合编译后的 java 文件,资源文件等。有不同的整合方式,比如 jar、war、war exploded 等等,对于一个 module 而言,有了 Artifact 就可以部署了,类似于 maven 的 package 打包。

说明:war 和 war exploded 区别就是后者不压缩,开发时选后者便于实时看到修改文件后的效果


来个栗子,这里演示下将 hello 模块打包成一个 Jar:




配置好后,只需顶部菜单栏 Build -> Build Artifacts,就可以打出这个 Jar 包:




执行完此命令后,在Output Directory里就能看到 hello.jar 这个打包好的文件啦。然后java -jar .\hello.jar就能运行喽(因为咱们打的是可执行 Jar 包)。关于使用 IDEA 打包还包括打可执行 jar 包、Fatjar、包外引用 jar 包等等,这里就不展开了,后面会放在单独文章里把各种方式汇总在一起聊聊。


总的来说,无论配置 Facets 还是 Artifacts,都是 Intellij IDEA 要求我们来做的(虽然有些可自动识别),目的是以便其能识别这些文件并整合各插件实现功能(如自动化配置、自动打包),一切为了编码体验和编码效率。


模块如何依赖其它 Module

一个中大型项目一般有多个模块,它们各司其职。模块与模块之间一般都存在依赖关系,比如常见的 xxx-core 模块一般会被其它几乎所有模块所依赖。模块依赖外部库 Library 知道怎么搞了,那么如何增加本项目的模块依赖呢?


其实道理和步骤基本一样,比如 hello-core 模块里有个 Person 类:



hello-service 模块也需要用到 Person 类及其功能,那么就需要把 hello-core 模块依赖进来,操作步骤如下:


添加 Dependency 依赖时,请选择Module Dependency...选项:



选择本项目中需要依赖进来的模块:



选中 hello-core 模块把它依赖到 hello-service 里来:



点击 ok,搞定了。对应的,此依赖关系也会体现在 hello-service.iml 这个配置文件上:



如此,我们就可以在 hello-service 模块里正常使用 Person 类啦:

public static void main(String[] args) {    System.out.println(new Person());}
复制代码

完美。


总结

本文对 IntelliJ IDEA 的项目结构 Project Structure 的每个 tab 页进行了全面分析,据我短浅的目光所及,可能是全网独一份写这个内容的。很多同学觉得 IntelliJ IDEA 不需要专门的学习分析,会用它导入 maven 项目,跑跑 main 函数启动下 Spring Boot 就成啦,我却不以为然。


衡量一个新手和一个高手的差异不是顺风顺水时,而是遇到问题时谁能够快速解决,谁又只能望洋兴叹,相信薪资的差异也体现在此。我见过的“高手”对自己最常用的工具用得都是很 666 的,这不正是技术范该有的样子麽?说到底,我们不可能认为用一指禅敲代码的人会是大牛嘛~


好啦,关于 IDEA 的话题暂且先聊到这。其实我想到的主题还有好几个,如:

  • IDEA 如何主动去识别导入不能被自动识别的 Maven 项目?原理是什么呢?

  • IDEA 如何打可执行 Jar 包?又如何打 FatJar?如何打 包外 Jar 包(散包) 呢?

  • IDEA 如何巧用其最新的 Http Client 脚本能力,结合对 Controller 的嗅探快速完成本地测试?

  • ......


有你 pick 的吗?欢迎留言告诉我,需求多就尽快上号,不然这个专题就暂时告一段落啦,把时间继续花在其它专题上啦。

本文思考题

本文所属专栏:IDEA,后台回复专栏名即可获取全部内容。本文已被https://www.yourbatman.cn收录。


看完了不一定懂,看懂了不一定会。来,文末 3 个思考题帮你复盘:

  1. Module 模块如何单独设置 JDK 版本?

  2. IDEA 如何打 jar 包?

  3. 开个脑洞:Maven 用 pom 管理项目结构,IDEA 是如何识别它的呢?


推荐阅读



System.out.println("点个赞吧!");print_r('关注【BAT的乌托邦】!');var_dump('私聊A哥:fsx1056342982');console.log("点个赞吧!");NSLog(@"关注【BAT的乌托邦】!");print("私聊A哥:fsx1056342982");echo("点个赞吧!");cout << "关注【BAT的乌托邦】!" << endl;printf("私聊A哥:fsx1056342982");Console.WriteLine("点个赞吧!");fmt.Println("关注【BAT的乌托邦】!");Response.Write("私聊A哥:fsx1056342982");alert("点个赞吧!");
复制代码

A哥(YourBatman):Spring Framework 开源贡献者,Java 架构师,领域专家。文章不标题党,不哗众取宠,每篇文章都成系列去系统的攻破一个知识点,每个系列可能是全网最佳/唯一。注重基本功修养,底层基础决定上层建筑。现有 IDEA 系列、Spring N 多系列、Bean Validation 系列、日期时间系列......关注免费获取


发布于: 2021 年 02 月 02 日阅读数: 69
用户头像

YourBatman

关注

分享、成长,拒绝浅尝辄止。 2018.01.21 加入

分享、成长,拒绝浅尝辄止。公众号:BAT的乌托邦

评论

发布
暂无评论
玩转IDEA项目结构Project Structure,打Jar包、模块/依赖管理全搞定