RESTEasy:「javax.ws.rs.ext.Providers」文件的加载

RESTEasy使用「META-INF/services/javax.ws.rs.ext.Providers」这个文件来设置所要加载的Providers。

在「resteasy-jaxrs」里面设置了默认加载的providers:

$ pwd
/Users/weli/projs/resteasy/resteasy-upstream/resteasy-jaxrs/src
$ find . | grep javax.ws.rs.ext.Providers
./main/resources/META-INF/services/javax.ws.rs.ext.Providers
$ cat ./main/resources/META-INF/services/javax.ws.rs.ext.Providers
org.jboss.resteasy.plugins.providers.DataSourceProvider
org.jboss.resteasy.plugins.providers.DocumentProvider
org.jboss.resteasy.plugins.providers.DefaultTextPlain
org.jboss.resteasy.plugins.providers.DefaultNumberWriter
org.jboss.resteasy.plugins.providers.StringTextStar
org.jboss.resteasy.plugins.providers.SourceProvider
org.jboss.resteasy.plugins.providers.InputStreamProvider
org.jboss.resteasy.plugins.providers.ReaderProvider
org.jboss.resteasy.plugins.providers.ByteArrayProvider
org.jboss.resteasy.plugins.providers.FormUrlEncodedProvider
org.jboss.resteasy.plugins.providers.JaxrsFormProvider
org.jboss.resteasy.plugins.providers.FileProvider
org.jboss.resteasy.plugins.providers.FileRangeWriter
org.jboss.resteasy.plugins.providers.StreamingOutputProvider
org.jboss.resteasy.plugins.providers.IIOImageProvider
org.jboss.resteasy.plugins.interceptors.CacheControlFeature
org.jboss.resteasy.plugins.interceptors.ClientContentEncodingAnnotationFeature
org.jboss.resteasy.plugins.interceptors.ServerContentEncodingAnnotationFeature
org.jboss.resteasy.plugins.interceptors.MessageSanitizerContainerResponseFilter
org.jboss.resteasy.plugins.providers.sse.SseEventProvider
org.jboss.resteasy.plugins.providers.sse.SseEventOutputProvider
org.jboss.resteasy.plugins.providers.sse.SseEventSinkInterceptor

加载的逻辑在「RegisterBuiltin.java」里面:

$ pwd
/Users/weli/projs/resteasy/resteasy-upstream/resteasy-jaxrs/src
$ grep -rl 'META-INF' *
main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java
main/java/org/jboss/resteasy/plugins/providers/SerializableProvider.java
main/java/org/jboss/resteasy/spi/FactoryFinder.java
$ grep 'META-INF' main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java
	  Enumeration<URL> en = Thread.currentThread().getContextClassLoader().getResources("META-INF/services/" + Providers.class.getName());

如上所示,「RegisterBuiltin」会负责进行providers的加载工作。使用「RegisterBuiltin」的classes如下:

$ grep -rl 'RegisterBuiltin' *
main/java/org/jboss/resteasy/core/ThreadLocalResteasyProviderFactory.java
main/java/org/jboss/resteasy/mock/MockDispatcherFactory.java
main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java
main/java/org/jboss/resteasy/plugins/providers/sse/InboundSseEventImpl.java
main/java/org/jboss/resteasy/plugins/server/servlet/ConfigurationBootstrap.java
main/java/org/jboss/resteasy/spi/ResteasyDeployment.java
main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java

其中,「ResteasyDeployment」负责给「ResteasyProviderFactory」设置options:

$ grep -i 'builtin' main/java/org/jboss/resteasy/spi/ResteasyDeployment.java
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
   protected boolean registerBuiltin = true;
	  providerFactory.setRegisterBuiltins(registerBuiltin);
		 // Interceptor preferences should come before provider registration or builtin.
		 if (registerBuiltin)
			providerFactory.setRegisterBuiltins(true);
			RegisterBuiltin.register(providerFactory);
			providerFactory.setRegisterBuiltins(false);
   public boolean isRegisterBuiltin()
	  return registerBuiltin;
   public void setRegisterBuiltin(boolean registerBuiltin)
	  this.registerBuiltin = registerBuiltin;

而实际的加载部分则在「ResteasyProviderFactory」当中:

