Modularization without OSGI in Web project

Asked

Viewed 187 times

2

I have a project that will be fairly large, so it would be very interesting to modularize, I know, there is Osgi, but I found it very complex and had difficulty adapting my application, the impression I had is that it will complicate more than facilitating maintenance,is too bold simply to use a class that is in a separate jar through an interface, so I’m thinking of doing through Classloader, the structure I think is the following

Core Project

package core;

public interface IModulo {
<T> T getString();
}

Example Project Module

package modulo1;

import core.IModulo;

public class Teste implements IModulo{

public <T> T getString() {
    return (T) "Hello";
}
}

Main project, where the modules will be "installed", this main project already has the Core project as a dependency, that is, the Imodulo interface is already in the classpath, if I run through a simple main class, it works, but by Tomcat no, see the code snippet

  import core.IModulo;
   public class Main {
public static void main(String[] args) {

    try {
        String jarDoModulo = "C:\\modulo1.jar";
        File file = new File(jarDoModulo);
        URL url;
        url = file.toURL();

        URL[] urls = new URL[] { url };
        ClassLoader cl = new URLClassLoader(urls);          
        Class<IModulo> cls = (Class<IModulo>) cl.loadClass("modulo1.Teste");
        IModulo modulo1 = cls.newInstance();
        System.out.println(modulo1.getString());

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

The error that appears is

Caused by: java.lang.ClassNotFoundException: core.IModulo
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 60 more
  • 1

    Hello Rodrigo, I changed the tag [tag:java-ee] by [tag:Tomcat] to try to help you attract more answers. Each container has its feature configuration specifics and Classloaders. Besides Tomcat is a special case that is not even a Java EE application server, it is just a container Servlet / JSP.

1 answer

1


From what I understand its requirement is to basically separate implementations of certain interfaces from the core. These implementations are in projects jar apart from your main web project.

The problem you bumped into happens because Tomcat has its own hierarchy of class loaders.

The way your code was written, inside the Tomcat IModulo shall be administered by a WebappClassLoader and the class Teste for his URLClassLoader (which has no instance of IModulo loaded, therefore, fires an exception).

There are two recommended paths here:

  1. Put the modulo1.jar in the briefcase WEB-INF/lib of your main project. This way the classes of your module will be available for the application and you will not even need to mess with class loaders. Modularity is still maintained in the sense that it is possible to change the module implementation without changing the core application.

  2. Use or write a ClassLoader customized (if you really want to leave your module in one location non-standard). Until the Tomcat 7 you could use one Virtualwebapploader to make your module jar available; from Tomcat 8 you can use the Preresources.

  • The problem with solution 1 is that I would have to take down Tomcat and redo the deploy to add a module, with classLoader I think, that I can "install" the jar in Runtime and use=lo in having to stop Tomcat, I’m sure?

  • Hello Rodrigo. You do not need to overthrow the Tomcat, but due to the very nature of the class loaders, you will need to re-load the application. Configure Tomcat to read new versions of a . jar on WEB-INF/lib is a matter of putting a reloadable="true" in the xml context.. In this process it will "reopen" the application (as if you had given a touch in the web.xml) discarding the old ClassLoader and opening a new one with all the features of your new jar.

  • You can still make a copy of the entire folder of your application, replace only the jar and make a parallel deploy to avoid unavailability for customers consuming older versions of the application.

  • If even one Reload in versioned environment does not meet your requirements I would say to go from Osgi even. Hot class replacement requires nontrivial code (locate all old references of a given class, discard them, replace them with a new version maintaining the state of the compatible variables, force old class GC ClassLoader to avoid Leaks, etc.).

  • You will eventually discover that you will need to demarcate import and export interfaces of a container to manage the class loaders, of commands to publish, startar and stop modules, etc. In the end you will end up with a mini Equinox or Felix written in the nail :) (my point is; if you really need to swap of Bundles in hot production, Osgi turns out not to be such a complex solution, this kind of thing really requires complex infrastructure code).

  • 1

    I get it Anthony, it really ends up being a complex code and Osgi should not get so complex, well, first I’m organizing the infrastructure of my project, where I already physically separate the modules, look, incredibly the code of the project has become neat and very easy to understand, extender, testability etc... impressive modularization how much it facilitates, in case it is "modularized" but not with hotdeploy, I believe that calmly, trying to apply Osgi on top of my structure that I have made now, the thing becomes clearer.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.