有没有类似 Tomcat 的类加载器可以独立使用?

发布于 2024-12-08 11:18:31 字数 302 浏览 0 评论 0原文

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

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

  • 可以从包含 JAR 的目录加载类。
  • 更喜欢来自其自己的类路径的类而不是来自父级的类

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

I'm working with a Java sort-of-application-server (Smartfox) which can run multiple applications ("extensions") but has a very inconvenient classpath setup to go along with it, along with issues when trying to use SLF4J.

To work around that I'd like to wrap my applications in their own classloaders. Such a containing classloader should be much like Tomcat's, in that it

  • Can load classes from a directory containing JARs.
  • Prefers classes from its own classpath over those from the parent

Is there a library somewhere that has such a classloader I can just "drag and drop" in my project? If not, would it be hard to create it myself? Any known pitfalls?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小嗲 2024-12-15 11:18:31

OSGi(和其他模块系统)旨在准确地处理这种情况的问题。

一开始它可能看起来有点大材小用,但我认为您很快就会重新实现 OSGi 已经为您做的事情的重要部分。

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

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.

榆西 2024-12-15 11:18:31

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

        };

    }

}

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;

        };

    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文