$ grep -i 'builtin' main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
	  public boolean isBuiltin = false;
	  private SortedKey(Class<?> intf, T reader, Class<?> readerClass, int priority, boolean isBuiltin)
		 this.isBuiltin = isBuiltin;
	  private SortedKey(Class<?> intf, T reader, Class<?> readerClass, boolean isBuiltin)
		 this.isBuiltin = isBuiltin;
		 // Sort user provider before builtins
		 if (isBuiltin == tMessageBodyKey.isBuiltin)
		 if (isBuiltin) return 1;
   public static boolean registerBuiltinByDefault = true;
   protected boolean builtinsRegistered = false;
   protected boolean registerBuiltins = true;
	  builtinsRegistered = false;
	  registerBuiltins = true;
			   if (registerBuiltinByDefault) RegisterBuiltin.register(instance);
   public static void setRegisterBuiltinByDefault(boolean registerBuiltinByDefault)
	  ResteasyProviderFactory.registerBuiltinByDefault = registerBuiltinByDefault;
   public boolean isRegisterBuiltins()
	  return registerBuiltins;
   public void setRegisterBuiltins(boolean registerBuiltins)
	  this.registerBuiltins = registerBuiltins;
   public boolean isBuiltinsRegistered()
	  return builtinsRegistered;
   public void setBuiltinsRegistered(boolean builtinsRegistered)
	  this.builtinsRegistered = builtinsRegistered;
   protected void addMessageBodyReader(Class<? extends MessageBodyReader> provider, int priority, boolean isBuiltin)
	  addMessageBodyReader(reader, provider, priority, isBuiltin);
   protected void addMessageBodyReader(MessageBodyReader provider, int priority, boolean isBuiltin)
	  addMessageBodyReader(provider, provider.getClass(), priority, isBuiltin);
	* @param isBuiltin
   protected void addMessageBodyReader(MessageBodyReader provider, Class<?> providerClass, int priority, boolean isBuiltin)
	  SortedKey<MessageBodyReader> key = new SortedKey<MessageBodyReader>(MessageBodyReader.class, provider, providerClass, priority, isBuiltin);
   protected void addMessageBodyWriter(Class<? extends MessageBodyWriter> provider, int priority, boolean isBuiltin)
	  addMessageBodyWriter(writer, provider, priority, isBuiltin);
	* @param isBuiltin
   protected void addMessageBodyWriter(MessageBodyWriter provider, Class<?> providerClass, int priority, boolean isBuiltin)
	  SortedKey<MessageBodyWriter> key = new SortedKey<MessageBodyWriter>(MessageBodyWriter.class, provider, providerClass, priority, isBuiltin);
   protected void addContextResolver(Class<? extends ContextResolver> resolver, boolean builtin)
	  addContextResolver(writer, resolver, builtin);
   protected void addContextResolver(ContextResolver provider, boolean builtin)
	  addContextResolver(provider, provider.getClass(), builtin);
   protected void addContextResolver(ContextResolver provider, Class providerClass, boolean builtin)
	  addContextResolver(provider, parameter, providerClass, builtin);
   protected void addContextResolver(ContextResolver provider, Type typeParameter, Class providerClass, boolean builtin)
	  SortedKey<ContextResolver> key = new SortedKey<ContextResolver>(ContextResolver.class, provider, providerClass, priority, builtin);
			if (!list.get(i).isBuiltin)
			if (list.get(i).isBuiltin)
   public void registerProvider(Class provider, boolean isBuiltin)
	  registerProvider(provider, null, isBuiltin, null);
   public void registerProvider(Class provider, Integer priorityOverride, boolean isBuiltin, Map<Class<?>, Integer> contracts)
	  processProviderContracts(provider, priorityOverride, isBuiltin, contracts, newContracts);
   protected void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin,
			addMessageBodyReader(provider, priority, isBuiltin);
			addMessageBodyWriter(provider, priority, isBuiltin);
			addContextResolver(provider, isBuiltin);
   public void registerProviderInstance(Object provider, Map<Class<?>, Integer> contracts, Integer priorityOverride, boolean builtIn)
	  processProviderInstanceContracts(provider, contracts, priorityOverride, builtIn, newContracts);
		 Integer priorityOverride, boolean builtIn, Map<Class<?>, Integer> newContracts)
			addMessageBodyReader((MessageBodyReader) provider, priority, builtIn);
			addMessageBodyWriter((MessageBodyWriter) provider, provider.getClass(), priority, builtIn);

以上是对于providers加载方面的分析。