在tomcat中重新加载类文件 [英] Reload class file in tomcat

查看:133
本文介绍了在tomcat中重新加载类文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



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



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






我使用以下代码检索当前classLoader。

  ClassLoader classLoader = LoggingAspect.class.getClassLoader(); 

以下是load class方法的实现。

 公共类AspectClassLoader扩展ClassLoader {

@Override
公共同步类<?> 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();
返回defineClass(name,classData,0,classData.length);
}
}
catch(例外e)
{
e.printStackTrace();
}
返回null;
}

要重新加载课程我使用以下代码。

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

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

 公共同步类<?> reloadClass(String name,boolean resolve,String reloadClassUrl)抛出ClassNotFoundException 
{
this.reloadClassUrl = reloadClassUrl;
返回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();

我仍然得到旧实例。



<请提示为什么classloader不加载修改后的类?

解决方案

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



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



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



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

  IService service = createService(); 

其中 IService 是定义生成的类支持的方法。这样,您可以编写使用这些方法的代码而无需实际执行。


I am creating a class file at run time.

I want to replace the existing class file with the updated one in the class loader.

It is similar to hot swapping (e.g. JRebel) which avoids server restart and redeployment.

I found context.xml approach for tomcat for context reloading. But it is not very useful in case of production environment.

Can we register class with ClassLoader at runtime? Please suggest if any alternative is there to reload class at runtime.


I am using following code to retrieve current classLoader.

ClassLoader classLoader = LoggingAspect.class.getClassLoader();

Below is the implementation of load class method.

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

To reload class i am using following code.

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

My reload method of the classloader is

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

After reloading if i create the new instance of LoggingAspect it still gives me the old instance. Please suggest.

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

Still I am getting the old instance.

Please suggest why classloader does not load the modified class?

解决方案

This is possible but complex. What you need to do is create a new URLClassLoader with the current ClassLoader as parent. Add the URL to the folder with your class (without package folders) to the new URLClassLoader

Next, you will have to patch loadClass() to return your new class before calling parent.loadClass() (otherwise, the existing class will be used and the updated one will be ignored).

It gets complex when you want to use the new class. For this, you will have to create it using the new classloader and make sure that everyone uses this instance of the type.

It's probably more safe (and easier to debug) if the class doesn't exist in your WAR. Instead of using the type, load the class with the URLClassLoader and create an instance of it. So the code using this class works like this:

IService service = createService();

where IService is an interface which defines the methods that the generated class supports. That way, you can write code which uses the methods without actually needing an implementation.

这篇关于在tomcat中重新加载类文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