是否有一个类似Tomcat的类加载器可以独立使用?

时间:2011-10-04 09:19:52

标签: java classpath osgi classloader encapsulation

我正在使用一个Java应用程序服务器(Smartfox),它可以运行多个应用程序(“扩展”)但是有一个非常不方便的类路径设置,以及它在尝试使用时的问题SLF4J。

要解决这个问题,我想将我的应用程序包装在自己的类加载器中。这样一个包含类的加载器应该像Tomcat一样,因为它

  • 可以从包含JAR的目录中加载类。
  • 优先选自自己的类路径中的类,而不是父类
  • 中的类

是否有某个库有这样的类加载器我可以在项目中“拖放”?如果没有,自己创建它会难吗?任何已知的陷阱?

2 个答案:

答案 0 :(得分:3)

OSGi(和其他模块系统)旨在处理完全这类问题。

一开始可能看起来有点过头了,但我认为你会很快重新实现OSGi为你做的事情的重要部分。

Equinox是Eclipse使用的OSGi实现,例如。

答案 1 :(得分:3)

由于我在嵌入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;

        };

    }

}