`
zengshaotao
  • 浏览: 777752 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

self define classloader

    博客分类:
  • java
 
阅读更多
大家都知道一个java应用项目可以打包成一个jar,当然你必须指定一个拥有main函数的main class作为你这个jar包的程序入口。

具体的方法是修改jar包内目录META-INF下的MANIFEST.MF文件。

比如有个叫做test.jar的jar包,里面有一个拥有main函数的main class:test.someClassName
我们就只要在MANIFEST.MF里面添加如下一句话:
Main-Class: test.someClassName

然后我们可以在控制台里输入java -jar  test.jar即可以运行这个jar。

但是我们这个项目需要引用其他第三方的jar包,在eclipse里面以项目jar包的形式引用了这个叫做some.jar的包,当时放在项目的lib子目录下,最后项目打包时把这个some.jar也打进来了,但是用java -jar执行这个test.jar的时候报找不到Class异常,原因就是jar引用不到放在自己内部的jar包。

那怎么办?

运行时将其加入classpath的方式行不行?就是在运行jar的同时加入classpath参数:
java -classpath some.jar  -jar test.jar

这种方式是不行的,因为使用classpath指定的jar是由AppClassloader来加载,java 命令 加了-jar 参数以后,AppClassloader就只关注test.jar范围内的class了,classpath参数失效。

那该怎么引用其他的jar包呢?

方法一、使用Bootstrap Classloader来加载这些类。

我们可以在运行时使用如下参数:

-Xbootclasspath:完全取代系统Java classpath.最好不用。
-Xbootclasspath/a: 在系统class加载后加载。一般用这个。
-Xbootclasspath/p: 在系统class加载前加载,注意使用,和系统类冲突就不好了.
win32     java -Xbootclasspath/a: some.jar;some2.jar;  -jar test.jar
unix          java -Xbootclasspath/a: some.jar:some2.jar:  -jar test.jar
win32系统每个jar用分号隔开,unix系统下用冒号隔开



方法二、使用Extension Classloader来加载

你可以把需要加载的jar都扔到%JRE_HOME%/lib/ext下面,这个目录下的jar包会在Bootstrap Classloader工作完后由Extension Classloader来加载。非常方便,非常省心。:)



方法三、还是用AppClassloader来加载,不过不需要classpath参数了

我们在MANIFEST.MF中添加如下代码:
Class-Path: lib/some.jar

lib是和test.jar同目录的一个子目录,test.jar要引用的some.jar包就在这里面。
然后测试运行,一切正常!

如果有多个jar包需要引用的情况:
Class-Path: lib/some.jar lib/some2.jar
每个单独的jar用空格隔开就可以了。注意使用相对路径。

另:如果META-INF 下包含INDEX.LIST文件的话,可能会使Class-Path配置失效。INDEX.LIST是Jar打包工具打包时生成的索引文件,删除对运行不产生影响。


方法四、自定义Classloader来加载
这种方法是终极解决方案,基本上那些知名java应用都是那么干的,如tomcat、jboss等等。
这种方式有点复杂,需要专门开贴讨论。关于ClassLoader的原理和自定义ClassLoader可以参考这篇  http://longdick.iteye.com/blog/442213。


总结:
以上四种方法都可以用,特别是程序运行在非常单纯的环境中时。但是,如果是运行在多任务,多应用的环境中时,最好每个应用都能相互独立,第一种和第二种方案都有可能对其他应用产生影响,因此最好就是选择第三种和第四种。
分享到:
评论

相关推荐

    USR-C21x-webpage-self-define.rar

    这个"USR-C21x-webpage-self-define.rar"压缩包文件提供了自定义该模块Web界面的工具和资源,使得用户可以根据自己的需求来定制模块的网页交互功能,提升设备的用户友好性和功能扩展性。 在物联网设备中,Wi-Fi模块...

    UDF 动网格,DEFINE-CG-MOTION,DEFINE-GRID-MOTION

    `DEFINE_CG_MOTION`和`DEFINE_GRID_MOTION`是UDF编程中用于定义网格运动的两个关键函数。它们是ANSYS Fluent内建的宏,用于在UDF中指定网格如何随时间变化。 1. `DEFINE_CG_MOTION`:这个宏主要用于定义中心点...

    #define——用法大全

    关于 #define 指令的用法大全 #define 指令是 C 语言中的一种预处理指令,用于给常量赋予一个有意义的名称。在本文中,我们将详细介绍 #define 指令的用法、实例和注意事项。 定义 ---- #define 指令的基本语法有...

    FLUENT UDFs 金属材料属性udf,表面张力、DEFINE-PROTERTY、DEFINE-SPECIFIC-HEAT

    标题中的"FLUENT UDFs 金属材料属性udf,表面张力、DEFINE-PROPERTY、DEFINE-SPECIFIC-HEAT"涉及了UDFs在模拟金属材料特性的应用,特别是关于不锈钢的热力学性质。 首先,我们来看`DEFINE-PROPERTY`和`DEFINE-...

    Define_Grid_Motion.zip_DEFINE_GRID_MOTION_fluent udf_fluent变形_f

    标题中的"Define_Grid_Motion.zip_DEFINE_GRID_MOTION_fluent udf_fluent变形_f" 提到了`Fluent`中的`Define Grid Motion`功能,这正是用来定义网格运动的一种方法,它允许用户自定义边界条件下的网格动态行为。...

    define用法完全集锦

    ### #define用法完全集锦 #### 一、概述 `#define` 是 C/C++ 预处理器指令中非常重要的一部分,它允许开发者为程序中的常量赋予有意义的名字,简化了代码的阅读与维护。本文将详细介绍 `#define` 的各种用法及其...

    define用法以及.doc

    `#define`是C/C++预处理器中的一个指令,用于创建宏定义,它可以在编译期间替换特定的文本。下面是对`#define`用法及其与`typedef`区别的详细解释: 1. **简单的宏定义**: `#define`常用于定义常量,如`#define ...

    DEFINE_DPM_EROSION.rar_DEFINE DPM EROSION_DPM_UDF EROSION_fluent

    标题中的"DEFINE_DPM_EROSION.rar_DEFINE DPM EROSION_DPM_UDF EROSION_fluent"指的是一款与 Fluent 模拟软件相关的用户定义函数(UDF),用于模拟颗粒动力学(DPM)过程中的侵蚀现象。Fluent 是一款广泛使用的计算...

    define与typedef 区别

    `#define` 和 `typedef` 是 C/C++ 语言中两种不同的类型定义方式,它们各自有不同的特性和用途。 首先,`#define` 是预处理器指令,它的主要功能是在编译之前进行文本替换。这意味着,当你在代码中使用 `#define` ...

    define使用

    ### Define 使用详解与案例分析 在程序开发过程中,`#define` 是一个非常常见的预处理器指令,被广泛应用于多种编程语言之中,尤其是在 C 和 C++ 语言中。本文将从多个方面详细介绍 `#define` 的使用方法,并通过...

    typedef与define的区别

    typedef与define的区别 在C/C++语言中,typedef和define是两个常用的关键字,虽然它们都可以用来定义别名,但是它们的用法和特点却有很大的区别。 一、typedef的用法 typedef是C/C++语言中的一个关键字,用于定义...

    const #define inline

    ### const、#define与inline详解及其应用场景 在编程领域,`const`、`#define`与`inline`是三个常用的关键字或预处理器指令,它们各自具有独特的作用和使用场景,掌握它们的区别和正确应用是提升代码质量和效率的...

    #define 问题 用法陷阱

    ### #define 问题 用法陷阱 在C语言编程中,`#define`是一个非常强大的预处理器指令,它被广泛用于定义宏、常量或简化的类型声明等。然而,`#define`的不当使用可能会引入一系列的问题和陷阱,本文将深入探讨这些...

    第四章 DEFINE宏_UDf宏_UDFdescription_

    "第四章 DEFINE宏_UDf宏_UDFdescription_"这一标题暗示了我们将会探讨Fluent中的用户定义函数(User-Defined Functions,简称UDFs)以及与其相关的DEFINE宏。在Fluent中,UDFs允许用户自定义物理模型,以处理标准...

    宏(#define)定义函数妙用

    在C/C++编程中,宏定义(#define)是一种预处理器指令,用于创建符号常量或简单的文本替换。宏在程序编译时起作用,它不是真正的函数,但可以通过模拟函数调用来实现类似的功能,从而提高代码的可读性和可维护性。在...

    C++/C 宏定义(define)中# ## 的含义

    ### C++/C宏定义(define)中#与##的含义及应用 #### 一、引言 在C++和C语言中,预处理器指令`#define`被广泛用于定义宏,这些宏可以包含简单的替换文本,也可以进行复杂的条件判断和参数处理。本文将详细介绍宏...

    php中const与define的区别 具体归纳详细介绍

    define('MY_CONDITIONAL_DEFINE', 'Conditional Define'); // Valid } ``` #### 4. 常量名称 - **`const`**: 只能使用简单的常量名称。 ```php const MY_SIMPLE_CONST = 'Simple Const'; ``` - **`define...

    #define的使用技巧

    在C语言中,宏定义是使用预处理器指令#define实现的一种编译前文本替换机制。它在编译之前处理源代码,使得可以定义常量、实现内联函数以及防止头文件被重复包含等多种功能。下面详细说明标题和描述中提到的知识点。...

    define与typedef

    ### define与typedef详解 在C语言编程中,`define`和`typedef`是两种非常重要的预处理器指令和关键字,它们各自具有独特的用途和优势。本文将深入探讨`define`与`typedef`的区别,以及为什么在某些情况下应优先选择...

Global site tag (gtag.js) - Google Analytics