Is there a Tomcat-like classloader that can be used standalone?

萝らか妹 提交于 2019-12-06 11:28:40

OSGi (and other module systems) are designed to handle exactly this kind of problem.

It might look like overkill at first, but I think you'll quickly re-implement significant parts of the things that OSGi alread does for you.

Equinox is the OSGi implementation used by Eclipse, for example.

Since I had trouble embedding an OSGi container and it was indeed a bit overkill, I rolled my own solution. But I'll learn to use OSGi one day, in a situation where I don't need to embed the framework.

If you somehow happen to want to use this code, it's under the "do whatever you want with it" license.

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;

        };

    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!