How does Dubbo extend Java

1.Java SPI and Dubbo ExtensionLoader

  • 1.SPI Service Provider Interface is a set of apis provided by Java that can be implemented or extended by third parties. It can be used to enable framework extensions and replace components. You can simply understand that Java provides an interface that can also be implemented by vendor A or vendor B. That is, when a Client calls an interface, Java loads all of the implementation classes for that interface. Without further ado, let’s give some examples
  • Define an interface and two classes
``` Java public interface Robot { void sayHello(); } ` ` `
Robot public class Bumblebee implements Robot {public void sayHello() {system.out.println (" Hello,I am Bumblebee"); }} ` ` `
Robot public class OptimusPrime implements Robot {public void sayHello() {system.out.println (" Hello I am Optimus prime "); }} ` ` `
  • Then create the corresponding directory Services figure under the Resources folder and inhale the full class names of the two implementation classes

  • Program execution result
  • hello ,I am Bumblebee
  • hello i am Optimus prime
  • The principle of analytic
Iterator Iterator = load. Iterator (); Iterator = load. Iterator (); while (iterator.hasNext()) { iterator.next().sayHello(); } ` ` `
  • There is an inner class LazyIterator inside the ServiceLoader
  • Implementation process

  • private static final String PREFIX = “META-INF/services/”;
  • Get the full class name of the interface corresponding to “meta-INF /services/+”
  • If yes, run the pending = parse(service, configs.nextelement ()) command. Returns the corresponding implementation class in Iterator order.

  • Service implementation: one is the loading of local services,
  • Mode uses the policy mode + configuration file method to record the implementation class of the corresponding interface.
  • What’s bad about JavaSPI’s implementation?
  • 1. Load the service implementation in full
  • 2. No cache
  • 3. Do not use a single Service Provider

Dubbo ExtensionLoader

  • Example:
  • Classes and interfaces Implementation classes that are the same as the Java Spi
  • The difference here is that beanName = the full name of the class
```Java ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class); / / get the corresponding element Robot bumblebee = extensionLoader. GetExtension (" bumblebee "); bumblebee.sayHello(); Robot optimusPrime = extensionLoader.getExtension("optimusPrime"); optimusPrime.sayHello(); ` ` `
  • Program running result
  • hello ,I am Bumblebee
  • hello i am Optimus prime
  • Analysis of execution Principle
  • Call the procedure ExtensionLoader
  • ExtensionLoader.getExtensionLoader(Robot.class);
  • com.alibaba.dubbo.common.extension.ExtensionLoader#getExtensionLoader()
  • com.alibaba.dubbo.common.extension.ExtensionLoader#ExtensionLoader()
  • The SpiFactory in ExtensionFactory is initialized first
  • objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
  • Initialize the business class after loading ExtensionFactory
  • Credit loads the corresponding Classes
  • com.alibaba.dubbo.common.extension.ExtensionLoader#getExtensionClasses()
  • com.alibaba.dubbo.common.extension.ExtensionLoader#loadExtensionClasses()
```Java final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation ! = null) { String value = defaultAnnotation.value(); If ((value = value.trim()).length() > 0) {// Split @spi ("impl1") value String[] names = name_separate.split (value); if (names.length > 1) { throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } // Put value into cachedDefaultName if (names.length == 1) cachedDefaultName = names[0]; } } Map> extensionClasses = new HashMap>(); // DUBBO_INTERNAL_DIRECTORY : "META-INF/dubbo/internal/" loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); // DUBBO_DIRECTORY : "META-INF/dubbo/" loadDirectory(extensionClasses, DUBBO_DIRECTORY); // SERVICES_DIRECTORY: "META-INF/services/" loadDirectory(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; ` ` `
  • After loading the class file, the following results are returned

  • Get the corresponding Class, createExtension() to get the corresponding Interface Provider, clazz.newinstance () to return the instance com.alibaba.dubbo.common.extension.ExtensionLoader#createExtension();

  • High performance ExtensionLoader has different caches. Both cache Classes and instances are singletons, and the double check method does this by taking Classes from the cache, loading them, creating them, and then putting them back in the cache.

Class ->ExtensionLoader private Static Final ConcurrentMap, ExtensionLoader> EXTENSION_LOADERS = new ConcurrentHashMap, ExtensionLoader>(); Private static final ConcurrentMap, Object> EXTENSION_INSTANCES = new ConcurrentHashMap, Object>(); / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = / / the Extension of the current Class type private final Class type. // ExtensionFactory; SpiExtensionFactory , AdaptiveExtensionFactory , SpringFactory private final ExtensionFactory objectFactory; Private final ConcurrentMap; private final ConcurrentMap; String> cachedNames = new ConcurrentHashMap, String>(); Private final Holder>> cachedClasses = new Holder>>(); Private final Map cachedInvariant = new; // Activate activates a class that activates automatically ConcurrentHashMap(); // private final ConcurrentMap> cachedInstances = new ConcurrentHashMap>(); Private final Holder cachedAdaptiveInstance = new Holder(); // @adaptice bytecode file private volatile Class cachedAdaptiveClass = null; // Cache extension class name private String cachedDefaultName; ` ` `
  • The JavaSpI problem is solved by using BeanName to obtain different Service providers.
  • When loading, check the cache for further loading rather than full loading as in JavaSpI.