大数据平台底层技术-JAVA篇-如何动态加载不同版本的 HIVE JDBC 驱动 - 一文读懂JAVA的类加载机制 1

简介: 大数据平台底层技术-JAVA篇-如何动态加载不同版本的 HIVE JDBC 驱动 - 一文读懂JAVA的类加载机制

1 前言

大家好,我是明哥!

市场上大数据相关岗位和对应的的技能,主要分为三大类:

  • 侧重数据平台底层技术:如大数据运维工程师,大数据开发工程师,大数据架构师;
  • 侧重数据的加工和分析:如数据仓库工程师/建模工程师,数据工程师/ETL开发,数据分析师;(data engineer, data analyst)
  • 侧重数据的深度挖掘:如算法工程师,数据科学家,AI工程师;(data scientist)

image.png

其中第一大类,“侧重数据平台底层技术”,需要在底层大数据平台(如CDH/HDP/CDP/TDH等)的基础上,开发一些平台类的工具或应用,来支撑或辅助第二大类和第三大类相关从业人员的日常工作,所以需要扎实的 JAVA 或 SCALA 语言功底,也需要扎实的 LINUX 运维知识。

有鉴于此,后续笔者会推出系列文章,从大数据的角度出发,专门讲述数据平台底层技术 (分为 JAVA 篇与 LINUX 篇)。

本文是“数据平台底层技术-JAVA篇” 之一,讲述如何根据用户的具体情况,动态加载特定目录下的 JAVA 类,这在一些跨平台跨版本的大数据应用中,是一个常见的需求。(比如根据用户的具体情况,加载特定目录下特定版本的 HIVE JDBC 驱动),背后涉及到的知识是 JAVA 的类加载机制。

2 什么是类加载器

  • 类加载器,即 Class loaders, 是 JRE 的一部分,负责在 JVM 程序运行时,动态加载 JAVA 类到 JVM 内存中;
  • 通过类加载器,JVM 在运行 JAVA 程序时,不需要知道底层的文件系统和文件,即类加载器解耦了 JVM 和操作系统底层的文件系统;
  • 我们之所以说类是“动态”加载的,主要是因为运行程序时需要的所有的 JAVA 类,并不是一次性全部加载到 JVM 内存中,而是在需要哪个类时才加载那个类。

3 JRE 中主要有哪些内置的类加载器

3.1. Bootstrap Class Loader

  • bootstrap class loader 是 JVM 核心的一部分,是使用 native 代码编写的,所以在不同的平台上(如windows,linus,macos),有不同的实现;
  • Bootstrap class loader 是所有其它类加载器的父类;( 这里所说的父类,不是普通类继承关系层面上的父类);
  • Bootstrap Class Loader 负载加载 JDK 内部类,这些内部类在目录 $JAVA_HOME/jre/lib 下,比如 rt.jar;
  • Bootstrap Class Loader 打印时会显示为 null (因为其是用 native 代码实现的);

3.2 Extension Class Loader

  • extension class loader 是 bootstrap class loader 的子类;
  • extension class loader 负责加载JDK的扩展类,这些扩展类一般在目录 $JAVA_HOME/lib/ext 下,或系统变量 java.ext.dirs 指定的其它目录;

3.3. System/application Class Loader

  • system class loader, 或称为 application class loader, 是 Extensions classloader 的子类;
  • system class loader 负责加载 JAVA 应用级别的类, 这些类都在环境变量 classpath 指定的目录下,用户在提交 JAVA 程序时,可以通过命令行参数 -classpath 或 -cp 指定环境变量 classpath。

大家可以通过以下示例代码进行验证:

public void printClassLoaders() throws ClassNotFoundException {
    System.out.println("Classloader of this class:"
        + PrintClassLoader.class.getClassLoader());
    System.out.println("Classloader of Logging:"
        + Logging.class.getClassLoader());
    System.out.println("Classloader of ArrayList:"
        + ArrayList.class.getClassLoader());
}
示例输出:
Class loader of this class:sun.misc.Launcher$AppClassLoader@18b4aac2
Class loader of Logging:sun.misc.Launcher$ExtClassLoader@18769467
Class loader of ArrayList:null

4 JRE 中类加载器是怎么工作的

image.png

