【问题标题】:Reload class file in tomcat在tomcat中重新加载类文件
【发布时间】:2012-09-01 06:59:56
【问题描述】:

我正在运行时创建一个类文件。

我想在类加载器中用更新的类文件替换现有的类文件。

它类似于热交换(例如 JRebel),避免服务器重启和重新部署。

我找到了用于上下文重新加载的 tomcat 的 context.xml 方法。 但在生产环境中用处不大。

我们可以在运行时向 ClassLoader 注册类吗? 请建议是否有任何替代方法可以在运行时重新加载类。


我正在使用以下代码来检索当前的类加载器。

ClassLoader classLoader = LoggingAspect.class.getClassLoader();

下面是load类方法的实现。

public class AspectClassLoader extends ClassLoader{

@Override
public synchronized Class<?> loadClass(String name) throws ClassNotFoundException
{
    String customLoadClass = "com.log.LoggingAspect";
    try
    {
        if(!customLoadClass.equals(name))
        {
            return super.loadClass(name);
        }
        else
        {
            URL classLoadUrl = new URL(this.reloadClassUrl);
            URLConnection connection = classLoadUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();

            while(data != -1){
                buffer.write(data);
                data = input.read();
            }

            input.close();

            byte[] classData = buffer.toByteArray();
            return defineClass(name, classData, 0, classData.length);
        }
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    return null; 
}

要重新加载类,我使用以下代码。

AspectClassLoader urlClsLoader = new AspectClassLoader(classLoader);
Class aspect = urlClsLoader.reloadClass("com.log.LoggingAspect", true, new String("file:"+className));

我的类加载器的重载方法是

public synchronized Class<?> reloadClass(String name, boolean resolve, String reloadClassUrl) throws ClassNotFoundException
{
    this.reloadClassUrl = reloadClassUrl;
    return this.loadClass(name, resolve);
}

重新加载后,如果我创建 LoggingAspect 的新实例,它仍然会给我旧实例。请提出建议。

Class aspect = urlClsLoader.reloadClass("com.log.LoggingAspect", true, new String("file:"+className));
        com.log.aspect.Aspect aspectObj = (com.log.aspect.Aspect)aspect.newInstance();

我仍然得到旧实例。

请说明为什么类加载器不加载修改后的类?

【问题讨论】:

    标签: java tomcat classloader urlclassloader contextclassloader


    【解决方案1】:

    这是可能的,但很复杂。您需要做的是创建一个新的URLClassLoader,并将当前的ClassLoader 作为父级。将带有您的类的文件夹的 URL(不包括包文件夹)添加到新的 URLClassLoader

    接下来,您必须先修补 loadClass() 以在调用 parent.loadClass() 之前返回您的新类(否则,将使用现有类而忽略更新的类)。

    当你想使用这个新类时它会变得复杂。为此,您必须使用新的类加载器创建它,并确保每个人都使用该类型的实例。

    如果您的 WAR 中不存在该类,它可能更安全(并且更容易调试)。不使用类型,而是使用 URLClassLoader 加载类并创建它的实例。所以使用这个类的代码是这样工作的:

    IService service = createService();
    

    其中IService 是一个接口,它定义了生成的类支持的方法。这样,您可以编写使用这些方法的代码,而实际上不需要实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 1970-01-01
      • 1970-01-01
      • 2013-11-22
      • 2021-09-12
      相关资源
      最近更新 更多