一、什么是classpath


  classpath,翻译过来就是类路径的意思,它是包含class文件的路径集合,用于指示虚拟机jvm在这些路径下搜索class文件。
  类路径可以同时定义多个,多个类路径之间需要使用分隔符进行分隔,windows环境下使用“;”,linux环境下则使用“:”。下面我们对类路径进行一个简单的分类,如下所示:
类路径的类型 描述
"." 表示当前目录,即执行java命令启动应用的目录。如果我们不显式的设置任何类路径,则默认它包含一个多当前目录;但如果显式设置了类路径,并且设置的路径不包含当前目录的话,则类路径就不包含当前目录了
扩展目录 (1)扩展目录可以是包含class文件的基目录,比如“/home/user/classdir”,该目录作为类路径,其下的内容就开始是包路径目录。

(2)扩展目录也可以是一些其他的文件目录,不过jvm并不能从中找到class文件,该目录用于存放一些文件以供查找使用。
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项目打包结构:

  在META-INF中存在清单文件MANIFEST.MF,打开该文件查看里面的内容,我们找到main-class属性指定的并非是我们编写的应用启动类ServiceFeignApplication,而是org.springframework.boot.loader.JarLauncher。

  在可执行jar包对应的目录中找到这个类,进行反编译。通过反编译代码我们大概可以推断出JarLauncher这个类添加了两个新的classpath,即“path/to/BOOT-INF/classes”与“/path/to/BOOT-INF/lib”,这两个目录类似于传统war包中的“WEB-INF/classes”与“WEB-INF/lib”。
  我们的研究当然不止于此,继续深入的看一下springboot中的另外一个类“WebMVCAutoConfiguration”,其中的方法addResourcesHandlers调用了ResourcesProperties类的getLocations方法,在该方法中,我们发现了springboot定义了4个查找静态资源或者配置文件的默认路径,它们分别是:
  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/
  如果将classpath代入,便可知静态资源实际在jar中的查找位置了,这与springboot将静态资源“resources/static”目录的打包位置一致,下图为jar包中“BOOT-INF/classes”目录下的内容:

4.3.自定义打包的classpath

  之前做过一个项目,使用maven-assembly插件对springboot web项目进行定制打zip包,由于客户规定了打包目录结构,因此无法使用springboot默认的打包结构,包结构如下:
  为了使得springboot能够正确查找到静态页面文件,选择的解决方式是,在启动脚本文件中,将“/path/to/WEB-INF”添加到classpath中,这样就满足了“classpath:/static/”的查找路径,同时为了保证conf与lib目录也能被查找,也将“/path/to/WEB-INF/conf”与“/path/to/WEB-INF/lib”添加到classpath中。    

理解classpath的更多相关文章

  1. JAVA classpath jar问题[zz]

    classpath问题可以说是所有初学者头疼的问题,偶也一样. 1) classpath的作用:  它的作用就事让java找到你所要执行,或你拥有的类. 2) classpath的设置:  设置cla ...

  2. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  3. java与java学习路线

    JAVA学习路线图 Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征.Java语言作为静态面 ...

  4. 20155321 2016-2017-2 《Java程序设计》第一周学习总结

    学习目标 [√]了解Java基础知识 [√]了解JVM.JRE与JDK,并下载.安装.测试JDK [√]了解PATH.CLASSPATH.SOURCEPATH的作用并会设置 [√]初步使用IDE(推荐 ...

  5. 20155337祁家伟 2016-2017-2 《Java程序设计》第2周学习总结

    20155337 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 这周我学习了从JDK到IDE的学习内容,简单来说分为以下几个部分 使用命令行和IDE两种方式 ...

  6. 手动编译java的package问题,及演示继承的基本实现

    不用IDE,而直接用命令编译JAVA包,仔细看了下,作一个记录. 以下的URL值得收藏. http://www.aiuxian.com/article/p-2115485.html http://ww ...

  7. 一文彻底搞懂Java中的环境变量

    一文搞懂Java环境变量 记得刚接触Java,第一件事就是配环境变量,作为一个初学者,只知道环境变量怎样配,在加上各种IDE使我们能方便的开发,而忽略了其本质的东西,只知其然不知其所以然,随着不断的深 ...

  8. 理解根目录,classpath, getClass().getResourceAsStream和getClass().getClassLoader().getResourceAsStream的区别

    一: 理解根目录 <value>classpath*:/application.properties</value> <value>classpath:/appli ...

  9. path、classpath理解

    path.classpath最常见的场景:环境变量配置 path环境变量:设置path的作用是让操作系统可以找到JDK命令(指定了JDK命令搜索路径):path环境变量原来Windows里面就有,只需 ...

随机推荐

  1. 题解 d

    传送门 写出来\(n^2\)就有81pts-- \(n^2\)的话枚举最后成为限制的是哪两个矩形,利用前缀和和二分\(n^3\)化\(n^2\)就行了 这题最无脑直接贪心的方法会有后效性 但实际上正解 ...

  2. 题解 w

    传送门 一直觉得有点后效性什么的,也不知道怎么写 这题什么时候再康一遍,第一次见这个样子的树形DP,是个树上带不定权边的DP(??? 这里能树形DP的原因好像是在这里所有子节点的状态都能表示出来 还有 ...

  3. msp432搭建平衡小车(二)

    前言 上一节掌握了使用pwm驱动电机,接下来介绍如何使用msp432读取mpu6050数据 正文 首先我们得知道mpu6050通信方式,由于mpu6050只能用i2c通信,所以学会使用msp432的i ...

  4. 黑马JVM教程——自学笔记(二)

    三.垃圾回收 3.1.如何判断对象可以回收 3.1.1 引用计数法 弊端:循环引用时,两个对象的计数都为1,导致两个对象都无法被释放 3.1.2 可达性分析算法 JVM中的垃圾回收器通过可达性分析来探 ...

  5. Spring-JDBC表情符号不能存入数据库

    ALTER TABLE TABLE_NAME CONVERT TO CHARACTER SET utf8mb4; JDBC解决方案: //params List<Object> param ...

  6. 高德Web开发入门之一

    高德Web开发 一.地图开发阐述 1)不管是高德地图的Web开发使用,亦或是百度地图的应用开发,都可以直接百度"高德地图/百度地图",进入地图首页下边"开放平台" ...

  7. SpringBoot获取所有接口的路由

    @Autowired WebApplicationContext applicationContext; @RequestMapping(value = "v1/getAllUrl" ...

  8. HCNP Routing&Switching之OSPF虚连接

    前文我们了解了OSPF的网络类型.帧中继交换机映射以及路由器帧中继映射相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15195762.html:今天我 ...

  9. 利用AOP切面打印项目中每个接口的运行情况

    1.前言 AOP切面技术,大家应该都听知道,Spring框架的主要功能之一. AOP切面的用途很广,其中一个常见的用途就是打印接口方法的运行日志和运行时间. 日志对于一个项目很是重要,不仅有助于调错, ...

  10. 新东方APP技术架构演进, 分布式系统架构经验分享

    今天的演讲题目是"新东方APP技术架构演进, C端技术经验分享" 作者:张建鑫, 曾任IBM高级软件架构师, 滴滴高级技术专家, 现任新东方集团高级技术总监 古代东西方的思想家都产 ...