当前位置: 首页 > news >正文

网站分析案例免费货源网站免费版权

网站分析案例,免费货源网站免费版权,济南谷歌推广,企业展厅数字多媒体类加载器与双亲委派 Java 类加载器#xff08;Class Loader#xff09;是 Java 虚拟机#xff08;JVM#xff09;的一部分#xff0c;负责将类的字节码加载到内存中#xff0c;并将其转换为可执行的 Java 对象。类加载器在 Java 应用程序中起着重要的作用#xff0c;它…类加载器与双亲委派 Java 类加载器Class Loader是 Java 虚拟机JVM的一部分负责将类的字节码加载到内存中并将其转换为可执行的 Java 对象。类加载器在 Java 应用程序中起着重要的作用它实现了动态加载类的机制使得 Java 具备了灵活性和可扩展性。 1. 概念 1.1 类加载的过程 类的生命周期通常包括加载、链接验证、准备、解析、初始化、使用和卸载。其中类加载的三个阶段为加载、链接验证、准备、解析、初始化、 其作用分别为 加载通过一个类的完全限定查找类字节码文件转化为方法区运行时的数据结构创建一个代表该类的 Class 对象。链接 验证确保 Class 文件的字节流中包含信息符合当前虚拟机要求不会危害虚拟机自身安全。准备为类变量(即 static 修饰的字段变量)分配内存并且设置该类变量的初始值。不包含被 final 修饰的 static 变量因为它在编译时已经分配了。解析将常量池内的符号引用转换为直接引用的过程。如果符号引用指向一个未被加载的类或者未被加载类的字段或方法那么解析将触发这个类的加载。 初始化类加载最后阶段若该类具有超类则对其进行初始化执行静态初始化器和静态初始化成员变量。 1.2 Java 类加载器 Java 类加载器 Java 虚拟机用于加载类文件的一种机制。在 Java 中每个类都由类加载器加载并在运行时被创建为一个 Class 对象。类加载器负责从文件系统、网络或其他来源中加载类的字节码并将其转换为可执行的 Java 对象。类加载器还负责解析类的依赖关系即加载所需的其他类。 虚拟机内部提供了三种类加载器 启动Bootstrap类加载器也称为根类加载器它负责加载 Java 虚拟机的核心类库如 java.lang.Object 等。启动类加载器是虚拟机实现的一部分它通常是由本地代码实现的不是 Java 类。扩展Extension类加载器用来加载 Java 扩展类库的类加载器。扩展类库包括 javax 和 java.util 等包它们位于 jre/lib/ext 目录下。系统System类加载器也称应用类加载器它负责加载应用程序的类。它会搜索应用程序的类路径包括用户定义的类路径和系统类路径并加载类文件。 用户可以自定义类加载器。 1.3 双亲委派模型加载类 类加载器采用了双亲委派模型Parent Delegation Model来加载类。即当一个类加载器需要加载类时它会首先委派给其父类加载器加载。如果父类加载器无法加载才由该类加载器自己去加载。这种层级关系使得类加载器能够实现类的共享和隔离提高了代码的安全性和可靠性。 1.3.1 双亲委派模型的执行流程 双亲委派模型的执行流程 1、当加载一个类时会先从应用程序类加载器的缓存里查找相应的类如果能找到就返回对象如果找不到就执行下面流程 2、在扩展加载器缓存中查找相应的类如果能找到就返回对象如果找不到就继续下面流程 3、在启动类加载器中查询相应的类如果找到就返回对象如果找不到就继续下面流程 4、在扩展加载器中查找并加载类如果能找到就返回对象并将对象加入到缓存中如果找不到就继续下面流程 5、在应用程序类加载器中查找并加载类如果能找到就返回对象并将对象加入到缓存中如果找不到就返回 ClassNotFound 异常。 即当一个类加载器收到了一个类加载请求时它自己不会先去尝试加载这个类而是把这个请求转交给父类加载器。 双亲的含义 向上查找缓存并加载向下加载类 ClassLoader 内的 loadClass 方法中的双亲委派实现: protected Class? loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {//检查该class是否已经被当前类加载器加载过这是一个抽象方法具体实现由子类实现Class? c findLoadedClass(name);if (c null) {//此时该class还没有被加载try {if (parent ! null) {//如果父加载器不为null,则委托给父类加载c parent.loadClass(name, false);} else {//如果父加载器为null,说明当前类加载器已经是启动类加载器直接时候用启动类加载器去加载该classc findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {}if (c null) {//此时父类加载器都无法加载该class,则使用当前类加载器进行加载long t1 System.nanoTime();c findClass(name);...}}//是否需要连接该类if (resolve) {resolveClass(c);}return c;}}1.3.2 优点 安全 用户无法伪造不安全的系统类。根据双亲委派模型jre 提供的类在启动类和扩展类加载时加载早于用户伪造的系统类的应用类加载。 避免重复加载 当一个类加载后会被缓存不会出现多个类加载器将同一个类重复加载的情况。 1.3.3 缺点 加载 SPI 实现类的场景 类加载的范围受到限制某些情况下父 class loader 无法加载某些类文件这时候就需要委托到下层级的 class loader 去加载类文件。 双亲委派使得启动类加载器无法加载用户的 jar 包比如 装载 JDBC 驱动实现类的 DriverManager 类是 JDK 核心类而被装载的类是用户类导致无法加载的尴尬问题需要用 Context Class Loader 来加载 Driver 实现类从而打破了双亲委派模型。在 tomcat 中子加载器优先于父加载器加载。即为了实现各个 webapp 的隔离性webappClassLoader 会先于父加载器加载。 2. 自定义类加载器 参考 ClassLoader 的实现流程需要依次实现 loadclass双亲委派机制子加载器委托父加载器加载父加载器都加载失败时子加载器通过 findclass 自行加载。该方法使用了模版方法模式继承 ClassLoader 后不需要我们实现。findclass当前类加载器根据路径以及 class 文件名称加载字节码从 class 文件中读取字节数组然后使用 defineClassdefineclass根据字节数组返回 Class 对象。 在 ClassLoader 的源码中提供了一个自定义类加载器的模版 class NetworkClassLoader extends ClassLoader {String host;int port;public Class findClass(String name) {// 读取class文件转化为字节数组byte[] b loadClassData(name);// 读取字节数组转化为Class对象return defineClass(name, b, 0, b.length);}private byte[] loadClassData(String name) {// load the class data from the connection}}可以看到只需要继承 ClassLoader并且重写 findClass 方法即可。 3. JDBC 打破双亲委派 jdk 为了统一管理数据库驱动在 java.sql 下定义了 Driver 接口具体的实现由数据库厂商去做。 3.1 JDBC 4.0 之前 // 使用应用类加载器加载 Driver 实现类Class.forName(com.mysql.jdbc.Driver);Connection conn DriverManager.getConnection(jdbc:mysql://localhost:3306/test, root, root);public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {//将mysql的Driver注册进驱动管理器中DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException(Cant register driver!);}} }加载 Driver 实现类的过程 Class.forName 会使用应用类加载器加载 Driver 实现类加载 Driver 实现类需要执行静态方法即将 mysql 的 Driver 注册进驱动管理器中那么此时需要加载 DriverManager 类应用类加载器去加载 DriverManager 类而 DriverManager 位于 rt.jar 中便一直向上委托到启动类加载器完成加载 没有破坏双亲委派 3.2 JDBC 4.0 之后 // 直接调用 DriverManager获取驱动列表EnumerationDriver en DriverManager.getDrivers();while (en.hasMoreElements()) {java.sql.Driver driver en.nextElement();System.out.println(driver);}应用类加载器逐层委托到启动类加载器去加载 DriverManager 时会同时执行它的静态方法 static {loadInitialDrivers();println(JDBC DriverManager initialized);}启动类加载 DriverManager之后需要通过 spi 机制去加载 jar 包中的 Driver 类而该 Driver 理应被应用类加载器加载这个时候就需要启动类加载器去通知应用类加载器这明显违背了双亲委派机制。 loadInitialDrivers 方法 ServiceLoaderDriver loadedDrivers ServiceLoader.load(Driver.class);IteratorDriver driversIterator loadedDrivers.iterator();ServiceLoader.load 方法Thread.currentThread().getContextClassLoader()是线程上下文类加载器,使用的是线程上下文类加载器去加载的 Driver 实现类。 public static S ServiceLoaderS load(ClassS service) {ClassLoader cl Thread.currentThread().getContextClassLoader();return ServiceLoader.load(service, cl);}在 sun.misc.Launcher 类中将应用类加载器设置进了线程上下文类加载器中,通过线程上下文类加载器我们可以拿到应用类加载器的引用: public Launcher() {this.loader Launcher.AppClassLoader.getAppClassLoader(var1);Thread.currentThread().setContextClassLoader(this.loader);}打破双亲委派的过程 在 jdbc4.0 的情况下梳理一下整个过程 应用类加载器逐层委托到启动类加载器去加载 DriverManager 类启动类加载器加载 DriverManager 类时会执行其静态方法即通过 spi 机制去加载 jar 包中的 Driver 实现类此时启动类加载器需要委托应用类加载器加载 Driver 实现类具体做法是通过线程上下文类加载器拿到应用类加载器的引用 4. TOMCAT 打破双亲委派 TOMCAT 的两个基础功能点 实时更新 JSP应用打包放在 webapps 目录下就可以运行 4.1 实时更新 JSP JVM 确定类的唯一性由类加载器实例全限定名一起确定的。全限定名相同类加载器不同则会被认定为不同的类。 4.2 应用打包放在 webapps 目录下就可以运行 应用 A 和应用 B 所依赖的 Spring 版本不同却依旧可以运行。 webapps 下的每一个应用都会对应一个不同的类加载器实例用以保持应用间的隔离。 4.3 打破双亲委派 某个自定义的类加载想要打破双亲委派只需要重写 loadClass 方法即可。 Tomcat 中的 WebappClassLoader 就是自定义类加载器它的 loadClass 方法为 public Class loadClass(String name) throws ClassNotFoundException {return (loadClass(name, false));}public Class loadClass(String name, boolean resolve)throws ClassNotFoundException {if (log.isDebugEnabled())log.debug(loadClass( name , resolve ));Class clazz null;// Log access to stopped classloaderif (!started) {try {throw new IllegalStateException();} catch (IllegalStateException e) {log.info(sm.getString(webappClassLoader.stopped, name), e);}}//1、从自己的本地缓存中查找本地缓存的数据结构为ResourceEntryclazz findLoadedClass0(name);if (clazz ! null) {if (log.isDebugEnabled())log.debug( Returning class from cache);if (resolve)resolveClass(clazz);return (clazz);}//2、从jvm的缓存中查找clazz findLoadedClass(name);if (clazz ! null) {if (log.isDebugEnabled())log.debug( Returning class from cache);if (resolve)resolveClass(clazz);return (clazz);}//3、如果缓存中都找不到则利用系统类加载器加载try {clazz system.loadClass(name);if (clazz ! null) {if (resolve)resolveClass(clazz);return (clazz);}} catch (ClassNotFoundException e) {// Ignore}if (securityManager ! null) {int i name.lastIndexOf(.);if (i 0) {try {securityManager.checkPackageAccess(name.substring(0,i));} catch (SecurityException se) {String error Security Violation, attempt to use Restricted Class: name;log.info(error, se);throw new ClassNotFoundException(error, se);}}}boolean delegateLoad delegate || filter(name);//4、开启代理的话则使用父加载器加载if (delegateLoad) {if (log.isDebugEnabled())log.debug( Delegating to parent classloader1 parent);ClassLoader loader parent;if (loader null)loader system;try {clazz loader.loadClass(name);if (clazz ! null) {if (log.isDebugEnabled())log.debug( Loading class from parent);if (resolve)resolveClass(clazz);return (clazz);}} catch (ClassNotFoundException e) {;}}//5、自行加载if (log.isDebugEnabled())log.debug( Searching local repositories);try {clazz findClass(name);if (clazz ! null) {if (log.isDebugEnabled())log.debug( Loading class from local repository);if (resolve)resolveClass(clazz);return (clazz);}} catch (ClassNotFoundException e) {;}//如果自己也加载不了那就只能让父加载器加载了if (!delegateLoad) {if (log.isDebugEnabled())log.debug( Delegating to parent classloader at end: parent);ClassLoader loader parent;if (loader null)loader system;try {clazz loader.loadClass(name);if (clazz ! null) {if (log.isDebugEnabled())log.debug( Loading class from parent);if (resolve)resolveClass(clazz);return (clazz);}} catch (ClassNotFoundException e) {;}}throw new ClassNotFoundException(name);}内部逻辑 先从 WebappClassLoader 的 ResourceEntry 缓存中查找从 jvm 缓存中查找比如去元数据区查找利用系统类应用类加载器加载避免 webapp 中的类覆盖掉标准类库中的类。开启代理的话则使用父加载器加载这个默认没开启的。webappClassLoader 自行去加载自己也没加载成功的话最后只能让父加载器去加载 即 对于一些标准类库中的类比如 Object 类会让系统类加载器加载然后一直委托到启动类加载器这个过程是没有违背双亲委派的。而对于 webapp 中独有的类则是 webappClassLoader 自行去加载加载失败才让父加载器加载明显是违背双亲委派的。 参考资料 深度思考老生常谈的双亲委派机制JDBC、Tomcat 是怎么反其道而行之的
http://www.dnsts.com.cn/news/21818.html

