Java 在tomcat中重新加载类文件

Java 在tomcat中重新加载类文件,java,tomcat,classloader,urlclassloader,contextclassloader,Java,Tomcat,Classloader,Urlclassloader,Contextclassloader,我正在运行时创建一个类文件 我想用类装入器中更新的类文件替换现有的类文件 它类似于热交换(如JRebel),避免了服务器重启和重新部署 我为tomcat找到了context.xml方法来重新加载上下文。 但在生产环境中,它不是很有用 我们可以在运行时向类加载器注册类吗? 请建议是否有其他方法可以在运行时重新加载类 我使用以下代码检索当前的类加载器 ClassLoader classLoader = LoggingAspect.class.getClassLoader(); 下面是load类方

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

我想用类装入器中更新的类文件替换现有的类文件

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

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

我们可以在运行时向类加载器注册类吗? 请建议是否有其他方法可以在运行时重新加载类


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

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; 
}
我的类加载器的重载方法是

public synchronized Class<?> reloadClass(String name, boolean resolve, String reloadClassUrl) throws ClassNotFoundException
{
    this.reloadClassUrl = reloadClassUrl;
    return this.loadClass(name, resolve);
}
但我还是得到了老的例子


请说明classloader为什么不加载修改过的类?

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

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

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

如果您的WAR中不存在该类,那么它可能更安全(也更容易调试)。不要使用该类型,而是使用
URLClassLoader
加载该类并创建其实例。因此,使用此类的代码如下所示:

IService service = createService();
其中,
IService
是一个接口,它定义生成的类支持的方法。这样,您就可以编写使用这些方法的代码,而无需实际实现

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