类加载器加载类,遵循了双亲委派模型:

  • “双亲委派模型”的双亲,更严谨来讲,其实是多级单亲;
  • 双亲委派模型下,所有的类加载器,除了 bootstrap class loader, 都有一个唯一的父加载器;
  • ”双亲委派模型“的父子关系,不是普通 JAVA 类关系层面上的父子继承关系 (extends),而更像是一种有层次之分的组合关系;
  • 当类加载器收到一个类或资源的加载请求后,会首先搜索该类或资源是否已经被加载到内存中了,如果已经被加载了的话,不会重复加载该类或资源;如果没有被加载,则会将加载请求委派给父级加载器去加载;(在内存中搜索时,一样会遵循类的可见性,类的可见性的具体含义见下文)
  • 父级加载器一样遵循向上委派机制,将加载请求委派给其父级加载器去加载,通过这种向上传导关系,所有的类加载请求,最终都会被传入到启动类加载器(Bootstrap ClassLoader)中;
  • 只有当父级加载器反馈无法完成特定类或资源的加载请求时,即父级加载器在它的搜索范围内找不到该类或资源时,子级加载器才尝试在自己的搜索范围内加载类或资源;
  • 如果所有的父级加载器在其搜索范围内都找不到该类或资源,且子级加载器在自己的搜索范围内也找不到该类或资源,JVM 就会报 java.lang.ClassNotFoundException;

遵循以上双亲委派模型,当我们需要加载一个应用类到 JVM 中时:

  • system class loader 首先搜索 jvm 内存,发现该类没有被加载过,然后会委派该加载请求给其父类加载器 extension class loader;
  • extension class loader 又会将该加载请求委派给其父类 bootstrap class loader;
  • bootstrap class loader 尝试加载该类,会在其搜索范围内(即目录 $JAVA_HOME/jre/lib)尝试查找该类,找不到;
  • 然后 extension class loader 才会尝试加载该类,在其搜索范围内(即目录 $JAVA_HOME/lib/ext 下,或系统变量 java.ext.dirs 指定的其它目录下)尝试查找该类,找不到;
  • 然后 system class loader 才会尝试自己加载该类,会在其搜索范围内(环境变量 classpath 指定的目录下)尝试查找该类,查找成功,加载成功。

通过以上双亲委派模型,JVM 确保了:

  • 类的唯一性 Unique:只有在父类加载器在其搜索范围内找不到类,无法加载类时,子类加载器才会尝试自己加载,这样就避免了重复加载,确保了类的唯一性:比如类 java.lang.Object,它在 $JAVA_HOME/jre/lib/rt.jar中,无论哪个类加载器需要加载该类,最终都是委派给处于模型顶端的启动类加载器bootstrap class loader 加载的,而 bootstrap class loader 只会在 $JAVA_HOME/jre/lib/rt.jar 中搜索加载该类,因此类 java.lang.Object 在各种加载环境中都是同一个类;
  • 类的可见性 Visibility:父类加载器加载的类对子类加载器(加载的类)可见,而子类加载器加载的类对父类加载器(加载的类)不可见:(所谓的可见,即能访问):即 system class loader 加载的类,可见 extension 和 Bootstrap class loaders 加载的类,反过来则不可见;比如,Class A 是 application class loader 加载的,而 class B 是 extensions class loader 加载的, 则此时 Application class loader 加载的其它类,可以访问 A 和 B; 而 extenson class loader 加载的其它:类, 则只可以访问 B 而不能访问A;
  • 类的安全性 Secure:双亲委派模型实现了类的唯一性和可见性,避免了用户随意定义类加载器加载核心 API 带来的安全隐患,从而进一步确保了类的安全性;

以上双亲委派模型的具体实现,可以参见源码java.lang.ClassLoader

image.png


5. JRE 中双亲委派模型的不足与 thread Context Classloaders

有时,JVM 核心类可能需要动态加载应用开发人员提供的特定类或资源:

  • 比如 JNDI 中核心功能都是在 rt.jar 的核心内部类中实现的,但在程序运行时,这些 JNDI 类可能需要加载类加载路径下各个 vendor 的具体实现类 (通过命令行参数 -classpath 或 -cp 指定类加载路径的具体目录),此时就需要 bootstrap class loader (parent class loader) 加载本应只对 application class loader 可见的类 (child class loader);
  • 再比如 JDBC 中核心功能都是在 rt.jar 的核心内部类中实现的,包括 java.sql.DriverManager/java.sql.Driver等, 但在程序运行时,这些 JDBC 类可能需要加载类加载路径下各个 vendor 的具体实现类 (通过命令行参数 -classpath 或 -cp 指定类加载路径的具体目录),比如 oracle jdbc 驱动 oracle.jdbc.driver.OracleDriver,此时也需要 bootstrap class loader (parent class loader) 加载本应只对 application class loader 可见的类 (child class loader).

此时,以上 J2SE 双亲委派机制就不 work 了。为此,JVM 提供了 thread context class loader:

  • 每个线程在创建时,都有一个对应的 ContextClassLoader,来负责该线程中类或资源的加载;
  • 当没有显示指定时,线程的 ContextClassLoader 跟其父线程的 context class loader 是同一个;
  • 可以通过方法 getContextClassLoader() 获得当前线程的 ContextClassLoader;
  • 可以通过方法 setContextClassLoader(ClassLoader cl) 重置当前线程的 ContextClassLoader;

image.png

image.png

image.png

可以通过以下代码,验证 JDBC 相关类的加载器:

