Есть ли Tomcat-подобный загрузчик классов, который можно использовать отдельно? - PullRequest
2 голосов
/ 04 октября 2011

Я работаю с Java-сервером приложений (Smartfox), который может запускать несколько приложений («расширений»), но имеет очень неудобную настройку пути к классам, чтобы согласиться с ним, а также проблемы при попытке использовать SLF4J.

Чтобы обойти это, я бы хотел обернуть свои приложения в свои собственные загрузчики классов. Такой содержащий загрузчик классов должен быть очень похож на Tomcat, так как он

  • Может загружать классы из каталога, содержащего JAR.
  • Предпочитает классы из своего собственного пути к классам по сравнению с классами из родительского

Есть ли где-нибудь библиотека, в которой есть такой загрузчик классов, который я могу просто "перетащить" в свой проект? Если нет, то будет ли сложно создать его самому? Есть известные подводные камни?

Ответы [ 2 ]

3 голосов
/ 04 октября 2011

Поскольку у меня были проблемы с встраиванием контейнера OSGi, и это было действительно немного излишне, я выбрал свое собственное решение. Но я научусь использовать OSGi однажды, в ситуации, когда мне не нужно встраивать фреймворк.

Если вам почему-то захочется использовать этот код, он находится под лицензией «делай с ней что хочешь».

public class SmartfoxExtensionContainer extends AbstractExtension {

    private AbstractExtension extension;

    private void initRealExtension() {
        final String zone = this.getOwnerZone();
        System.out.println("[SmartfoxExtensionContainer] ========= Init extension for zone " + zone + " =========");

        try {

            // load properties
            File propFile = new File("wext/" + zone + ".properties");
            System.out.println("[SmartfoxExtensionContainer] Load config from " + propFile.getCanonicalPath());
            Properties props = new Properties();
            final FileInputStream ins = new FileInputStream(propFile);
            try {
                props.load(new InputStreamReader(ins, "UTF-8"));
            } finally {
                try {
                    ins.close();
                } catch (IOException e) {}
            }

            // construct classloader
            File jarDir = new File(props.getProperty("classpath", "wext/" + zone));
            System.out.println("[SmartfoxExtensionContainer] Load classes from " + jarDir.getCanonicalPath());
            if (!jarDir.isDirectory()) throw new RuntimeException("That is not an existing directory");

            final File[] fs = jarDir.listFiles();

            URL[] urls = new URL[fs.length];

            for (int f = 0; f < fs.length; f++) {
                System.out.println("[SmartfoxExtensionContainer]     " + fs[f].getName());
                urls[f] = fs[f].toURI().toURL();
            }

            SelfishClassLoader cl = new SelfishClassLoader(urls, SmartfoxExtensionContainer.class.getClassLoader());

            // get real extension class
            String mainClass = props.getProperty("mainClass", "Extension");
            System.out.println("[SmartfoxExtensionContainer] Main class: " + mainClass);

            @SuppressWarnings("unchecked")
            Class<? extends AbstractExtension> extClass = (Class<? extends AbstractExtension>) cl.loadClass(mainClass);

            // create extension and copy settings
            extension = extClass.newInstance();
            extension.setOwner(this.getOwnerZone(), this.getOwnerRoom());

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /* ======================= DELEGATES ======================= */

    @Override
    public void init() {
        initRealExtension();
        extension.init();
    }

    @Override
    public void destroy() {
        extension.destroy();
    }

    @Override
public void handleRequest(String arg0, ActionscriptObject arg1, User arg2, int arg3) {
    extension.handleRequest(arg0, arg1, arg2, arg3);
}

@Override
public void handleRequest(String arg0, String[] arg1, User arg2, int arg3) {
    extension.handleRequest(arg0, arg1, arg2, arg3);
}

@Override
public void handleInternalEvent(InternalEventObject arg0) {
    extension.handleInternalEvent(arg0);
}

@Override
public Object handleInternalRequest(Object params) {
    return extension.handleInternalRequest(params);
}

@Override
public void handleRequest(String cmd, JSONObject jso, User u, int fromRoom) {
    extension.handleRequest(cmd, jso, u, fromRoom);
}

    /* ======================= CUSTOM CLASSLOADER ======================= */

    private static class SelfishClassLoader extends URLClassLoader {

        SelfishClassLoader(URL[] urls, ClassLoader parent) {
            super(urls, parent);
        }

        // override default behaviour: find classes in local path first, then parent
        @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

            // First, check if the class has already been loaded
            Class<?> clz = findLoadedClass(name);

            if (clz == null) {

                try {
                    clz = findClass(name);
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from current class loader
                }

                if (clz == null) {
                    // If still not found, then invoke parent.findClass in order
                    // to find the class.
                    clz = getParent().loadClass(name);
                }

            }

            if (resolve) {
                resolveClass(clz);
            }

            return clz;

        };

    }

}
3 голосов
/ 04 октября 2011

OSGi (и другие модульные системы) предназначены для решения точно подобных проблем.

Сначала это может показаться излишним, но я думаю, что выМы быстро осуществим значительную часть того, что OSGi уже сделал для вас.

Equinox - это реализация OSGi, используемая, например, Eclipse.

...