`
yfyh87
  • 浏览: 35175 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

谁动了他的jar包 (一)

阅读更多
哈,你想改变jar包某个类的运行方式?

或是因为业务需要,或是因为这个jar暂时不能满足你你欲望...

或者只是for Fun!

但是你无法改变这个jar包,可能因为是公用的,可能因为产品的生成依赖于标准仓库,或者仅仅是你不想用 "编译一下你的java类,然后把你的.class替换进去" 这么...这么..这么...的方法,那你要怎么做?


例如:
有类 Feature
public class Feature {

    private String content;

    public void show() {
        System.out.println(this.content);
    }
}


及类 Function
public class Function {

    private Feature f;

    public void show() {
        this.f.show();
    }
    
}


测试类 Test,运行结果为 null . 而你想让他输出hello kitty
public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Function function = new Function();
        function.show();
    }

}



最先想到的方法是就是直接建一个同包同名类,在你的eclipse或者其它编译环境下;然后把相关方法,改成自己想要的方法;如下:

public class Feature {

    private String content;

    public Feature(){
        this.content = "hello kitty";
    }

    public void show() {
        System.out.println(this.content);
    }
}



然后,你会发现,使用的是你的class吖,而不是jar包里的吖.
但是,如果你的程序也打成jar包,和原jar一起运跑,会是什么情况呢;
你可能发现,会输出 空,如果运气好,也可能 输出 hello kitty ;

为啥呢? 因为当有同包同名类时,classLoader总会尝试先加载到一个,而且加载到这个class文件后,后面就不会再加载;这个先加载到的类一般和classpath设置的先后有关;

在eclipse环境下,会先加载编辑器下的类,然后优先加载,先导入的类库;
如果先加载到你的类,那么就会输出 "hellokitty".

假如需要在生产环境指定加载你的类,
而且,
你无法预知客户如何设置classPath的先后顺序,那么,要怎么办呢?


可否自己写一个classLoader只加载目标类,而让你的调用程序在此classLoader环境下运行?

Let us try try : 先写出这个特别的classLoader

public class HoneyLoader extends URLClassLoader {

    public HoneyLoader(URL[] urls, ClassLoader parent){
        super(urls, parent);
    }

    public synchronized Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        if (c != null) {
            return c;
        }
//先自己在指定位置(通过urls指定)找,找不到交给父类
        try {
            c = this.findClass(name);
        } catch (Exception e) {
            c = super.loadClass(name);
        }
        return c;
    }
}


回到我们的测试类,修改如下

public class Test {

    public static void main(String[] args) throws Exception {
        // 根据jar包名称,获取我们需要的jar包的名称的url
        String jarName = "feature2.jar";
        URL url = null;

        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Enumeration<URL> urls = loader.getResources("Feature.class");
        int i = 0;
        while (urls.hasMoreElements()) {
            url = urls.nextElement();
            i = url.getPath().indexOf(jarName);
            if (i > -1) {
                break;
            }
        }

        // 用honeyLoader启动我们的运行环境
        ClassLoader myLoader = new HoneyLoader(new URL[] { new URL(url.getPath().substring(0, i) + jarName) }, loader);
        Object object = myLoader.loadClass("Feature").newInstance();
        object.getClass().getMethod("show").invoke(object);

    }


运行结果:
hello kitty


呵呵~ 成功了


---------------------------------------------------------

你能想到其它更简单的办法么?

谁动了你的jar包 (二)  http://ilab.iteye.com/blog/1002629
  之  通过反射动态改变类状态

谁动了你的jar包 (三) http://ilab.iteye.com/blog/1006423
  之  那个啥 jvmti !






6
2
分享到:
评论
4 楼 yfyh87 2011-04-20  
zhaohaolin 写道
请问楼主,javassist可以完成你的功能吧


是的javaasist也可以动态改变字节码,包括jvmti以及 bcel,asm 等等;

这里是借发挥,做一些有趣的实验HOHO~

希望在某些时候,在特定场景下,给予帮助


3 楼 zhaohaolin 2011-04-20  
请问楼主,javassist可以完成你的功能吧
2 楼 jasonsun1985 2011-04-19  
说错了2007+的时候
1 楼 jasonsun1985 2011-04-19  
提到类加载顺序问题,我做office2000和office2003+的时候也需要这样问题,搜索功能需要根据不同word附件来判断用哪个,这个很让人苦恼

相关推荐

Global site tag (gtag.js) - Google Analytics