关于java动态加载jar的问题?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于java动态加载jar的问题?相关的知识,希望对你有一定的参考价值。

我做了一个java动态加载jar包的功能,我现在是不停止tomcat服务,而是停止调用jar包,然后我更新一下这个jar包,(注:此时这个jar的代码已经是改变过的,有新的功能),更新完我继续调用这个jar包的对象,但是,我动态加载过来的对象还是原先的那个对象,并没有我新加的功能,除非重新启动tomcat服务才可以,我现在不能想停止tomcat服务达到更新的效果,那个大哥会做啊?小弟在此先谢过了!

设我们有一个hello.jar文件,里面有一个Util类,我们希望在运行期调将这个jar包放入到我们运行环境并且调用里面的Util.getVersion方法。怎么实现?
在java中,我们的类都是通过ClassLoader来加载的,同时ClassLoader具有层级关系,当某个类找不到时,它会去他的父类加载器去寻找,如果依然找不到,就抛出ClassNotFoundException了。
为了动态加载hello.jar里面的Util类,我们需要将这个jar包放入到我们的类加载器中去,然后再获取里面的类。如下面的代码。

// 位于hello.jar
package com.flyingzl;

public class Util

public static void getVersion()

System.out.println("java version: " + System.getProperty("java.version"));




import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class Main
public static void main(String[] args)

URL[] urls = new URL[] ;
MyClassLoader classLoader = new MyClassLoader(urls, null);

try
classLoader.addJar(new File("c:/hello.jar").toURI().toURL());
Class<?> clazz = classLoader.loadClass("com.flyingzl.Util");
Method method = clazz.getDeclaredMethod("getVersion");
method.invoke(null);
classLoader.close();
catch (Exception e)
e.printStackTrace();




static class MyClassLoader extends URLClassLoader

public MyClassLoader(URL[] urls)
super(urls);


public MyClassLoader(URL[] urls, ClassLoader parent)
super(urls, parent);


public void addJar(URL url)
this.addURL(url);






注意:这里仅仅是为了展示如何动态加载jar包,代码写得很粗,生产代码需要有更完善的异常处理。我们只关心如何动态加载jar包即可。
动态加载jar包,需要用到java.net.URLClassLoader这个类,它可以指定一个路径将jar包或者classes文件加载到类空间。加载完毕后,直接调用loadClass就可以加载指定的类,然后通过反射生成实例或者调用方法即可。
其实,Tomcat等服务器也利用了此思路,比如每一个web应用启动时,它都会自动加载其下的lib文件夹下的jar包。
运行程序,我们就可以看到程序正常输出:
java version: 1.7.0_03追问

非常感谢你!我能做到动态加载了,只是,当我在jar包中加入新的功能后打成jar包,然后替换掉旧的jar包,但是,程序加载的还是原先旧的jar包内容,我想问问这是怎么回事,我应该在哪里找问题的原因?谢谢您!

追答

查看附件,希望能够帮助你,字数多,百度提示字数限制,抱歉。

参考技术A 好问题。好问题。好问题。好问题。追问

你是来围观的吗?好问题,你到时回答一下啊

追答

恩,我也是想知道答案的人。

Java动态加载类

【中文标题】Java动态加载类【英文标题】:Java Dynamically Loading a class 【发布时间】:2011-04-04 14:10:43 【问题描述】:

我正在尝试将类动态加载到组件中。我正在使用文件选择器来选择将要加载的 .JAR 文件,然后使用选项窗格来获取类的名称。

我在网上搜索了如何将 java 文件转换为 URL 以便在 URLClassLoader 中加载它,我想出了:

File myFile = filechooser.getSelectedFile();
String className = JOptionPane.showInputDialog(
    this, "Class Name:", "Class Name", JOptionPane.QUESTION_MESSAGE);

URL myUrl= null;
try 
    myUrl = myFile.toURL();
 catch (MalformedURLException e) 


URLClassLoader loader = new URLClassLoader(myUrl);
loader.loadClass(className);

我现在在将 URL 加载到 URLClassLoader 时遇到“找不到符号”错误

【问题讨论】:

是一个词吗?谷歌唯一建议的是“被控制”:-) urbandictionary.com/define.php?term=trolled @seanizer: “trawled”——作为搜索的一部分进行筛选。 @trashgod 听起来好多了... 相关:Adding files to java classpath at runtime 【参考方案1】:

URLClassLoadertakes an array of URLs的构造函数,不是单个URL。

【讨论】:

【参考方案2】:

看看这个相关的问题:How should I load Jars dynamically at runtime?

【讨论】:

