一 JAVA_HOME、path、classPath的区别
CLASSPATH是Java中最重要的概念之一,但通常都被忽视了。不清楚classpath就不会知道java如何定位你的类文件。
1、JAVA_HOME指的是你JDK安装的位置,一般默认安装在C盘,如
C:\Program Files\Java\jdk1.8.0_91
2、path
PATH=%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;%PATH%;
- 设置path的作用是让操作系统可以找到JDK命令(指定了JDK命令搜索路径);path环境变量原来Windows里面就有,只需修改一下,使他指向JDK的bin目录,这样在控制台下面编译、执行程序时就可以直接使用java、javac命令了;
- 将程序路径包含在PATH当中后,在命令行窗口就可以直接键入它的名字了,而不再需要键入它的全路径,如果我们用到的javac和java两个命令。
3、classPath
CLASSPATH=.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
- 告诉类装载器到哪里去寻找第三方提供的类和用户定义的类。JVM和其他JDK工具通过依次搜索平台库,扩展库,和类路径来查找类。最通俗可以这样理解:path是操作系统用 ,classpath是java编译器用。
- 一看就是指向jar包路径。需要注意的是前面的.;,.代表当前目录。
- classpath它是javac编译器的一个环境变量。它的作用与import、package关键字有关。当你写下improt java.util.*时,编译器面对import关键字时,就知道你要引入java.util这个package中的类---就是类的路径所在,你要的类到哪里找。
4、环境变量的设置与查看
echo %JAVA_HOME%echo %PATH%
echo %CLASSPATH%
5、参考文献:
(1)百度知道 关于java_home,classpath,path和javac的问题 https://zhidao.baidu.com/question/497329193350662564.html
(2)csdn 一看你就懂,超详细java中的ClassLoader详解 https://blog.youkuaiyun.com/briblue/article/details/54973413
(3)博客园 path、classpath理解 https://www.cnblogs.com/huahua035/p/6598863.html
(4)技术之家 你理解java中classpath到底是什么,怎么理解 http://www.jszja.com/contents/14/705.html
(5)csdn 关于JAVA项目中CLASSPATH路径详解 https://blog.youkuaiyun.com/qq_16605855/article/details/72909785
(6)csdn Java入门实例classpath及package详解 https://blog.youkuaiyun.com/martin_liang/article/details/7626571
(7)csdn Java中的classpath https://blog.youkuaiyun.com/weixin_34138377/article/details/89995627
(8)博客园 范仁义 Java中classpath配置 https://www.cnblogs.com/Renyi-Fan/p/6876446.html
二 JVM类加载机制

注意点:用eclipse的打包工具将ClassLoaderTest输出成jre/lib/ext目录下的lqqheima.jar包,再在eclipse中运行这个类,运行结果显示为ExtClassLoader。此时的环境状态时classpath目录有ClassLoaderTest.class,ext/lqqheima.jar包中也有ClassLoaderTest.class,这个时候我们就需要了解类加载的具体过程和原理了。以上情况验证的结果是打印出显示加载ClassLoaderTest.class的加载器是ExtClassLoader,而不再是之前的AppClassLoader加载器了。

JVM中包括集中类加载器:
1 BootStrapClassLoader 引导类加载器。其实类加载器也是类,也需要加载,这些BootStrapClassLoader以外的类加载器,就是由BootStrapClassLoader加类。
2 ExtClassLoader 扩展类加载器
3 AppClassLoader 应用类加载器
4 CustomClassLoader 用户自定义类加载器
他们的区别上面也都有说明。需要注意的是,不同的类加载器加载的类是不同的,因此如果用户加载器1加载的某个类,其他用户并不能够使用。
当JVM运行过程中,用户需要加载某些类时,会按照下面的步骤(父类委托机制):
1 用户自己的类加载器,把加载请求传给父加载器,父加载器再传给其父加载器,一直到加载器树的顶层。
2 最顶层的类加载器首先针对其特定的位置加载,如果加载不到就转交给子类。
3 如果一直到底层的类加载都没有加载到,那么就会抛出异常ClassNotFoundException。
因此,按照这个过程可以想到,如果同样在CLASSPATH指定的目录中和自己工作目录中存放相同的class,会优先加载CLASSPATH目录中的文件。
三 Tomcat 如何实现自己独特的类加载机制?
所以,Tomcat 是怎么实现的呢?牛逼的Tomcat团队已经设计好了。我们看看他们的设计图:

