我想在已经加载的运行时更改java类。这该怎么做?

时间:2017-04-27 09:09:21

标签: java javassist

首次成功创建类,但下次类中发生更改时(如添加一些变量)会抛出错误。 以下是我的代码。

ClassPool pool = ClassPool.getDefault();
        CtClass cc=null;
        final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        if (contextClassLoader != null)
        {
            pool.insertClassPath(new LoaderClassPath(contextClassLoader));
        }
        try{

            cc = pool.makeClass(className); 
            cc.defrost();
            for (Entry<String, Class<?>> entry : properties.entrySet()) {
                cc.addField(new CtField(resolveCtClass(entry.getValue()), entry.getKey(), cc));
                // add getter
                cc.addMethod(generateGetter(cc, entry.getKey(), entry.getValue()));
                // add setter
                cc.addMethod(generateSetter(cc, entry.getKey(), entry.getValue()));

            }
            cc.addConstructor(generateConstructor(cc,properties,className));
            CtConstructor defaultCons=new CtConstructor(NO_ARGS, cc);
            defaultCons.setBody(";");
            cc.addConstructor(defaultCons);
            return cc.toClass();
        }catch(Exception e){
            cc = pool.get(className);   
            cc.detach();
            cc = pool.makeClass(className); 
            cc.defrost();
            for (Entry<String, Class<?>> entry : properties.entrySet()) {
                cc.addField(new CtField(resolveCtClass(entry.getValue()), entry.getKey(), cc));
                // add getter
                cc.addMethod(generateGetter(cc, entry.getKey(), entry.getValue()));
                // add setter
                cc.addMethod(generateSetter(cc, entry.getKey(), entry.getValue()));

            }
            cc.addConstructor(generateConstructor(cc,properties,className));
            CtConstructor defaultCons=new CtConstructor(NO_ARGS, cc);
            defaultCons.setBody(";");
            cc.addConstructor(defaultCons);
            return **cc.toClass();** // getting error at this line
        }

2 个答案:

答案 0 :(得分:1)

简单回答:你不能(轻松)。

关键是:当类已经加载时,JVM已经有关于该类的信息。 “默认”类加载器根本不允许您使用新的替换该定义。

如果您想动态交换类定义,则必须转向编写允许此类内容的自己的类加载器的高级主题。请参阅here作为起点。

答案 1 :(得分:0)

您需要编写a Java agent并动态附加它以在类已经加载后对其进行转换。 Java代理定义了一个名为agentmain的方法,该方法将Instrumentation的实例作为其第二个参数。使用这样的Java代理,允许应用的更改仅限于更改方法的主体,不能添加成员(字段或方法)或更改现有的更改。

您致电Instrumentation::redefineClass以应用重新定义。

您可以在线上的几个地方find articles on how to change loaded code