【参考方案3】:

ClassPathHacker.java 在this forum thread 中找到,是一个动态加载类的选项。

import java.lang.reflect.*;
import java.io.*;
import java.net.*;


public class ClassPathHacker 

private static final Class[] parameters = new Class[]URL.class;

public static void addFile(String s) throws IOException 
    File f = new File(s);
    addFile(f);
//end method

public static void addFile(File f) throws IOException 
    addURL(f.toURL());
//end method


public static void addURL(URL u) throws IOException 

    URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
    Class sysclass = URLClassLoader.class;

    try 
        Method method = sysclass.getDeclaredMethod("addURL",parameters);
        method.setAccessible(true);
        method.invoke(sysloader,new Object[] u );
     catch (Throwable t) 
        t.printStackTrace();
        throw new IOException("Error, could not add URL to system classloader");
    //end try catch

//end method

//end class

【讨论】:

【参考方案4】:

我喜欢the answer by Zellus 中提到的 ClassPathHacker 类,但它充满了不推荐使用的调用和不良做法,所以这里有一个重写版本,它还缓存了 Classloader 和 addUrl 方法:

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.IOException;
import java.io.File;

public class ClassPathHacker

    private static final Class<URLClassLoader> URLCLASSLOADER =
        URLClassLoader.class;
    private static final Class<?>[] PARAMS = new Class[]  URL.class ;

    public static void addFile(final String s) throws IOException
        addFile(new File(s));
    

    public static void addFile(final File f) throws IOException
        addURL(f.toURI().toURL());
    

    public static void addURL(final URL u) throws IOException

        final URLClassLoader urlClassLoader = getUrlClassLoader();

        try
            final Method method = getAddUrlMethod();
            method.setAccessible(true);
            method.invoke(urlClassLoader, new Object[]  u );
         catch(final Exception e)
            throw new IOException(
                "Error, could not add URL to system classloader");
        

    

    private static Method getAddUrlMethod()
        throws NoSuchMethodException
        if(addUrlMethod == null)
            addUrlMethod =
                URLCLASSLOADER.getDeclaredMethod("addURL", PARAMS);
        
        return addUrlMethod;
    

    private static URLClassLoader urlClassLoader;
    private static Method addUrlMethod;

    private static URLClassLoader getUrlClassLoader()
        if(urlClassLoader == null)
            final ClassLoader sysloader = 
                ClassLoader.getSystemClassLoader();
            if(sysloader instanceof URLClassLoader)
                urlClassLoader = (URLClassLoader) sysloader;
             else
                throw new IllegalStateException(
                    "Not an UrlClassLoader: "
                    + sysloader);
            
        
        return urlClassLoader;
    


【讨论】:

【参考方案5】:

我在 scala 中重写了这个,以防万一有人需要,因为它不是 100% 微不足道的 :)

/*
 * Class which allows URLS to be "dynamically" added to system class loader
 */
object class_path_updater 
  val URLCLASSLOADER = classOf[URLClassLoader]

  var urlClassLoader = getUrlClassLoader
  var addUrlMethod = getAddUrlMethod

  /*
   * addFile - have to use reflection to retrieve and call class loader addURL method as it is protected
  */
  def addFile(s: String) = 
    val urlClassLoader = getUrlClassLoader
    try 
      val method = getAddUrlMethod
      method.setAccessible(true)
      val v = (new File(s)).toURI.toURL
      invoke(urlClassLoader, method, Array[AnyRef](v))
      def invoke(proxy: AnyRef, m: Method, args: Array[AnyRef]) = m.invoke(proxy, args: _*)
    

  

  private def getAddUrlMethod: Method = 
    if (addUrlMethod == null) addUrlMethod = URLCLASSLOADER.getDeclaredMethod("addURL", classOf[URL])
    addUrlMethod
  

  private def getUrlClassLoader: URLClassLoader = 
    if (urlClassLoader == null) 
      val sysLoader = ClassLoader.getSystemClassLoader
      sysLoader match 
        case x: URLClassLoader => urlClassLoader = sysLoader.asInstanceOf[URLClassLoader]
        case _ => throw new IllegalStateException("Not a UrlClassLoader: " + sysLoader)
      
    
    urlClassLoader
  

【讨论】:

以上是关于关于java动态加载jar的问题?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA怎么动态加载JAR包

Java动态加载JAR包

Java 动态加载jar和class文件

Java_Java中动态加载jar文件和class文件

寻找在动态加载 Jar 文件和在 Java 运行时实例化类时使用 Apache Felix 的基本示例

JAVA如何动态加载jar,并调用对应的函数?