📄 servicefactory.java
字号:
private static final class ServiceIterator implements Iterator { /** * The service provider interface (usually an interface, sometimes * an abstract class) which the services must implement. */ private final Class spi; /** * An Enumeration<URL> over the URLs that contain a resource * <code>META-INF/services/<org.foo.SomeService></code>, * as returned by {@link ClassLoader#getResources(String)}. */ private final Enumeration urls; /** * The class loader used for loading service providers. */ private final ClassLoader loader; /** * The security context used when loading and initializing service * providers. We want to load and initialize all plug-in service * providers under the same security context, namely the one that * was active when {@link #lookupProviders(Class, ClassLoader)} has * been called. */ private final AccessControlContext securityContext; /** * A reader for the current file listing class names of service * implementors, or <code>null</code> when the last reader has * been fetched. */ private BufferedReader reader; /** * The URL currently being processed. This is only used for * emitting error messages. */ private URL currentURL; /** * The service provider that will be returned by the next call to * {@link #next()}, or <code>null</code> if the iterator has * already returned all service providers. */ private Object nextProvider; /** * Constructs an Iterator that loads and initializes services on * demand. * * @param spi the service provider interface which the services * must implement. Usually, this is a Java interface type, but it * might also be an abstract class or even a concrete superclass. * * @param urls an Enumeration<URL> over the URLs that contain a * resource * <code>META-INF/services/<org.foo.SomeService></code>, as * determined by {@link ClassLoader#getResources(String)}. * * @param loader the ClassLoader that gets used for loading * service providers. * * @param securityContext the security context to use when loading * and initializing service providers. */ ServiceIterator(Class spi, Enumeration urls, ClassLoader loader, AccessControlContext securityContext) { this.spi = spi; this.urls = urls; this.loader = loader; this.securityContext = securityContext; this.nextProvider = loadNextServiceProvider(); } /** * @throws NoSuchElementException if {@link #hasNext} returns * <code>false</code>. */ public Object next() { Object result; if (!hasNext()) throw new NoSuchElementException(); result = nextProvider; nextProvider = loadNextServiceProvider(); return result; } public boolean hasNext() { return nextProvider != null; } public void remove() { throw new UnsupportedOperationException(); } private Object loadNextServiceProvider() { String line; if (reader == null) advanceReader(); for (;;) { /* If we have reached the last provider list, we cannot * retrieve any further lines. */ if (reader == null) return null; try { line = reader.readLine(); } catch (IOException readProblem) { log(Level.WARNING, "IOException upon reading {0}", currentURL, readProblem); line = null; } /* When we are at the end of one list of services, * switch over to the next one. */ if (line == null) { advanceReader(); continue; } // Skip whitespace at the beginning and end of each line. line = line.trim(); // Skip empty lines. if (line.length() == 0) continue; // Skip comment lines. if (line.charAt(0) == '#') continue; try { log(Level.FINE, "Loading service provider \"{0}\", specified" + " by \"META-INF/services/{1}\" in {2}.", new Object[] { line, spi.getName(), currentURL }, null); /* Load the class in the security context that was * active when calling lookupProviders. */ return AccessController.doPrivileged( new ServiceProviderLoadingAction(spi, line, loader), securityContext); } catch (Exception ex) { String msg = "Cannot load service provider class \"{0}\"," + " specified by \"META-INF/services/{1}\" in {2}"; if (ex instanceof PrivilegedActionException && ex.getCause() instanceof ClassCastException) msg = "Service provider class \"{0}\" is not an instance" + " of \"{1}\". Specified" + " by \"META-INF/services/{1}\" in {2}."; log(Level.WARNING, msg, new Object[] { line, spi.getName(), currentURL }, ex); continue; } } } private void advanceReader() { do { if (reader != null) { try { reader.close(); log(Level.FINE, "closed {0}", currentURL, null); } catch (Exception ex) { log(Level.WARNING, "cannot close {0}", currentURL, ex); } reader = null; currentURL = null; } if (!urls.hasMoreElements()) return; currentURL = (URL) urls.nextElement(); try { reader = new BufferedReader(new InputStreamReader( currentURL.openStream(), "UTF-8")); log(Level.FINE, "opened {0}", currentURL, null); } catch (Exception ex) { log(Level.WARNING, "cannot open {0}", currentURL, ex); } } while (reader == null); } } // Package-private to avoid a trampoline. /** * Passes a log message to the <code>java.util.logging</code> * framework. This call returns very quickly if no log message will * be produced, so there is not much overhead in the standard case. * * @param level the severity of the message, for instance {@link * Level#WARNING}. * * @param msg the log message, for instance <code>“Could not * load {0}.”</code> * * @param param the parameter(s) for the log message, or * <code>null</code> if <code>msg</code> does not specify any * parameters. If <code>param</code> is not an array, an array with * <code>param</code> as its single element gets passed to the * logging framework. * * @param t a Throwable that is associated with the log record, or * <code>null</code> if the log message is not associated with a * Throwable. */ static void log(Level level, String msg, Object param, Throwable t) { LogRecord rec; // Return quickly if no log message will be produced. if (!LOGGER.isLoggable(level)) return; rec = new LogRecord(level, msg); if (param != null && param.getClass().isArray()) rec.setParameters((Object[]) param); else rec.setParameters(new Object[] { param }); rec.setThrown(t); // While java.util.logging can sometimes infer the class and // method of the caller, this automatic inference is not reliable // on highly optimizing VMs. Also, log messages make more sense to // developers when they display a public method in a public class; // otherwise, they might feel tempted to figure out the internals // of ServiceFactory in order to understand the problem. rec.setSourceClassName(ServiceFactory.class.getName()); rec.setSourceMethodName("lookupProviders"); LOGGER.log(rec); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -