Reload class file in tomcat

I am creating a class file at runtime.

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

It looks like a hot swap (for example, JRebel), which avoids rebooting and reinstalling the server.

I found the context.xml approach for tomcat to overload the context. But this is not very useful in the case of a production environment.

Is it possible to register a class with ClassLoader at runtime? Please suggest if there is any alternative to reloading the class at runtime.


I am using the following code to retrieve the current classLoader.

ClassLoader classLoader = LoggingAspect.class.getClassLoader(); 

The following is the implementation of the 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 the class, I use the following code.

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

My method of reloading the class loader

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

After rebooting, if I create a 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(); 

However, I get the old instance.

Indicate why the class loader does not load the modified class?

+1
source share
1 answer

It is possible, but difficult. You need to create a new URLClassLoader with the current ClassLoader as the parent. Add the url to the folder with your class (without package folders) in the new URLClassLoader

Then you will need to schedule loadClass() to return the new class before calling parent.loadClass() (otherwise, the existing class will be used, and the updated one will be ignored).

It becomes complicated if you want to use a new class. To do this, you will need to create it using the new class loader and make sure that everyone uses this type instance.

This is probably safer (and easier to debug) if the class does not exist in your WAR. Instead of using this type, load the class using URLClassLoader and instantiate it. Thus, code using this class works as follows:

 IService service = createService(); 

where IService is the interface that defines the methods supported by the generated class. This way you can write code that uses methods without an actual implementation.

+2
source

Source: https://habr.com/ru/post/1435049/


All Articles