N
N
Nick20152016-05-12 10:44:32
Java
Nick2015, 2016-05-12 10:44:32

Classloader and what does it represent?

Good day. The essence of the following is the interface

public interface Module {
  public int run();
}

And 2 classes implementing the interface.
  1. How can I use the classloader and these classes/interfaces?
  2. The interface itself must be taken out in a jar file?
  3. How can I then make it so that the output was first from the loaded class 1 and then 2, and vice versa?
  4. I searched a lot on the net, but if there is something, then, some actions, which, most likely through a poor understanding of the structure, how it should work, what to load where .. I looked at this article, everything is clear in words, but I can’t implement it :( Therefore if it’s not difficult, maybe share the material, articles, maybe pierced something ...

I'm interested in a way with a common interface....

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
vlad20012, 2016-05-12
@Nick2015

The topic with class loading is already quite hackneyed and the theory on it is easy to google. In a couple of minutes I found
the official docks ,
a rather detailed article from someone's blog ,
a recording of a speech at the JUG.RU conference Let
's decide on the initial conditions. As I understand it, there is a folder with jar files. You need to go through all the jar files and get a list of classes that implement Module. Something like
Let's assume that 1 jar file can contain only one module (hereinafter, "module" is a class that implements the interfaceModule). Here is the most non-trivial question, how to find this module inside the archive. The easiest (for starters) way is to put a config in each jar file in a certain path, in which you specify the path to the module. And there is already such a config in the jar file - standard META-INF. In the simplest case, we get a jar file from two files with the following structure:

MyMod.jar
├───META-INF
│   └───MANIFEST.MF
└───mymod
    └───MyMod.class

Where MANIFEST.MFcontains the string
i.e. path to the MyMod class.
The MyMod class must be built as a separate project, adding a project containing the Module. Contents of MyMod.java
package mymod;

public class MyMod implements Module {
    public int run() {
        System.out.println("MyMod loaded!");
    }
}

Let's assume that MyMod.jar is already built and is (perhaps, along with other modules) in the "/modules" directory.
Well, these were the initial conditions =) Now to the essence of the matter.
public class ModuleLoader {
  public static void main(String[] args) {
    List<Module> mods = new ModuleLoader().discoverModules(new File("/modules"));
    for(Module mod : mods)
      mod.run();
  }

  public List<Module> discoverModules(File dir) {
    List<File> jarFiles = Stream.of(dir.listFiles())
        .filter(f -> f.getName().endsWith(".jar"))
        .collect(Collectors.toList());
    URL[] moduleUrls = jarFiles.stream().map(this::toUrl).toArray(URL[]::new);

    URLClassLoader classLoader = new URLClassLoader(moduleUrls, getClass().getClassLoader());
    return jarFiles.stream()
        .map(this::getMainClassName)
        .map(name -> {
          try {
            return (Module) classLoader.loadClass(name).newInstance();
          } catch(Exception e) {
            throw new RuntimeException(e);
          }
        })
        .collect(Collectors.toList());
  }

  private String getMainClassName(File file) {
    try(JarFile jar = new JarFile(file)){
      return (String) jar.getManifest().getMainAttributes().get("Main-Class");
    } catch(IOException e) {
      throw new RuntimeException(e);
    }
  }

  private URL toUrl(File file) {
    try {
      return file.toURI().toURL();
    } catch(MalformedURLException e) {
      throw new RuntimeException(e);
    }
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question