Scala Class etc.

本文深入探讨Scala编程语言的关键特性,包括类与对象、构造器、内部类、伴生对象、trait、继承、包与导入机制。详细解析了Scala如何处理类字段、方法、构造过程、类型检查与转换、模式匹配等核心概念。

Classes

  • 一个源文件可包含多个类,每个类默认都是 public
  • 类字段必须初始化,编译后默认是 private,自动生成 public 的 getter/setter ;Person 示例
    • private 字段,生成 private 的 getter/setter
    • val 字段,只生成 getter
    • private[this] 字段,不生成 getter/setter
    • 自定义 getter/setter,foo 和 foo_=
  • 类方法默认都是 public
  • 方法调用规约:访问器调用可省略括号,修改器调用加上括号
  • 为字段加上 @bean.BeanProperty 注解可生成符合 JavaBean 规范的 get/set 方法(加上默认的两个方法,共四个方法)
  • 构造器:1 个主构造器,任意个辅构造器
    • 全部都叫 this,只是参数不同
    • 辅构造器必须调用主构造器或之前定义的辅构造器
    • 主构造器与类定义密不可分,参数直接定义在类名后
    • 主构造器会立即执行类定义中的所有语句
    • 主构造器中的参数被方法使用到,则对应的参数等价于 private[this] val 字段
  • 内部类
    • 路径依赖,不同于 Java 内部类,同一类 A 的不同实例(a1, a2)构建的内部类 Inner,其类型是不同的,a1.Inner != a2.Inner
    • 解决路径依赖
      • 类型投射,Outer#Inner
      • 将内部类放到伴生对象 object 中
    • self => 自身类型,区分调用的内部类和外部类的字段、方法等

Objects

  • 用于单例及工具类方法
    • object 构造器只在第一次被调用时执行
  • 可继承一个 class 或多个 trait
    • 可用于全局默认对象
  • 不可提供构造器参数
  • 伴生对象
    • 与类名称一致
    • 类与伴生对象可互相访问私有资源,但区分作用域,如 Accounts.newUniqueNumber() 而不是 newUniqueNumber()
    • 类与伴生对象必须在同一个源文件中
  • 伴生对象中的 apply 方法
    • 调用方式 Object(arg1, ..., argN), 返回伴生类的实例,如 Array(1,2,3)
    • 省略 new 关键字,在嵌套表达式中很方便
  • 应用对象
    • extends App
    • 不需要 main 方法直接执行构造器内的代码
  • scala 默认无枚举类型
    • 使用 Enumeration 帮助类实现
    • 枚举类型为 Enumeration.Value(ID, name) 内部类, ID 依次累加, 默认 0 开始;name 默认是字段名

Traits

  • 替代 Java 中的接口
  • 可以有抽象的和具体的方法
    • trait 中未实现的方法默认是抽象的 (abstract)
  • 类可以实现多个 trait,从最后一个开始调用
    • 使用 extends 关键字实现
    • 覆盖抽象方法时不需要 override 关键字
    • 有多个 trait 则对其他的 trait 使用 with 关键字
  • 所有的 Java 接口都可以被当做 trait 使用
  • 对象也可以添加多个 trait,从最后一个开始调用
  • 多个 trait 的情况下,super.someMethod 会根据从右向左的顺序调用下一个 trait 的方法
    • 具体调用依赖于使用时的顺序,相比传统的继承更灵活
    • 在多个 mix-in 的情况下,如果父trait存在抽象方法,则子trait需使用 abstract override 关键字,否则 super.someMethod 无法编译
  • 有初始值的字段/具体字段,都会被添加到子类中
  • 无初始值的字段/抽象字段,在非抽象子类中,需要进行初始化
  • trait 也有构造器
    • 不可以有构造参数,且只有一个构造器
    • 由定义体中的初始化字段和其他语句构成
    • 构造顺序:父类 > 各trait从左向右,有父 trait 的先构造,共享的父 trait 只构造一次 > 子类
    • 考虑到构造顺序,如果子类中使用抽象字段,则可使用提前定义(early definition,会在构造器之前执行)的语法讲改字段初始化
      • 提前定义语句块中只能使用字段定义语句,不可使用其他语句
  • trait 可继承类,混入该 trait 的类都是被继承类的子类,子类如果有继承其他的类也必须是被继承类的子类
  • 与自身类型(self type)比较
    • trait 不继承类,直接在 body 内定义 this: Type =>,则混入的类必须是该 Type 类型的/子类型的
    • 也可使用结构类型(structural type),this: { def log(msg: String) } => ,则混入的类必须包含结构类型中定义的方法
  • trait 最终会翻译成类和接口

