注册并使用自定义java.net.URL协议

我试图从我的java程序中调用custom url ,因此我使用了这样的东西:

 URL myURL; try { myURL = new URL("CustomURI:"); URLConnection myURLConnection = myURL.openConnection(); myURLConnection.connect(); } catch (Exception e) { e.printStackTrace(); } 

我得到以下例外:

java.net.MalformedURLException:未知协议:来自java.net.URL的java.net.URL。(未知来源)的CustomURI。(来自未知来源)java.net.URL。(未知来源)at com.demo.TestDemo。主(TestDemo.java:14)

如果我从浏览器触发URI然后它按预期工作但如果我尝试从Java Program调用它,那么我得到上述exception。

编辑:

以下是我尝试的步骤(我肯定错过了一些东西,请告诉我):

步骤1:在java.protocol.handler.pkgs添加自定义URI

第2步:从URL触发自定义URI

码:

 public class CustomURI { public static void main(String[] args) { try { add("CustomURI:"); URL uri = new URL("CustomURI:"); URLConnection uc = uri.openConnection(); uc.connect(); } catch (Exception e) { e.printStackTrace(); } } public static void add( String handlerPackage ){ final String key = "java.protocol.handler.pkgs"; String newValue = handlerPackage; if ( System.getProperty( key ) != null ) { final String previousValue = System.getProperty( key ); newValue += "|" + previousValue; } System.setProperty( key, newValue ); System.out.println(System.getProperty("java.protocol.handler.pkgs")); } } 

当我运行这段代码时,我得到了CustomURI:在我的控制台中打印(来自add方法),但是当使用CustomURI:初始化URL时,我得到了这个exceptionCustomURI:作为构造函数:

 Exception in thread "main" java.lang.StackOverflowError at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Unknown Source) at java.net.URL.getURLStreamHandler(Unknown Source) at java.net.URL.(Unknown Source) at java.net.URL.(Unknown Source) at sun.misc.URLClassPath$FileLoader.getResource(Unknown Source) at sun.misc.URLClassPath.getResource(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at java.net.URL.getURLStreamHandler(Unknown Source) at java.net.URL.(Unknown Source) at java.net.URL.(Unknown Source) 

请告知如何使这项工作。

  1. 创建一个自定义URLConnection实现,该实现在connect()方法中执行作业。

     public class CustomURLConnection extends URLConnection { protected CustomURLConnection(URL url) { super(url); } @Override public void connect() throws IOException { // Do your job here. As of now it merely prints "Connected!". System.out.println("Connected!"); } } 

    不要忘记相应地覆盖和实现其他方法,如getInputStream() 。 由于该信息在问题中缺失,因此无法提供更多详细信息。


  2. 创建一个自定义URLStreamHandler实现,它在openConnection()返回它。

     public class CustomURLStreamHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL url) throws IOException { return new CustomURLConnection(url); } } 

    如有必要,请不要忘记覆盖并实现其他方法。


  3. 创建一个自定义URLStreamHandlerFactory ,根据协议创建并返回它。

     public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(String protocol) { if ("customuri".equals(protocol)) { return new CustomURLStreamHandler(); } return null; } } 

    请注意,协议始终是小写的。


  4. 最后通过URL#setURLStreamHandlerFactory()在应用程序启动时注册它

     URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory()); 

    请注意, Javadoc明确表示您最多可以设置一次。 因此,如果您打算在同一个应用程序中支持多个自定义协议,则需要生成自定义URLStreamHandlerFactory实现以在createURLStreamHandler()方法中覆盖它们。


    或者,如果您不喜欢Demeter法则,请将它们全部放在匿名类中以进行代码缩小:

     URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() { public URLStreamHandler createURLStreamHandler(String protocol) { return "customuri".equals(protocol) ? new URLStreamHandler() { protected URLConnection openConnection(URL url) throws IOException { return new URLConnection(url) { public void connect() throws IOException { System.out.println("Connected!"); } }; } } : null; } }); 

    如果您已经使用Java 8,请使用lambda替换URLStreamHandlerFactoryfunction接口以进一步缩小:

     URL.setURLStreamHandlerFactory(protocol -> "customuri".equals(protocol) ? new URLStreamHandler() { protected URLConnection openConnection(URL url) throws IOException { return new URLConnection(url) { public void connect() throws IOException { System.out.println("Connected!"); } }; } } : null); 

