Skip to content

Commit d80c54e

Browse files
committed
Reduce allocations due to ClassLoader#defineClassSourceLocation
It will call URL#toExternalForm() for each class, which will generate again and again the same string pointing to the jar files. By introducing a specific URLStreamHandler, we are able to avoid calling URL#toExternalForm() and use a cached version of it for each JarResource. While not making a tremendous difference, it is an easy way to reduce our allocations at startup.
1 parent 3dad3e2 commit d80c54e

File tree

1 file changed

+68
-1
lines changed
  • independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner

1 file changed

+68
-1
lines changed

independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/JarResource.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package io.quarkus.bootstrap.runner;
22

3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.FileNotFoundException;
36
import java.io.IOException;
47
import java.io.InputStream;
58
import java.net.MalformedURLException;
69
import java.net.URI;
710
import java.net.URISyntaxException;
811
import java.net.URL;
12+
import java.net.URLConnection;
13+
import java.net.URLStreamHandler;
914
import java.nio.file.Path;
1015
import java.security.CodeSource;
1116
import java.security.ProtectionDomain;
@@ -44,7 +49,7 @@ public void init() {
4449
path = '/' + path;
4550
}
4651
URI uri = new URI("file", null, path, null);
47-
url = uri.toURL();
52+
url = new URL((URL) null, uri.toString(), new JarUrlStreamHandler(uri));
4853
} catch (URISyntaxException | MalformedURLException e) {
4954
throw new RuntimeException("Unable to create protection domain for " + jarPath, e);
5055
}
@@ -201,4 +206,66 @@ public boolean equals(Object o) {
201206
public int hashCode() {
202207
return Objects.hashCode(jarPath);
203208
}
209+
210+
/**
211+
* This URLStreamHandler is designed to handle only one jar, which is the one passed in the constructor.
212+
* The goal here is to cache the external form of the URL.
213+
* <p>
214+
* Do not use this class outside of this extremely specific purpose.
215+
*/
216+
private static class JarUrlStreamHandler extends URLStreamHandler {
217+
218+
private final String externalForm;
219+
220+
private JarUrlStreamHandler(URI uri) {
221+
this.externalForm = "file:".concat(uri.getRawPath());
222+
}
223+
224+
@Override
225+
protected URLConnection openConnection(URL u) throws IOException {
226+
return new JarURLConnection(u);
227+
}
228+
229+
@Override
230+
protected String toExternalForm(URL u) {
231+
return externalForm;
232+
}
233+
}
234+
235+
private static class JarURLConnection extends URLConnection {
236+
237+
private final File file;
238+
239+
private JarURLConnection(URL url) {
240+
super(url);
241+
this.file = new File(url.getPath());
242+
}
243+
244+
@Override
245+
public void connect() throws IOException {
246+
if (!file.exists()) {
247+
throw new FileNotFoundException(file.getAbsolutePath());
248+
}
249+
}
250+
251+
@Override
252+
public InputStream getInputStream() throws IOException {
253+
return new FileInputStream(file);
254+
}
255+
256+
@Override
257+
public int getContentLength() {
258+
return (int) file.length();
259+
}
260+
261+
@Override
262+
public long getContentLengthLong() {
263+
return file.length();
264+
}
265+
266+
@Override
267+
public String getContentType() {
268+
return "application/java-archive";
269+
}
270+
}
204271
}

0 commit comments

Comments
 (0)