Packages and Imports

  • package 包名和文件路径并不一定对应
  • java.lang, scala, Predef 始终默认会导入
  • 与 Java 不同,包路径并不是绝对的,如 collection.mutable 实际是 scala.collection.mutable
  • package a.b.cpackage a { package b { package c {}}} 不同
    • package apackage b 中定义的资源可在带括号的包声明中访问,但 package a.b.c 无法访问
  • 包对象
    • package 由于 JVM 的限制不能直接声明函数或变量
    • 不同于 package, package object 可定义工具函数或常量
  • 可见性控制,通过 private[package.name] 限制资源的可见性
  • import
    • 导入包后可使用相对路径访问类等,如 collection.mutable
    • 导入所有资源 import collection.mutable._
    • 可在任意位置进行导入操作
    • selector
      • 选择性的导入一部分成员,import java.awt.{Color, Font}
      • 为导入成员取别名:import java.util.{HashMap => JavaMap}
      • 隐藏成员: import java.util.{HashMap => _, _} // 避免产生混淆
    • 隐式导入,默认导入三个 java.lang, scalaPredef
      • 后面导入的可将前面的成员覆盖,避免冲突
      • 导入 scala 相关的包可省略 scala 路径

Inheritance

fragile base class 基类被继承之后,修改基类可能会对子类造成无法预期的影响

  • 继承类,与 Java 一样使用 extends 关键字

    • final 类不能被继承, final 字段、方法不能被覆盖
  • 覆盖非抽象方法,必须使用 override 关键字

  • 抽象方法

    • 无方法体的方法,可以省略 abstract 关键字;子类覆盖时也可以省略 override
  • 抽象字段

    • 无初始值的字段,可省略 abstract 关键字,子类覆盖式也可省略 override
  • 调用父类方法,使用 super 关键字

  • 类型检查和转换, isInstanceOf, asInstanceOf;获取类型, classOf

    • 模式匹配通常是个更好的类型检查方式
  • protected 不同于 Java,受保护成员在包内不可见

  • 辅助构造器不可直接调用超类构造器

    • 可在定义类时直接在 extends 时调用超类构造器并传递参数
    • 继承 Java 类时主构造器必须调用超类的构造器
  • 覆盖字段

    • def 只能覆盖 def
    • val 只能覆盖 无参数的 def
    • var 只能覆盖 抽象的 var
  • 继承层级

    file

    • Any 定义了 asInstanceOf, isInstanceOf,判断相等,hash值等方法
    • AnyRef 是除基础类型外所有类的父类,等价于 java.lang.Object
      • 提供方法 wait, notify/notifyAllsynchronized
    • AnyVal 不包含任何方法,只是个值类型的标记
    • 所有 Scala 类都实现了 ScalaObject 这个标记接口,该接口无任何方法
    • Null 的唯一实例 null,可分配给引用类型,但不可分配给值类型(Int 不可为 null)
    • Nothing 无实例,在泛型构造时有用,Nil 类型为 List[Nothing]
    • ??? 方法声明返回类型为 Nothing, 无返回值,会抛出 NotImplementedError,用于预留未实现的方法
    • Unit 代表空/void,类型唯一值为 ()
    • 如果方法参数类型为 AnyAnyRef, 当传递多个参数时,会被替换为 tuple
  • equalshashCode 判断对象相等

    • 可使用模式匹配实现 equals
    • equals 参数类型为 Any 而不是具体的类型
    • ##hashCode 的安全版本,遇到 null 会返回 0 而不是抛出异常
  • 值类 Value Class

    • 继承 AnyVal
    • 主构造器只有一个参数 val,无构造体
    • 无其他构造器和字段
    • 自动提供的 equalshashCode 比较实际值
    • 用于隐式转换
      • 其他用途,如 class a(x: Int, y: Int) 设计为 class a(x: X, y: Y) ,定义值类 X, Y 避免混淆参数