相关文章:

  • 网站查询功能代码重庆网红
  • 杭州网站设计自己创建网站容易吗
  • 小网站文案动漫设计工作室网站制作公司
  • 常州企业自助建站系统2022全国封城名单
  • 网站专项审批查询wordpress 书籍 pdf
  • 免费网站模板 下载网站制作教程一般地建网络
  • php网站开发什么男女做爰免费网站
  • 婚纱网站php可以做护考题目的网站
  • 广东网站开发费用seo知识是什么意思
  • core wordpress呼和浩特整站优化
  • 微网站开发协议seo比较好的优化方法
  • 网站收录低手机网站一年费用吗
  • 怎么自己编码做网站手机兼职赚钱
  • 建网站多少钱建个网站需要怎么做wordpress建站镜像
  • 个人网站建设公司地址网站建设需要多长时间
  • 唐山网站建设拓app设计策划书
  • 静态网站开发如何进入设计公司网站
  • 微商城网站建设报价卓航网站开发
  • 网站备案应该怎么做前端网站建设插件
  • 网站建设代码生成器南宁网站设计多少钱一个
  • 做网站的公司没有技术wordpress 插件库 思路
  • 武进网站建设多少钱上海优化外包公司排名
  • 网站建设工单系统海外营销是干什么的
  • 定西企业网站制作wordpress用什么建
  • 企业网站建设效果wordpress会员中心
  • 网站服务器在哪租建筑网站资料
  • 网站建设属于哪个税目免费域名注册优惠
  • 建设实验中心网站网站开发技术简介
  • 建网站logo怎么做建一个大型网站需要多少钱
  • 建设官方网站多少仿 wordpress