Contents
  1. 1. java类的加载机制
    1. 1.1. classLoader
    2. 1.2. tomcat的类加载机制
  2. 2. 反射和Spring IOC

java类的加载机制

  • java编译期:.java文件通过编译器编译成.class文件的过程,其中会校验格式和初步的问题(比如是否捕捉异常,list插入数据类型格式不对),也会优化一些运算(比如 String test=”a”+”b”; –> test=”ab”;)

  • 编译期的过程:

  1. 解析与填充符号表过程:解析主要包括词法分析和语法分析两个过程;
  2. 过程;(loombok的原理就是在这个时候按照规则插入相应的代码,绝对不是反射,反射是运行时编译)
  3. 语义分析与字节码的生成过程;
  • java运行期: 加载、连接、初始化、创建堆中对象

classLoader

http://blog.csdn.net/briblue/article/details/54973413#reply

  1. 加载器:
  • BootstrapClassLoader 最顶层的加载类,jvm内置的加载器,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。
  • ExtentionClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件
  • AppclassLoader也称为SystemAppClass 加载当前应用的classpath的所有类。也就是自己写的类基本上都是APP来加载的
  • 自定义ClassLoader,可以突破class文件包路径的限制,需要重写findClass()缓存查找方法制定寻找路径即可
  • contextClassLoader,是Thread的成员变量,默认是AppClassLoader。子线程默认和父线程相同的加载器
  1. 特点
  • 不同包路径下的类由不同的类加载器加载
  • jvm懒加载,根据需要去动态加载
  • 父加载器不是父类
  1. 加载机制:
    BootstrapClassLoader、ExtClassLoader、AppClassLoader实际是查阅相应的环境属性sun.boot.class.path、java.ext.dirs和java.class.path来加载资源文件的
  • AppclassLoader的父加载器为ExtClassLoader,ExtClassLoader的父加载器为null,JVM发现为null时就找内置的加载器BootstrapClassLoader。
  • Bootstrap ClassLoader是由C/C++编写的,它本身是虚拟机的一部分,所以它并不是一个JAVA类,也就是无法在java代码中获取它的引用,JVM启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件器。Bootstrap没有父加载器,但是它却可以作用一个ClassLoader的父加载器。比如ExtClassLoader
  1. 双亲委托:自下而上,先挨个找缓存,到了顶层缓存中还没有,就开始初始化,从各自对应负责的包路径下查找,有就创建,没有给就子加载器找。
  • 避免重复创建对象,浪费内存
  1. 重要的方法
  • loadClass(String 类全路径,Boolean resloved)
  • findLoadedClass(name) 先加锁在自己的加载器缓存中找是否已经有实例化
  • c = parent.loadClass(name, false); 找不到就递归在父加载器中加载
  • c = findClass(name);父加载器也加载不了,就在自己的管辖范围内创建类
  1. 加载的结果
  • 将class文件加载在内存中。
  • 将静态数据结构(数据存在于class文件的结构)转化成方法区中运行时的数据结构(数据存在于JVM时的数据结构)。
  • 在堆中生成一个代表这个类的java.lang.Class对象,作为数据访问的入口。

tomcat的类加载机制

http://blog.csdn.net/jiaomingliang/article/details/47416007
http://blog.csdn.net/czmacd/article/details/54017027

设计的结构:

  • tomcat下每个应用程序都有一个独立的类加载器,WebAppClassLoader,因为不同应用程序的类不能乱加载,更不能公用啊。
  • 但是有一些通用的类,比如JUnit、Log4j类,是不同应用程序公用的类,所以有sharedClassLoader出场,可以设置路径来实现这个类加载器,从而实现不同应用程序共同加载一些通用工具类
  • 再上一层就是CommonClassLoader:下面由shardClassLoader和CatalinaClassLoader,一个是所有应用程序,一个是tomcat容器的扩展类加载器
  • 再上一层就是AppClassLoader了,就是传统的模式往上走了
  1. tomcat类加载器
  • CommonClassLoader(默认父加载器为AppClassLoader)。加载一些tomcat/lib下面的jar包,servlet-api.jar、jsp-api.jar等
  • catalinaClassLoader(默认是空,有需要的话需要自己配置)
  • sharedClassLoader(默认是空,有需要的话需要自己配置)
  • WebAppClassLoader(tomcat下 WebRoot/应用程序/WEB-INF/lib 和 class包下的类)
  1. 加载顺序
  • tomcat启动,先加载BootStrap类初始化:CommonClassLoader、catalinaLoader、sharedLoader,会根据catelina.property里面的配置分配各自管理的类范围,默认catalinaLoader、sharedLoader配置为null,也就是默认3个加载器是同一个CommonClassLoader。
  • 每个应用程序都要各自独立的WebAppClassLoader,继承自sharedClassLoader

3.关键逻辑(源码 org.apache.catalina.loader.WebappClassLoader#loadClass)
tomcat的类加载机制是违反了双亲委托原则的,最后走投无路自己加载不了再去调用父加载器

  • 先在本地缓存中查找是否已经加载过该类(clazz = findLoadedClass0(name))
  • 再查询JVM缓存中查找是否已经加载过该类( clazz = findLoadedClass(name))
  • 让系统类加载器(AppClassLoader)尝试加载该类,主要是为了防止一些基础类会被web中的类覆盖(tomcat bin下包)(clazz = system.loadClass(name))
  • web应用的类加载器将自行加载(findClass),这里也违背了双亲 (clazz = findClass(name);)
  • 最后还是加载不到的话,则委托父类加载器(Common ClassLoader)去加载。(clazz = Class.forName(name, false, parentLoader);)

反射和Spring IOC

  • 反射是运行期编译,只有执行到这个方法,确定了参数:类名的时候才编译出对应的class文件,再加载到内存当中
    Class tc = Class.forName(“com.java.dbtest.TestConnection”);
  • CGLIB也是运行期编译,Enhancer类继承代理类,拦截相应的方法,实现代理
Contents
  1. 1. java类的加载机制
    1. 1.1. classLoader
    2. 1.2. tomcat的类加载机制
  2. 2. 反射和Spring IOC