C:\Users\50125\PycharmProjects\pythonProject1\.venv\Scripts\python.exe E:\Heart-disease-analysis-main\pre\app.py Warning: Ignoring non-Spark config property: hive.metastore.uris 25/04/29 16:07:34 ERROR UserGroupInformation: Unable to find JAAS classes:com.ibm.security.auth.UsernamePrincipal Exception in thread "main" org.apache.hadoop.security.KerberosAuthException: failure to login: javax.security.auth.login.LoginException: No LoginModule found for com.ibm.security.auth.module.Win64LoginModule at org.apache.hadoop.security.UserGroupInformation.doSubjectLogin(UserGroupInformation.java:1847) at org.apache.hadoop.security.UserGroupInformation.createLoginUser(UserGroupInformation.java:710) at org.apache.hadoop.security.UserGroupInformation.getLoginUser(UserGroupInformation.java:660) at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:571) at org.apache.spark.util.Utils$.$anonfun$getCurrentUserName$1(Utils.scala:2414) at scala.Option.getOrElse(Option.scala:189) at org.apache.spark.util.Utils$.getCurrentUserName(Utils.scala:2414) at org.apache.spark.SecurityManager.<init>(SecurityManager.scala:79) at org.apache.spark.deploy.SparkSubmit.secMgr$lzycompute$1(SparkSubmit.scala:368) at org.apache.spark.deploy.SparkSubmit.secMgr$1(SparkSubmit.scala:368) at org.apache.spark.deploy.SparkSubmit.$anonfun$prepareSubmitEnvironment$8(SparkSubmit.scala:376) at scala.Option.map(Option.scala:230) at org.apache.spark.deploy.SparkSubmit.prepareSubmitEnvironment(SparkSubmit.scala:376) at org.apache.spark.deploy.SparkSubmit.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:871) at org.apache.spark.deploy.SparkSubmit.doRunMain$1(SparkSubmit.scala:180) at org.apache.spark.deploy.SparkSubmit.submit(SparkSubmit.scala:203) at org.apache.spark.deploy.SparkSubmit.doSubmit(SparkSubmit.scala:90) at org.apache.spark.deploy.SparkSubmit$$anon$2.doSubmit(SparkSubmit.scala:1007) at org.apache.spark.deploy.SparkSubmit$.main(SparkSubm
最新发布
04-30
<think>好的,我现在需要帮助用户解决Spark提交时遇到的JAAS类未找到和Kerberos身份验证失败的问题。首先,我得理清用户的问题描述,然后结合我现有的知识以及用户提供的引用内容,找到可能的解决方案。 用户提到的错误有两个:一个是No LoginModule found for com.ibm.security.auth.module.Win64LoginModule,另一个是KerberosAuthException。首先,Win64LoginModule这个模块属于IBM的特定实现,可能用户的环境里没有正确配置或缺少相关依赖。而Kerberos身份验证失败可能与JAAS配置、keytab文件或Hive Metastore的连接有关。 接下来,我需要参考用户提供的引用内容。例如,引用[2]中提到了ZooKeeper的SASL配置和JAAS文件,这可能涉及到如何正确设置JAAS配置文件,特别是与Kerberos相关的部分。引用[4]提到了Hive连接的URL中可能存在空格问题,这可能提示用户检查配置中的拼写错误或多余字符。 首先,JAAS配置问题。Spark在启用Kerberos时需要正确配置JAAS文件,指定使用正确的LoginModule。用户遇到的Win64LoginModule未找到可能是因为在非Windows环境或未安装IBM相关安全模块的情况下尝试使用它。解决方案应该是改用标准的Krb5LoginModule,比如将JAAS配置文件中的相关条目改为使用com.sun.security.auth.module.Krb5LoginModule。 然后,检查spark-submit命令中是否正确指定了JAAS文件的位置,通过--conf spark.executor.extraJavaOptions和--conf spark.driver.extraJavaOptions参数来传递Java选项,确保路径正确,并且文件权限适当。 其次,Kerberos身份验证失败可能涉及多个方面。需要确认用户是否已经通过kinit成功获取了TGT,或者是否正确指定了keytab文件。例如,在Spark配置中,应设置spark.kerberos.keytab和spark.kerberos.principal,确保keytab文件路径正确,并且principal名称无误。 另外,Hive Metastore的连接问题也可能导致身份验证失败。用户需要检查hive.metastore.uris是否正确配置,确保Hive Metastore服务已经启动并且Kerberos保护良好。引用[4]提到URL中的空格问题,用户需要检查连接字符串是否有拼写错误或多余的空格。 用户提供的引用[3]中提到了HDFS的JMX配置,虽然可能与当前问题关联不大,但需要注意环境变量是否正确设置,避免其他配置干扰。 可能还需要检查Kerberos配置文件(krb5.conf)是否正确,确保KDC服务器地址和域名配置正确。同时,确保所有节点的时钟同步,因为Kerberos对时间同步非常敏感。 最后,用户可能需要查看详细的调试日志,通过设置Spark的日志级别为DEBUG来获取更多信息,帮助定位问题根源。例如,在spark-submit中添加--verbose选项,或者在log4j.properties中调整日志级别。 总结步骤应该是:1. 修改JAAS配置使用正确的LoginModule;2. 确保Spark配置中正确指定keytab和principal;3. 检查Hive Metastore URI和Kerberos配置;4. 验证Kerberos票据和网络连通性;5. 查看日志进行详细错误分析。 在回答时,需要结构清晰,分步骤说明解决方案,并引用相关的引用内容作为支持。同时,生成相关问题,帮助用户进一步排查可能的问题点。</think>### Spark提交时JAAS类未找到及Kerberos身份验证失败解决方案 #### 一、JAAS类未找到问题分析 1. **错误原因** `No LoginModule found for com.ibm.security.auth.module.Win64LoginModule` 表示Spark尝试使用IBM特定的安全模块,但当前环境未配置该模块。通常应使用Java标准Kerberos模块 `Krb5LoginModule`[^2]。 2. **解决方案** - **修改JAAS配置文件**: 将`jaas.conf`中`Client`段的`LoginModule`替换为Java标准实现: ``` Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/path/to/user.keytab" principal="user@REALM"; }; ``` - **指定JAAS路径**: 在`spark-submit`中添加配置参数: ```bash --conf spark.executor.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" \ --conf spark.driver.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" ``` - **检查文件权限**:确保`jaas.conf`和`keytab`文件对Spark进程可读。 #### 二、Kerberos身份验证失败问题分析 1. **常见错误场景** - Kerberos票据未初始化(未执行`kinit`或`keytab`配置错误) - Hive Metastore URI配置错误或服务不可达 - 网络问题或时间不同步 2. **解决方案** - **初始化Kerberos票据**: 手动执行`kinit`或通过Spark配置自动获取: ```bash --conf spark.kerberos.keytab="/path/to/user.keytab" \ --conf spark.kerberos.principal="user@REALM" ``` - **检查Hive Metastore配置**: 确保`hive.metastore.uris`指向正确的服务地址,并验证URI格式(注意避免多余空格)[^4]: ```sql thrift://metastore-host:9083 ``` - **验证Kerberos配置**: - 检查`/etc/krb5.conf`中的`realm`和`kdc`配置 - 使用`telnet`或`nc`验证Hive Metastore端口连通性 - 确保所有节点时间同步(NTP服务) #### 三、综合配置示例 1. **完整`spark-submit`命令** ```bash spark-submit \ --master yarn \ --deploy-mode cluster \ --keytab "/path/to/user.keytab" \ --principal "user@REALM" \ --conf spark.hadoop.hive.metastore.uris="thrift://metastore-host:9083" \ --conf spark.executor.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" \ --conf spark.driver.extraJavaOptions="-Djava.security.auth.login.config=/path/to/jaas.conf" \ --class com.example.MainApp \ /path/to/application.jar ``` 2. **调试日志启用** 在`log4j.properties`中添加: ``` log4j.logger.org.apache.hadoop.security=DEBUG log4j.logatorg.apache.spark=DEBUG ``` #### 四、注意事项 1. 若使用ZooKeeper,需同步检查SASL配置(如`quorum.auth.enableSasl`)[^2] 2. Windows环境下需替换路径分隔符(`\` → `/`) 3. Kerberos票据有效期需大于作业运行时间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值