使用反射替换 java.net.URL URLStreamHandlerFactory 是个好主意吗?

Posted

技术标签:

【中文标题】使用反射替换 java.net.URL URLStreamHandlerFactory 是个好主意吗?【英文标题】:Is it a good idea to replace java.net.URL URLStreamHandlerFactory using reflection? 【发布时间】:2015-11-29 21:28:03 【问题描述】:

在 Java 中,我们至少可以通过两种方式注册自定义协议处理程序:

    通过设置系统属性'java.protocol.handler.pkgs' 使用 URL.setURLStreamHandlerFactory

更多详情请查看http://accu.org/index.php/journals/1434

我不能使用第一个选项,因为我必须向服务器 (tomcat) 类路径添加大量 jar 文件,以使处理程序实现对引导类加载器可见。此外,还需要一些初始化,这必须在应用程序上下文中完成。

第二个选项的问题是Factory只能注册一次(检查java.net.URL#setURLStreamHandlerFactory),不幸的是它是由Tomcat完成的。

我能做的是创建一个装饰器工厂,它将通过我的协议处理程序扩展现有的。比使用 relfection 将静态字段 URL#factory 设置为 null 并使用 URL#setURLStreamHandlerFactory 以标准方式注册(再次?)我的“decoratorFactory”。我只是想知道在这里使用反射是否是个好主意......?安全性如何?

我想做这样的事情:

try 
        Field factoryField = URL.class.getDeclaredField("factory");
        factoryField.setAccessible(true);
        //  get current factory
        Object currentFactory = factoryField.get(null);
        //  define a decorator factory
        MyFactoryDecorator mfd = new MyFactoryDecorator(currentFactory);
        //  set the factory to null and register MyFactoryDecorator using URL#setURLStreamHandlerFactory.
        factoryField.set(null, null);
        URL.setURLStreamHandlerFactory(mfd);
     catch (NoSuchFieldException e) 
        e.printStackTrace();
     catch (IllegalAccessException e) 
        e.printStackTrace();
    

【问题讨论】:

每当我在同一个句子中听到“好主意”和“反思”时,我都会畏缩 【参考方案1】:

如果这可行的话,我想知道,但是如果您创建一个实际上不包含实现的新 URLStreamHandlerFactory 怎么办?它只是坐在那里,然后在运行时通过应用上下文查找调用它时实例化真正的实现。那么理论上你可以在开始时通过系统属性实例化这个新的代理处理程序,但也可以在实际调用时使用你想要的。

更新:

实际上,我认为您上面的链接提到了这种策略:

另一种方法是使用工厂注册,但提供一个工厂类,它本身支持使用不同名称注册多个不同的流处理程序。

这种方法支持使用 java.net.URL 类的代码,但它确实需要对每个协议进行注册调用,因此需要对应用程序进行更改才能使用新的 URL。然而,该方法通过多个类加载器解决了上面讨论的问题,因为工厂是由用户代码类加载器而不是由 URL 类的类加载器加载的。

我对您所做的一切以及注册的工作方式不是很熟悉,因此这可能会或多或少复杂,具体取决于您所做的事情。如果你甚至需要额外的注册,我知道,但听起来它可能会解决 .jar/app 上下文问题。

【讨论】:

以上是关于使用反射替换 java.net.URL URLStreamHandlerFactory 是个好主意吗?的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向加壳的 Android 应用启动流程 | 使用反射替换 LoadedApk 中的类加载器流程

Android 逆向加壳的 Android 应用启动流程 | 使用反射替换 LoadedApk 中的类加载器流程

如何通过 Java 程序中的 java.net.URL 类监控打开的 URL?

java.net.URL 读取流到字节 []

spring工程启动时,全局反射替换属性值

java如何提取url里的域名