Maison  >  Questions et réponses  >  le corps du texte

在java spring中,是否可以动态将一个新的class加载到beanFactory中?

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

阿神阿神2719 Il y a quelques jours457

répondre à tous(5)je répondrai

  • PHPz

    PHPz2017-04-18 10:28:24

    Après JDK1.5, il existe une API java.lang.instrument.Instrumentation prête à l'emploi pour implémenter cette fonction.

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

    L'interface ci-dessus peut redéfinir le class existant.
    Utilisez comme ci-dessous.

    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);
                }
            }
        }
    }

    Méthode pour obtenir un Instrumentation objet :

    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.jarVous devez spécifier Agent-Class lors de l'emballage et Can-Redefine-Classes activer la fonction de réécriture de classe.

    <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.javaMise en œuvre

    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()});
        }
    }

    Ici, j'ai injecté l'objet JMX à travers Instrumentation. Pourquoi l'ai-je fait de cette façon ?
    est dû au fait que l'environnement dans lequel vm.loadAgent(); s'exécute est nouveau et que je ne peux pas utiliser de méthodes statiques pour définir les propriétés. Bien que les classes soient les mêmes, le ClassLoader qui charge la classe est incohérent. Plus tard, j'ai essayé de l'appeler en utilisant JMX.

    D'accord, tant que vous obtenez l'objet Instrumentation, vous pouvez faire tout ce que vous ne pouviez pas faire auparavant.

    répondre
    0
  • PHP中文网

    PHP中文网2017-04-18 10:28:24

    Essayez d'obtenir l'AutowireCapableBeanFactory via ApplicationContext, puis appelez la méthode createBean() ou autowire() pour injecter

    répondre
    0
  • 怪我咯

    怪我咯2017-04-18 10:28:24

    Java a des flux d'entrée et de sortie d'objets, vous pouvez donc certainement stocker des objets en octets

    répondre
    0
  • 阿神

    阿神2017-04-18 10:28:24

    Tout ce qui est mentionné ci-dessus est faux. Je peux vous dire clairement que tout est possible.

    répondre
    0
  • 怪我咯

    怪我咯2017-04-18 10:28:24

    marquer pour apprendre

    répondre
    0
  • Annulerrépondre