Skip to main content

Java ClassLoader 学习反馈

Classloader是Java运行时核心机制之一,它解决了我们的.class文件如何被jvm加载的问题。也就是我们的写的源码.java文件被编译成.class字节码后,如何被jvm加载解释。
Java在广义上有三种classloader
  1. BootstrapClassLoader 是JVM级别的classloader,使用c/c++来写的。详细解释如何来加载一个bootstrap级别的class文件,哪些class文件是bootstrapclassloader来加载的。
  2. ExtClassLoader  是ExtensionClassLoader,他是AppClassLoader的 ‘父类’,这个父类不是指AppClassLoader extends ExtClassLoader,而是指ExtClassLoader来创建了AppClassloader,后面源码部分可以解释这个关系。
  3. AppClassLoader 这是一般我们自己写的class的classloader,他加载了我们自己写的class,而且同时如果我们有自定义的classloader,那么他也是custom class loader的parent class loader.
他们的加载顺序也是从上往下,即 1->2 ->3。
  到这里可能会产生疑问,他们加载的class有何不同? 
AppClassLoader是上面说的,他会加载我们自己定义的class,即我们workspace的classpath下的class
ExtClassLoader则是加载我们Jdk lib/ext 下的class
BootstrapClassLoader是加载rt.jar、resources.jar、charsets.jar和class等。 

那么他们是如何找到lib下这些class文件呢? 答案是通过环境变量中的一些变量,而这些变量的定义也是通过我们设置的JAVA HOME等来取得。
源码中有这么两个地方解释了这个地方。
==》 private static String bootClassPath = System.getProperty("sun.boot.class.path");
==》 String s = System.getProperty("java.ext.dirs");

蓝色部分的是定义了BootstrapClassLoader如何找到他需要的那些class所在的目录。
红色部分则是定义了ExtClassLoader如何找到他需要的class

挑选第一个,我们起一个main函数来做一个测试。
System.out.println(System.getProperty("sun.boot.class.path"));
==>>>
C:\Program Files\Java\jdk1.8.0\jre\lib\resources.jar;
C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar;
C:\Program Files\Java\jdk1.8.0\jre\lib\sunrsasign.jar;
C:\Program Files\Java\jdk1.8.0\jre\lib\jsse.jar;
C:\Program Files\Java\jdk1.8.0\jre\lib\jce.jar;
C:\Program Files\Java\jdk1.8.0\jre\lib\charsets.jar;
C:\Program Files\Java\jdk1.8.0\jre\lib\jfr.jar;
C:\Program Files\Java\jdk1.8.0\jre\classes
  这就是classloader如何加载class的方式。

  • 找到一个指定的路径
  • 加载路径下指定的class文件





Comments

Popular posts from this blog

Elasticsearch error when the field exceed limit 32kb

When we post data that the field exceed the limit, elasticsearch will reject the data which error: {"error":{"root_cause":[{"type":"remote_transport_exception","reason":"[cs19-2][10.200.20.39:9301][indices:data/write/index]"}],"type":"illegal_argument_exception","reason":"Document contains at least one immense term in field=\"field1\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped.  Please correct the analyzer to not produce such terms.  The prefix of the first immense term is You can handle this: 1. you can udpate the mapping part at any time PUT INDEXNAME/_mapping/TYPENAME { "properties" : { "logInfo" : { "type" : "string" , "analyzer" : "keyword" , "ignore_above" : 32766 } } } ignore_above means that we will only keep 32766 bytes 2

学习服务器配置之路~~

第一个常见的小问题:MySQL安装 os : fedora 20 mysql: mysql-server(5.5) 所有假设你的系统是没有经过特殊配置的。 1: yum install mysql-server 2: mysql 报错:socket连接不上 3: service mysqld start   注意这步是 mysqld 不是mysql 这样就解决。网上的方法好像有点麻烦。 第二个小问题:解压一些文件(.tar.gz)时报错 http://itsfoss.com/how-solve-stdin-gzip-format/ 上面介绍的很清楚,总之要先确认你下载的文件类型。 第三个小问题。配置tomcat服务器 主要问题是比如我的域名是 cqupt.me 而你tomcat服务器的项目在/webapps/{your projectname} 这时你很蛋疼的要 cqupt.me:8080/{your projectname}/index.html。 如果要cqupt.me就可以完成。这样配置: 都是在tomcat下/conf/server.xml 第一步端口。简单 不废话 第二部。 <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> </Host> 在标签中间插入: <Context path=""  docBase="xbwl"  debug="0" reloadable="true"/> docBase="xbwl" xbwl 即为指定的项目。即({your projectname}_ 完整如下: <Host name="localhost" appBase="webapps"

并发读写外部依赖

在我们以task为粒度的分布式系统中,需要对数据做checkpoint,以保证task在重启的时候内存中未被消费完的数据可以保存到文件系统中以防止丢失。 在第一个版本中,我们的task默认使用了task的名字作为任务的ID,同时在做checkpoint时使用diskQueue也是使用相同的方式来生成。直到我们碰到一个需要更新task配置的需求后产生了问题。 为了解决任务更新的问题,我们task的做了使用时间戳作为版本管理,简单就是说:在更新一个任务的配置后,version会替换,这时候会生成一个新的task(旧的任务在消费完数据后会被cleanTask的任务给删除掉)来继续。 在过渡期的时候,即新旧task同时在运行的时候,我们做了重启操作,此时两个任务同时执行了checkpoint操作。而bug的原因是在于,task的ID和diskQueue的ID是不相同的!也就是说两个任务虽然new出两个diskQ,但是两个diskQ会同时向一个文件中写数据,这就导致了文件的损坏。 这里的反思是:对于一个Task任务,如果需要和外部的文件或者其他资源交互时,一定需要保证外部的依赖对于每一个task任务都是唯一的。这里以fileSystem为例子,一个task保证对应的是一个file or dir。两种方式:1.使用一个xxx.lock的方式,一个系统如果已经决定对该资源做write/read操作时,就建立一个lock。该系统内部的进程想要同时做操作时可以避免因为上述简单的ID BUG而造成的问题。同时其他系统可以辨识到该文件可能被其他应用程序使用中,他可以针对这种情况做一些预期内的操作。 Golang中突然想起一种方案,对于需要写文件或者其他资源访问时,使用一个 channel 来做串行处理。比如当多个不可预知的任务可能同时做一个写入文件操作时,任务可以将此次操作的metadata以一种特定的数据格式交给上层系统(我们定义的channel)来统一处理,因为channel的并发写入是绝对安全的。当然如果是需要对多个文件做写入操作时,我们可以使用这样一种方式: 一个channel对应下游有多个channel(而不是file对象),每个channel都定义一个唯一ID,作为suffix。每个channel写完的文件都有ID,比如A,B,C三个channel现在