我们看到,前面3个类加载(Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader)和默认的一致。不一样的是,Tomcat自己定义多个类加载器,它们分别是:CommonClassLoader、CatalinaClassLoader、SharedClassLoader、WebApp ClassLoader、JasperLoader。其中:
- CommonClassLoader加载:%TOMCAT_HOME%/common/*中的Java类库;Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
- CatalinaClassLoader加载:%TOMCAT_HOME%/server/*中的Java类库;Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
- SharedClassLoader加载:%TOMCAT_HOME%/shared/*中的Java类库;各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
- WebApp ClassLoaderl加载:%TOMCAT_HOME%/WebApp/AppName/WEB-INF/*中的Java类库;各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;
其中WebApp类加载器和Jsp类加载器通常会存在多个实例,每一个Web应用程序对应一个WebApp类加载器,每一个JSP文件对应一个Jsp类加载器。
从图中的委派关系中可以看出:
- CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用;
- 而CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离;
- WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离;
- 而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能;
注意:在tomcat 6之后,common、server、shared,这3个目录已经合并到根目录(TOMCAT_HOME)下的lib目录下

好了,至此,我们已经知道了tomcat为什么要这么设计,以及是如何设计的,
问题1:那么,tomcat 违背了java 推荐的双亲委派模型了吗?答案是:违背了。 我们前面说过:双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。双亲委派机制如下图所示:

问题2:我们扩展出一个问题:如果tomcat 的 Common ClassLoader 想加载 WebApp ClassLoader 中的类,该怎么办?看了前面的关于破坏双亲委派模型的内容,我们心里有数了,我们可以使用线程上下文类加载器实现,使用线程上下文加载器,可以让父类加载器请求子类加载器去完成类加载的动作。牛逼吧。
四 参考文献
1、博客园 图解Tomcat类加载机制(阿里面试题) https://www.cnblogs.com/aspirant/p/8991830.html
2、博客园 【JVM】浅谈双亲委派和破坏双亲委派 https://www.cnblogs.com/joemsu/p/9310226.html
3、通俗易懂理解JAVA虚拟机(一)——类加载详解 https://www.it610.com/article/1288470555321769984.htm
4、博客园 JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架 https://www.cnblogs.com/heartstage/p/3390447.html
csdn Java类加载器深入讲解--张孝祥老师 https://blog.youkuaiyun.com/lushuner/article/details/41014191
csdn 黑马程序员_张孝祥_Java基础加强_类加载器 https://blog.youkuaiyun.com/longlangss/article/details/9930135
五 类加载器应用案例1:Tomcat类加载器调用顺序研究
网上很多资料(包括官方文档)都说有common、system这些类加载器。但是我调试源码的时候并没有看到这些类加载器。 tomcat version:8.5.42。
本文研究两个问题:
1、JAVA_HOME/lib/ext和/WebApp/WEB-INF/lib中有相同全限定类名时,加载谁的类。答:前者
2、加载类的过程中classloader的大致调用过程。WebappClassLoaderBase(tomcat的)->ExtClassLoader->BootStrapClassLoader
————————————————
参考文献:csdn Tomcat类加载器调用顺序研究 https://blog.youkuaiyun.com/m1f2c3/article/details/112424408
六 类加载器应用案例2:Tomcat的类加载顺序的实现
其实之所以为写这篇文章的原因,主要是前段时间,因为使用第三方的一些库,需要将这些库放到JDK的ext目录,由Java的ExtClassLoader进行加载,第三方库也是用了日志框架,而且使用的是slf4j,所以要使用这个第三方库,必须将slf4j-api.jar这个slf4j的接口包放到ext目录下。将这个日志放到slf4j-api.jar放到ext目录下,接着应用层的日志打印不出来,应用层的日志包也是使用slf4j,应用是在Tomcat中跑的。
————————————————
参考文献:csdn Tomcat的类加载顺序的实现 https://blog.youkuaiyun.com/strive_or_die/article/details/100850378
七 附1:apache-tomcat-5.5.17目录结构示意图


1272

被折叠的 条评论
为什么被折叠?



