URLConnection资源解析的运行时配置

时间:2019-04-26 17:15:28

标签: java url classloader urlconnection

虽然可以说这是基于观点的,但我很好奇这里是否有人对此有想法:

假设您正在为Web应用程序编写(高度专业化,但无关紧要的)应用程序服务器,例如Tomcat,Jetty等(相同的基本问题)。这些都具有资源加载机制,通常使用线程的上下文类加载器(Tomcat)或某些自定义方案(Spring Resource类,...)。

我很乐意(但尚未找到elegenat解决方案)提供类似的信息,但是还允许对“ override”目录进行运行时配置:考虑重新实现Tomcat,但允许“分配到指定目录的每个“ .war”旁边的“ .conf”文件。加载资源后,首先在该目录中搜索(针对每个war /应用程序),如果没有找到,则使用应用程序的类加载器(在Tomcat中,通过Thread.currentThread()。getContextClassloader()进行解析)-尽管我个人还发现该解决方案不太理想,因为并非所有第三方库都使用上下文类加载器,并且,如果您使用其中一种,则根本就不走运。

这将要求您在运行时访问自定义URLStreamHandler或URLConnection。这当然可以通过“ Tomcat方法”实现,即仅使用一个单例实例调用URL.setURLStreamHandlerFactory并在调用任何使用以下内容的东西(例如用于解析/验证的整个javax.xml机械)之前,在该单例实例中配置类似ThreadLocal变量的内容解决“链接”的网址。现在,众所周知,单例/全局状态是自动化测试的祸根,但是我在不依靠某种全局状态的情况下根本找不到解决方案。

这是我发现正在使用的解决方案,可悲地使用了全局状态:

public class XmlParser {
    // this is the global state...
    private static com.example.proto.classpath.Handler cpHandler;
    static {
        cpHandler = new com.example.proto.classpath.Handler();
        URL.setURLStreamHandlerFactory(p -> proto.equalsIgnoreCase("example") ? cpHandler : null);
    }
    public static interface ResourceLocator extends Function<String, URL> {};
    public org.w3c.dom.Element parse(InputStream doc, ResourceLocator locator) {
        ResourceLocator old = cpHandler.setResourceLocator(locator);
        try {
            // do the actual parsing, not relevant here
            return doc.getDocumentElement();
        } finally {
            cpHandler.setResourceLocator(old);
        }
    }
}

处理程序为

public class Handler {
    private ThreadLocal<ResourceLocator> loc;

    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        return loc.get().apply(url.getPath()).openConnection();
    }

    public ResourceLocator setResourceLocator(ResourceLocator loc) {
        ResourceLocator old = this.loc.get();
        this.loc.set(loc);
        return old;
    }
}

通过这种方式,您可以使用所需的任何类装入器来实现各种ResourceLocator,但是可以使用所需的许多覆盖目录等,但是您具有XmlParser的cpHandler变量形式的全局状态。

我想找到一种摆脱全局状态的方法。这个网站上有没有头脑的人有想法用Java实现该目标?

P.S .:目前正在尝试在Java 11上执行此操作(因为它是当前的LTS),因此JPMS在我当前的ResourceLocator实现中也起作用,但这并不重要。同样不反对升级到Java 12或13的早期访问,如果有帮助的话。

0 个答案:

没有答案