前两天在整理一个工程的时候突发奇想,能不能把需要的jar都打到一个类似于war包的jar包里面去,但是不解开原始jar包,而是将之统一放到外面jar包中的一个lib目录下。 按这个思路试了好几次,都遇到了NoClassDefFoundError。一开始以为是manifest中配置有误,在几次尝试调整manifest文件仍然失败之后,觉得有必要查看一些类似的案例。 类似的案例比如SpringBoot工程打成的jar包,又比如jenkins的可以直接用jar命令调用的war包。找到相关的包分析了许久,仍然找不到端倪。 后来在Oracle的官方文档中找到了解释: To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar’s manifest to load classes in MyUtils.jar into the class path. 懒得翻译了,大意就是如果要引用jar中的jar,就需要编写额外的代码,如自定义的类加载器。SpringBoot打成的包就是这样做的。 参考文档:https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html #######
[阅读更多...]-
jar包中的jar
-
Gradle中的“provided”
maven中值为provided的scope,可以让我们声明一个只在编译时使用的非传递性的依赖。在gradle中我们可以声明compileOnly依赖来实现类似的效果(需要java插件)。示例如下: compileOnly声明的使用场景可以一言蔽之:声明的依赖只在compile阶段使用,但是不会在runtime阶段用到,并且这种依赖也是非传递性的。 ######
[阅读更多...] -
Gradle依赖排除
在引用依赖时经常会有这样的问题:某些间接引用的依赖项是不需要的;产生了依赖冲突。此时需要排除一些依赖。 下面的内容介绍了几种在gradle中排除依赖的方式。 在dependency中排除 这种方式是粒度最细的,也是最为繁琐的。此时可以考虑全局设置。 在全局配置中排除 全局配置是在configuration中完成的。 禁用传递依赖 禁用传递依赖需要将属性transitive设置为false。可以在dependency中禁用传递依赖,也可以在configuration中全局禁用: 还可以在单个依赖项中使用@jar标识符忽略传递依赖: 强制使用某个版本 如果某个依赖项是必需的,而又存在依赖冲突时,此时没必要逐个进行排除,可以使用force属性标识需要进行依赖统一。当然这也是可以全局配置的: 在打包时排除依赖 先看一个示例: 代码表示在打zip包的时候会过滤掉名称中包含“unwanted”和“log”的jar包。这里调用的exclude方法的参数和前面的例子不太一样,前面的参数多是map结构,这里则是一个正则表达式字符串。 也可以使用在打包时调用include方法选择只打包某些需要的依赖项: 始终选择最新的依赖的项 最后这个特性和排除依赖没有什么关系,只是顺带说一下。 在依赖项中使用加号+,可以在构建时检查远程仓库是否存在该依赖的新版本,如果存在新版本则下载选用最新版本。更有用的是可以指定依赖某个大版本下的最新子版本,如1.+表示始终采用依赖的1.x序列的最新版本。 示例如下: 就这样。 #####
[阅读更多...] -
spark使用kafka报NoSuchMethodError
运行spark任务消费kafka时,报了如下的异常: 使用的spark版本是1.6.1,kafka版本是0.8.2.1。 根据异常信息猜测应该是scala版本导致的问题。 查看了一下依赖的spark和kafka的配置为: 依赖项直接copy自mvnrepository网站。 使用gradle dependencies指令查看了依赖详情:kafka依赖的scala的版本是2.11.5,spark依赖的scala版本是2.11.6。而spark集群服务器部署的scala版本是2.11.8。 照说都是在2.11.*范围内,不应该报错的。 反复测试了几次之后忽然想到spark集群使用的scala版本也许不是2.11.8,也就是说spark集群的scala版本和服务器scala环境的版本也许不一致,我之前的意识是错误的。 需要测试一下,依稀有些印象可以使用2.10.4版本的scala进行编译,所以得先把依赖调整一下: kafka和spark依赖的name后面的数字,如“kafka_2.10”中的2.10指的是采用scala 2.10.*编译打包的。 打包上传后,测试通过,不再报那个异常了。 该如何确认spark集群使用的scala的版本呢。第一个思路是看spark集群lib目录下的依赖是不是会有相关的提示。看了一下比较失望: 就这么几个包,一点儿信息都没有。 不死心,用vi查看了一下。在spark-1.6.1-yarn-shuffle.jar的DEPENDENCIES文件中找到些许证明: 提示了spark-network-common_2.10是用scala 2.10编译的。 又查了一些资料,可以简单进行判断: 如果是spark1,用的scala版本通常是2.10,spark2则通常对应2.11版的scala。 就这样。 ########
[阅读更多...]