Class<?> driverManagerClass = Class.forName("java.sql.DriverManager");
Class<?> driverClass = Class.forName("java.sql.Driver");
Class<?> oracleDriverClass = Class.forName("oracle.jdbc.driver.OracleDriver");
System.out.println("driverManagerClass.getClassLoader():" + driverManagerClass.getClassLoader());
System.out.println("driverClass.getClassLoader():" + driverClass.getClassLoader());
System.out.println("oracleDriverClass.getClassLoader():" + oracleDriverClass.getClassLoader());
对应的输出如下:
driverManagerClass.getClassLoader():null
drivrClass.getClassLoader():null
oracleDriverClass.getClassLoader():sun.misc.Launcher$AppClassLoader@18b4aac2


相关实践学习
简单用户画像分析
本场景主要介绍基于海量日志数据进行简单用户画像分析为背景,如何通过使用DataWorks完成数据采集 、加工数据、配置数据质量监控和数据可视化展现等任务。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
1月前
|
Cloud Native 数据处理 云计算
探索云原生技术在大数据分析中的应用
随着云计算技术的不断发展,云原生架构作为一种全新的软件开发和部署模式,正逐渐引起企业的广泛关注。本文将探讨云原生技术在大数据分析领域的应用,介绍其优势与挑战,并探讨如何利用云原生技术提升大数据分析的效率和可靠性。
|
16天前
|
分布式计算 Hadoop 大数据
大数据技术与Python:结合Spark和Hadoop进行分布式计算
【4月更文挑战第12天】本文介绍了大数据技术及其4V特性,阐述了Hadoop和Spark在大数据处理中的作用。Hadoop提供分布式文件系统和MapReduce,Spark则为内存计算提供快速处理能力。通过Python结合Spark和Hadoop,可在分布式环境中进行数据处理和分析。文章详细讲解了如何配置Python环境、安装Spark和Hadoop,以及使用Python编写和提交代码到集群进行计算。掌握这些技能有助于应对大数据挑战。
|
1月前
|
数据采集 分布式计算 大数据
Java语言在大数据处理中的应用
传统的大数据处理往往依赖于庞大的数据中心和高性能的服务器,然而随着大数据时代的到来,Java作为一种强大的编程语言正在被广泛应用于大数据处理领域。本文将探讨Java语言在大数据处理中的优势和应用,以及其在分布式计算、数据处理和系统集成等方面的重要作用。
|
1天前
|
分布式计算 安全 Java
JAVA的三大版本
JAVA的三大版本
|
4天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
11天前
|
Oracle Java 关系型数据库
Java 开发者必备:JDK 版本详解与选择策略(含安装与验证)
Oracle Java SE 支持路线图显示,JDK 8(LTS)支持至2030年,非LTS版本如9-11每6个月发布且支持有限。JDK 11(LTS)支持至2032年,而JDK 17及以上版本现在提供免费商用许可。LTS版本提供长达8年的支持,每2年发布一次。Oracle JDK与OpenJDK有多个社区和公司构建版本,如Adoptium、Amazon Corretto和Azul Zulu,它们在许可证、商业支持和更新方面有所不同。个人选择JDK时,可考虑稳定性、LTS、第三方兼容性和提供商支持。
24 0
|
17天前
|
SQL 分布式计算 Hadoop
利用Hive与Hadoop构建大数据仓库:从零到一
【4月更文挑战第7天】本文介绍了如何使用Apache Hive与Hadoop构建大数据仓库。Hadoop的HDFS和YARN提供分布式存储和资源管理,而Hive作为基于Hadoop的数据仓库系统,通过HiveQL简化大数据查询。构建过程包括设置Hadoop集群、安装配置Hive、数据导入与管理、查询分析以及ETL与调度。大数据仓库的应用场景包括海量数据存储、离线分析、数据服务化和数据湖构建,为企业决策和创新提供支持。
60 1
|
25天前
|
NoSQL 大数据 数据挖掘
现代数据库技术与大数据应用
随着信息时代的到来,数据量呈指数级增长,对数据库技术提出了前所未有的挑战。本文将介绍现代数据库技术在处理大数据应用中的重要性,并探讨了一些流行的数据库解决方案及其在实际应用中的优势。
|
30天前
|
机器学习/深度学习 人工智能 数据可视化
基于Python的数据可视化技术在大数据分析中的应用
传统的大数据分析往往注重数据处理和计算,然而数据可视化作为一种重要的技术手段,在大数据分析中扮演着至关重要的角色。本文将介绍如何利用Python语言中丰富的数据可视化工具,结合大数据分析,实现更直观、高效的数据展示与分析。
|
1月前
|
存储 NoSQL 大数据
新型数据库技术在大数据分析中的应用与优势探究
随着大数据时代的到来,传统数据库技术已经无法满足海量数据处理的需求。本文将探讨新型数据库技术在大数据分析中的应用情况及其所带来的优势,为读者解析数据库领域的最新发展趋势。