反正我收藏了!Apache Dubbo介绍以及扩展机制SPI( 三 )

上面的代码并不复杂 , 主要的步骤是:

  1. 通过 getExtensionClasses 获取所有拓展类
  2. 通过反射创建拓展对象
  3. 向拓展对象注入依赖
  4. 将拓展对象包裹进对应的 Wrapper 对象中
  5. 初始化对象
上面步骤为大致上的步骤 , 下面我们分步来细讲 。
第一步第一步主要是获取所有拓展类 。 我们来看看 getExtensionClasses() 的代码 。
private Map> getExtensionClasses() {//从spi注解中获取默认名字并挂载在cachedDefaultName这个属性上Map> classes = cachedClasses.get();//如果为空 , 则进行全部加载if (classes == null) {synchronized (cachedClasses) {classes = cachedClasses.get();if (classes == null) {//加载扩展类classes = loadExtensionClasses();cachedClasses.set(classes);}}}return classes;}上面代码主要是为加载拓展类进行判断
private Map> loadExtensionClasses() {//缓存组件的名称cacheDefaultExtensionName();Map> extensionClasses = new HashMap<>();//加载策略for (LoadingStrategy strategy : strategies) {loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());}return extensionClasses;}private void cacheDefaultExtensionName() {//获取注解 @SPIfinal SPI defaultAnnotation = type.getAnnotation(SPI.class);if (defaultAnnotation == null) {return;}//注解的值String value = http://kandian.youth.cn/index/defaultAnnotation.value();if ((value = value.trim()).length()> 0) {String[] names = NAME_SEPARATOR.split(value);if (names.length > 1) {//throw Exception}if (names.length == 1) {cachedDefaultName = names[0];}}}loadDirectory 方法就是加载某目录下的资源 , 然后通过 loadResource 方法加载资源 。 我们继续跟下去 。
private void loadDirectory(Map> extensionClasses, String dir, String type,boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {String fileName = dir + type;try {Enumeration urls = null;//获取 classLoaderClassLoader classLoader = findClassLoader();//获取 ClassLoader 这里会尝试以拓展类所在的类加载器为首要对象if (extensionLoaderClassLoaderFirst) {ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {urls = extensionLoaderClassLoader.getResources(fileName);}}if (urls == null || !urls.hasMoreElements()) {if (classLoader != null) {urls = classLoader.getResources(fileName);} else {urls = ClassLoader.getSystemResources(fileName);}}if (urls != null) {while (urls.hasMoreElements()) {java.net.URL resourceURL = urls.nextElement();loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);}}} catch (Throwable t) {//...}}loadResource 方法主要是读取文件 , 然后解析文件内容 , 通过反射加载类后 , 然后调用 loadClass 方法进行操作缓存 。 代码如下:
private void loadResource(Map> extensionClasses, ClassLoader classLoader,java.net.URL resourceURL, boolean overridden, String... excludedPackages) {try {try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {String line;while ((line = reader.readLine()) != null) {// # 分割 , 只要 # 前面的内容final int ci = line.indexOf('#');if (ci >= 0) {line = line.substring(0, ci);}line = line.trim();if (line.length() > 0) {try {String name = null;// = 符号进行分割 , 分别拿到键值对// 键 为别名 , 值为类的全限定名int i = line.indexOf('=');if (i > 0) {name = line.substring(0, i).trim();line = line.substring(i + 1).trim();}if (line.length() > 0}} catch (Throwable t) {//throw Exception}}}}} catch (Throwable t) {//...}}loadClass
private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name,boolean overridden) throws NoSuchMethodException {if (!type.isAssignableFrom(clazz)) {throw new IllegalStateException("Error occurred when loading extension class (interface: " +type + ", class line: " + clazz.getName() + "), class "+ clazz.getName() + " is not subtype of interface.");}//如果 class 有 Adapter 注解if (clazz.isAnnotationPresent(Adaptive.class)) {cacheAdaptiveClass(clazz, overridden);} else if (isWrapperClass(clazz)) { //是否是扩展类 , 是的话就加入 cachedWrapperClasses 属性cacheWrapperClass(clazz);} else {clazz.getConstructor();//检测是否有默认构造起if (StringUtils.isEmpty(name)) {//// 如果 name 为空 , 则尝试从 Extension 注解中获取 name , 或使用小写的类名作为 namename = findAnnotationName(clazz);if (name.length() == 0) {//throw Exception}}//分割名字String[] names = NAME_SEPARATOR.split(name);if (ArrayUtils.isNotEmpty(names)) {//存储 name 和 Activate 到 cachedActivatescacheActivateClass(clazz, names[0]);for (String n : names) {//存储 Class 到名字的映射关系cacheName(clazz, n);//存储名字到 Class 的映射关系saveInExtensionClass(extensionClasses, clazz, n, overridden);}}}}