在java spring中,是否可以动态将一个新的class加载到beanFactory中?
阿神
阿神 2017-04-18 10:26:24
0
5
485

在java spring中,是否可以动态将一个新的class加载到beanFactory中?是否可以将class类以字节流的方式存到redis中,再由类加载器重新加载到java运行实例中?
目前项目中有一个需求,需要可以动态地加载类到spring的beanFactory中或者说applicationContext里面,这个类是可以由开发人员动态上传到生产环境中,而无需重新启动生产环境。请问是否可以做到呢?还有一个问题,是否可以将class文件以字节的方式暂存在redis中间件上,需要用这个class时,动态地加载它?

阿神
阿神

闭关修行中......

reply all(5)
PHPzhong

After JDK1.5, there is a ready-made API java.lang.instrument.Instrumentation to implement this function.

java.lang.instrument.Instrumentation.redefineClasses(ClassDefinition... definitions)

The above interface can redefine the existing oneclass.
Use as below.

private void redefineScripts(File dir) {
    File[] files = dir.listFiles();
    for (File f : files) {
        if (f.isDirectory()) {
            redefineScripts(f);
        } else if (f.getName().endsWith(".class")) {
            String name = getScriptCanonicalName(f);
            String path = name.replaceAll("\.", "/");
            File target = new File(targetDir, path + ".class");

            try {
                InputStream in = new FileInputStream(target);
                byte[] buf = StreamUtils.copyToByteArray(in);
                ClassDefinition cdef = new ClassDefinition(scriptClassLoader.loadClass(name), buf);
                instrumentation.redefineClasses(cdef);
            } catch (Exception ex) {
                throw new ScriptException(ex);
            }
        }
    }
}

Method to get Instrumentationobject:

private void loadAgent() {
    try {
        String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
        VirtualMachine vm = VirtualMachine.attach(pid);
        vm.loadAgent("<jar file>", OBJECT_NAME.toString());
        vm.detach();
    } catch (Exception ex) {
        throw new RuntimeException(
                "无法加载代理JAR文件["
                + Typhons.getProperty(Constants.AGENT_JAR_PATH) + "]", ex);
    }
}

agent.jar打包时需要指定Agent-ClassCan-Redefine-ClassesEnable class rewriting function.

<plugin>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
            </manifest>
            <manifestEntries>
                <Agent-Class>org.skfiy.typhon.agent.Agent</Agent-Class>
                <Can-Redefine-Classes>true</Can-Redefine-Classes>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Agent.java Realization

public class Agent {

    /**
     * 代理主函数入口. 通过传入的{@code str }{@code ObjectName }执行其{@code setInstrumentation }
     * 方法.
     * <p>
     * e.g.<pre>
     * public void setInstrumentation(Instrumentation instrumentation) {
     *  this.instrumentation = instrumentation;
     * }
     * </pre>
     * 
     * @param str 一个{@link ObjectName }字符串
     * @param inst {@link Instrumentation }实现
     * @throws Exception 异常
     */
    public static void agentmain(String str, Instrumentation inst) throws Exception {
        ObjectName objectName = ObjectName.getInstance(str);
        MBeanServer mbeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
        mbeanServer.invoke(objectName, "setInstrumentation",
                new Object[]{inst},
                new String[]{Instrumentation.class.getName()});
    }
}

Here I injected the JMXInstrumentation对象注入过去的,当时为什么要这样来做呢。
是因为vm.loadAgent();运行的环境是一个全新的,我无法使用静态方法来设置属性,虽然类相同但是加载该个类的ClassLoader却不一致。后面我尝试出可以使用JMX object through JMX. Why did I do it this way?

It’s because the running environment of vm.loadAgent(); is a brand new one, and I cannot use static methods to set properties. Although the classes are the same, the ClassLoader is inconsistent. Later I tried to call it using JMX.

InstrumentationOkay, as long as you get the

object, you can do anything you couldn't do before. 🎜
Ty80

Try to get the AutowireCapableBeanFactory through ApplicationContext, and then call the createBean() or autowire() method to inject it

刘奇

Java has object input and output streams, so you can definitely store objects in bytes

阿神

None of what is said above is correct. I can tell you clearly that everything is possible.

刘奇

mark to learn

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template