在tomcat中重新加载类文件

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

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

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

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

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


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

ClassLoader classLoader = LoggingAspect.class.getClassLoader(); 

下面是load class方法的实现。

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

我仍然得到旧的实例。

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

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

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

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

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

 IService service = createService(); 

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