理解classpath
2021/9/26 23:15:21
本文主要是介绍理解classpath,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、什么是classpath
classpath,翻译过来就是类路径的意思,它是包含class文件的路径集合,用于指示虚拟机jvm在这些路径下搜索class文件。 类路径可以同时定义多个,多个类路径之间需要使用分隔符进行分隔,windows环境下使用“;”,linux环境下则使用“:”。下面我们对类路径进行一个简单的分类,如下所示:
类路径的类型 | 描述 |
"." | 表示当前目录,即执行java命令启动应用的目录。如果我们不显式的设置任何类路径,则默认它包含一个多当前目录;但如果显式设置了类路径,并且设置的路径不包含当前目录的话,则类路径就不包含当前目录了 |
扩展目录 | (1)扩展目录可以是包含class文件的基目录,比如“/home/user/classdir”,该目录作为类路径,其下的内容就开始是包路径目录。![]() |
jar文件 | 比如“/home/user/lib/Foo.jar”,该jar文件的完整路径也能作为类路径。当然,从javaSE6开始,可以通过通配符“*”一次指定多个jar,例如“/home/user/lib/*” |
运行时库文件,rt.jar,jre/lib,jre/lib/ext | 这些不用手动指定,它们默认包含在类路径中 |
二、如何设置classpath
启动应用时,设置classpath非常简单:
1 #方式1 2 java -classpath 具体的类路径 3 #-classpath也可以简写成-cp 4 java -cp 具体的类路径 5 #示例 6 java -classpath .:/home/user/classdir:/home/user/lib/* 7 8 #方式2(不推荐使用),使用CLASSPATH环境变量,JVM启动时会去查找CLASSPATH这个环境变量 9 export CLASSPATH=".:/home/user/classdir:/home/user/lib/*"
需要注意的是,某些情况下不需要我们设置classpath,比如在tomcat或者jetty中启动应用,亦或者是通过springboot可执行jar启动应用时,我们都未设置classpath,但这并不代表不用设置,而是框架或者容器替我们做好了这个事。
三、"classpath:"与"classpath*:"
这是一个扩展话题,我们在spring下常常能看到使用"classpath:"或者"classpath*:"去指定一个资源文件的路径,这两个路径前缀是啥意思呢? 其实"classpath:"或者"classpath*:"都不是java语言自带的东西,它只是spring自定义的一种路径格式前缀而已,意思是以classpath作为根目录的指定位置。举个例子,若应用启动时指定了classpath为"/home/user/classdir",那么对于以"classpath:"开头的路径"classpath:resources/myfile.xml",spring就会在"/home/user/classdir/"下去查找相对路径为myfile.xml的文件,也就是查找绝对路径为"/home/user/classdir/myfile.xml"的文件。 需要说明的是,"classpath:/"与"classpath:"对于spring来说是没有区别的,spring框架在处理这个路径的时候,会将开头的"/"符号去掉,这点对于"classpath*:"也是一样,具体可以查看PathMatchingResourcePatternResolver的getResources方法源码。 最后,我们需要搞清楚"classpath:"与"classpath*:"的区别,两者之间相差一个"*"号,但在查找方式上具有很大的差异,这一点网上大部分博客都是你抄我或者我抄你,要么就没说清楚,要么就直接有错误。
3.1.不包含通配符的路径
所谓不包含通配符的路径,指的是"classpath:"以及"classpath*:"后面资源文件的路径(含文件名)不包含通配符"*、?"等,因为spring在进一步处理路径时,首先会判断路径是否包含通配符,有和没有通配符的处理方式是完全不同的,这也是我们分开讨论的原因。查找规则 | 进一步说明 | |
classpath: | (1)既可以查找类路径中扩展目录下的资源,也可以查找类路径中jar包内的资源。 (2)查找顺序是按照类路径定义的顺序逐个查找扩展目录或jar包(并不是网上说的先去查找扩展目录再查找jar包),并返回查找到的第一个资源。 |
(1)返回的Resource都是ClasspathResource。 (2)如果资源位于扩展目录中,从ClasspathResource中获取到的是BufferedInputStream;如果位于jar包中,获取到的则是JarURLInputStream。 |
classpath*: | (1)既可以查找类路径中扩展目录下的资源,也可以查找类路径中jar包内的资源。 (2)返回查找到的所有的匹配文件资源,因此可以不考虑查找顺序。 |
(1)返回的Resource都是URLResource。 (2)如果资源位于扩展目录中,从URLResource获取到的是BufferedInputStream;如果位于jar包中,获取到的则是JarURLInputStream。 |
3.2.包含通配符的路径
包含通配符的路径指的是"classpath:"以及"classpath*:"后面资源文件的路径(含文件名)包含通配符"*、?"等。这种情况比较复杂,对于classpath尤其如此。因为spring在查找包含通配符的路径时,首先会从路径中提取出一个不包含通配符的“根目录”,它是“从根路径开始的、一个没有通配符的最长路径”。例如,"classpath: static/image/**/icon.png"的根目录为"static/image",而"classpath: **/image/first/icon.png"的根目录为""(后面我们称为空目录),另外"classpath: i*on.png"的根目录也是""。 可以看到,包含通配符的路径,其提取出的根目录有两种情况,一种是空目录,一种是包含了有效路径的目录,"classpath:"在这两种不同的根目录下查找行为有所区别,而"classpath*:"保持了一致,下面用一张表格归纳了它们的查找规则:根目录类型 | 查找规则 | 进一步说明 | |
classpath: | 空目录,即"" | (1)只在类路径中的扩展目录下查找资源,无法在类路径中的jar内查找。 (2)查找过程比较复杂:假设定义了3个类路径,分别是扩展目录"dir1"和"dir2",以及通配符jar包"dir3/*",它们的顺序可以是任意的,如"dir1:dir2:dir3/*"或者"dir3/*:dir2:dir1"。step1.首先过滤掉类路径中的jar包,剩下的扩展目录保持定义顺序不变;step2.按照类路径定义的顺序逐个查找扩展目录,如果在某个扩展目录下查找到匹配的资源文件,则将查找范围锁定在该扩展目录下,并返回该扩展目录下所有匹配的资源文件。 |
(1)返回的Resource都是FileSystemResource,从中获取FileInputStream。 (2)实际上,之所以无法去jar包中查找,是因为ClassLoader的getResources方法在传入""时,只能返回扩展目录资源。 |
包含了有效路径的目录 | (1)既可以查找类路径中扩展目录下的资源,也可以查找类路径中jar包内的资源。 (2)查找过程比较复杂:假设定义了3个类路径,分别是扩展目录"dir1"和"dir2",以及通配符jar包"dir3/*",它们的顺序可以是任意的,如"dir1:dir2:dir3/*"或者"dir3/*:dir2:dir1"。step1.直接按照类路径定义的顺序逐个查找扩展目录或jar包,如果查找到包含“根目录”的某个类路径,则将查找范围锁定在此类路径下,并返回此类路径下所有匹配的资源文件,如果没有匹配的就返回空。 |
(1)如果资源位于扩展目录中,返回的Resource是FileSystemResource,从中获取到FileInputStream。 (2)如果资源位于jar包中,返回的Resource是ClasspathResource,从中获取到JarURLInputStream。 |
|
classpath*: | 空目录,即"" | (1)既可以查找类路径中扩展目录下的资源,也可以查找类路径中jar包内的资源。 (2)返回查找到的所有的匹配文件资源,因此可以不考虑查找顺序。 |
(1)如果资源位于扩展目录中,返回的Resource是FileSystemResource,从中获取到FileInputStream。 (2)如果资源位于jar包中,返回的Resource是URLResource,从中获取到JarURLInputStream。 |
包含了有效路径的目录 |
3.3.总结查找规则
现在对上面分情况讨论的查找规则进行一个总结,方便我们记忆和使用- "classpath*:":总是能在类路径的扩展目录和jar包中查找,并且返回所有的匹配资源。
- "classpath:"(不含通配符):总是能按照类路径定义的顺序逐个查找扩展目录或jar包,并返回第一个匹配的资源。
- "classpath:"(含通配符):首先判断根目录是否为"",来决定查找的类路径范围是否需要过滤掉jar包。在处理后的类路径中按照定义的顺序逐一查找,直到查找出第一个匹配的资源文件,同时锁定该资源文件所在的类路径。之后查找并返回该锁定的类路径中所有匹配的资源文件。
四、框架和容器中的classpath
4.1.web容器的classpath
传统项目的部署方式是我们将应用打成war包,部署在tomcat或者jetty这样的web容器中,然后启动web容器,其classpath不需要我们手动设置,web容器在启动时会帮我们设置好,并且约定俗称的将“/path/to/WEB-INF/classes”与“/path/to/WEB-INF/lib”这两个目录设置成classpath,这也与war包的目录结构保持一致:- WEB-INF/classes:存放src目录java文件编译之后的class文件、xml、properties等资源配置文件。
- WEB-INF/lib:存放依赖库。
4.2.springboot的classpath
在springboot项目中,我们启动可执行jar时一般不指定classpath,那么springboot的classpath如何指定的呢?我们先来看一个典型的springboot项目打包结构:![](/upload/202109/26/202109262315201992.png)
在META-INF中存在清单文件MANIFEST.MF,打开该文件查看里面的内容,我们找到main-class属性指定的并非是我们编写的应用启动类ServiceFeignApplication,而是org.springframework.boot.loader.JarLauncher。
![](/upload/202109/26/202109262315202939.png)
![](/upload/202109/26/202109262315204819.png)
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
![](/upload/202109/26/202109262315205776.png)
4.3.自定义打包的classpath
之前做过一个项目,使用maven-assembly插件对springboot web项目进行定制打zip包,由于客户规定了打包目录结构,因此无法使用springboot默认的打包结构,包结构如下:![](/upload/202109/26/202109262315206713.png)
这篇关于理解classpath的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-29易优CMS安装常见问题汇总-icode9专业技术文章分享
- 2024-06-28易优新手必读安装教程-icode9专业技术文章分享
- 2024-06-28忘记eyoucms后台密码怎么办?-icode9专业技术文章分享
- 2024-06-26终极指南:Scrum中如何设置需求优先级
- 2024-06-26AI大模型企业应用实战(25)-为Langchain Agent添加记忆功能
- 2024-06-26小白家庭 nas 搭建方案-icode9专业技术文章分享
- 2024-06-23AI大模型企业应用实战(14)-langchain的Embedding
- 2024-06-23AI大模型企业应用实战(15)-langchain核心组件
- 2024-06-23AI大模型企业应用实战(16)-langchain核心组件
- 2024-06-23AI 大模型企业应用实战(06)-初识LangChain