问题点: 类加载 双亲委派 数据库jdbc和tomcat跳过双亲委派 spring的spi springboot启动的fatjar 类加载生命周期 获取一个类的所有属性(含父类 private)
- 启动类加载器:加载JAVA_HOME/lib,是自己java虚拟机实现的一部分,非java类 Bootstrap ClassLoader
- 扩展类加载器:加载JAVA_HOME/lib/ext sun.misc.Launcher$AppClassLoader
- 应用程序类加载器 加载calsspath下的jar和class sun.misc.Launcher$ExtClassLoader classpath下类
- 自定义类加载器 继承自ClassLoader
- 非继承而是委派。
- 扩展类加载器的parent是Bootstrap ClassLoader,但代码获取是返回null。
- 除了启动类加载器Bootstrap ClassLoader,其他的类加载器都是ClassLoader的子类。
- jndi打破双亲委派 JDK1.3时加入到rt.jar的 Java的设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context
ClassLoader)。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。
有了线程上下文类加载器,程序就可以做一些“舞弊”的事情了。 - 为了消除这种极不优雅的实现方式,在JDK 6时,JDK提供了java.util.ServiceLoader类,以NETA-INF/services中的配置信息,辅以责任链模式,这才算是给SPI的加载提供了一种相对合理的解决方案。 如:mysql-connector-java-5.1.25.jar中META-INF/services/java.sql.Driver文件内容:com.mysql.jdbc.Driver
- jdbc打破双亲委派原因:rt.jar包中DriverManager是启动类加载器加载,要用到各数据库厂商自己实现的Driver类,无法获取到。
com.mysql.jdbc.Driver类静态方法:java.sql.DriverManager.registerDriver(new Driver());
java.sql.DriverManager中方法getConnection中callerCL = Thread.currentThread().getContextClassLoader();
用上下文加载器替换双亲委派 - tomcat打破双亲委派原因:tomcat一个应用下好几个webapp,每个webapp有各自自己的lib目录,同一个类要重复加载。
- 代码热替换(Hot Swap)、模块热部署(Hot Deployment)
- 沙箱安全机制
- fatjar
getClasses
getDeclaredClasses
getFields:返回所有public (接口即public)
getDeclaredFields:本类所有属性,含private
如何获取所有属性 含超类
getMethods
getDeclaredMethods
类加载生命周期 加载、连接(验证 准备 解析)、初始化、使用、销毁
引用
类的加载器
比如在系统类中提供了一个接口,该接口需要在应用类中得以实现,该接口还绑定一个工厂方法,用于创建该接口的实例,而接口和工厂方法都在启动类加载器中。这时,就会出现该工厂方法无法创建由应用类加载器加载的应用实例的问题。
由于Java虚拟机规范并没有明确要求类加载器的加载机制一定要使用双亲委派模型,只是建议采用这种方式而已。比如在Tomcat中,类加载器所采用的加载机制就和传统的双亲委派模型有一定区别,当缺省的类加载器接收到一个类的加载任务时,首先会由它自行加载,当它加载失败时,才会将类的加载任务委派给它的超类加载器去执行,这同时也是Servlet规范推荐的一种做法。
AnnotationElement