现在您可以按如下方式使用它:

 URLConnection connection = new URL("CustomURI:blabla").openConnection(); connection.connect(); // ... 

或者根据规范使用小写协议:

 URLConnection connection = new URL("customuri:blabla").openConnection(); connection.connect(); // ... 

你做了一个递归/无限循环。

Classloader以不同的方式搜索类。

stacktrace(URLClassPath)是这样的:

  1. 加载资源。
  2. 我加载了每个协议吗? 没有!
  3. 加载所有protocoll-Handler,我找不到File «your java.protocol.handler.pkgs-package».CustomURI.Handler
  4. 这门课是一种资源! 我加载了每个协议吗? 没有!
  5. 加载所有protocoll-Handler,我找不到File «your java.protocol.handler.pkgs-package».CustomURI.Handler
  6. 这门课是一种资源! 我加载了每个协议吗? 没有!
  7. 加载所有protocoll-Handler,我找不到File «your java.protocol.handler.pkgs-package».CustomURI.Handler
  8. 这门课是一种资源! 我加载了每个协议吗? 没有!
  9. 加载所有protocoll-Handler,我找不到File «your java.protocol.handler.pkgs-package».CustomURI.Handler
  10. 这门课是一种资源! 我加载了每个协议吗? 没有!
  11. 加载所有protocoll-Handler,我找不到File «your java.protocol.handler.pkgs-package».CustomURI.Handler

    …… StackOverflowException !!!

如果您不想接管唯一的URLStreamHandlerFactory,您实际上可以使用一个可怕但有效的命名约定来获取默认实现。

必须URLStreamHandler类命名为Handler ,它映射到的协议是该类包的最后一段。

所以, com.foo.myproto.Handler – > myproto:urls ,只要将包com.foo添加到“url流源包”列表中,以便在未知协议上查找。 您可以通过系统属性"java.protocol.handler.pkgs" (这是要搜索的包名称的分隔列表)来执行此操作。

这是一个执行你需要的抽象类:(不要介意缺少的StringTo>StringURLConnection ,这些就是他们的名字所建议的,你可以使用你喜欢的任何抽象)

 public abstract class AbstractURLStreamHandler extends URLStreamHandler { protected abstract StringTo> dynamicFiles(); protected static void addMyPackage(Class handlerClass) { // Ensure that we are registered as a url protocol handler for JavaFxCss:/path css files. String was = System.getProperty("java.protocol.handler.pkgs", ""); String pkg = handlerClass.getPackage().getName(); int ind = pkg.lastIndexOf('.'); assert ind != -1 : "You can't add url handlers in the base package"; assert "Handler".equals(handlerClass.getSimpleName()) : "A URLStreamHandler must be in a class named Handler; not " + handlerClass.getSimpleName(); System.setProperty("java.protocol.handler.pkgs", handlerClass.getPackage().getName().substring(0, ind) + (was.isEmpty() ? "" : "|" + was )); } @Override protected URLConnection openConnection(URL u) throws IOException { final String path = u.getPath(); final Out1 file = dynamicFiles().get(path); return new StringURLConnection(u, file); } } 

然后,这是实现抽象处理程序的实际类(对于dynamic: urls:

 package xapi.dev.api.dynamic; // imports elided for brevity public class Handler extends AbstractURLStreamHandler { private static final StringTo> dynamicFiles = X_Collect.newStringMap(Out1.class, CollectionOptions.asConcurrent(true) .mutable(true) .insertionOrdered(false) .build()); static { addMyPackage(Handler.class); } @Override protected StringTo> dynamicFiles() { return dynamicFiles; } public static String registerDynamicUrl(String path, Out1 contents) { dynamicFiles.put(path, contents); return path; } public static void clearDynamicUrl(String path) { dynamicFiles.remove(path); } }