二. Dubbo 中的依赖注入
Dubbo 依赖注入和核心逻辑是通过 Set 方法进行依赖注入,会在 Dubbo SPI 或者 Spring SPI 中查找对象。
// 依赖注入 private T injectExtension(T instance) { if (objectFactory == null) { return instance; } try { for (Method method : instance.getClass().getMethods()) { if (!isSetter(method)) { continue; } if (method.getAnnotation(DisableInject.class) != null) { continue; } // 获取 set 方法参数类型 Class<?> pt = method.getParameterTypes()[0]; if (ReflectUtils.isPrimitives(pt)) { continue; } try { // 获取 setXXX 中的 xxx String property = getSetterProperty(method); Object object = objectFactory.getExtension(pt, property); // Car.class, car if (object != null) { // 根据参数类型或属性名,从 objectFactory 中获取到对象,然后调用 set 方法进行依赖注入 method.invoke(instance, object); } } catch (Exception e) { logger.error("Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; } // ExtensionLoader private ExtensionLoader(Class<?> type) { this.type = type; // ExtensionLoader 表示拓展类实例工程,可以利用 ExtensionFactory 得到某个拓展的对象实例 // 或者得到 ExtensionFactory 接口的 AdaptiveExtensionFactory 实例, 利用 AdaptiveExtensionFactory 来获取某个类的实例 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); } // AdaptiveExtensionFactory 构造方法 public AdaptiveExtensionFactory() { // 支持那些 ExtensionFactory (Spring, SPI) ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); } // SpringExtensionFactory#getExtension 在 Spring 容器中去查找Bean public <T> T getExtension(Class<T> type, String name) { // 如果有 @SPI 修饰就不管 if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { return null; } // 首先 byName, 然后 byType for (ApplicationContext context : CONTEXTS) { T bean = BeanFactoryUtils.getOptionalBean(context, name, type); if (bean != null) { return bean; } } return null; } // SpiExtensionFactory#getExtension public <T> T getExtension(Class<T> type, String name) { // 接口上的 SPI 注解 if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); if (!loader.getSupportedExtensions().isEmpty()) { return loader.getAdaptiveExtension(); // 接口的 Adaptive 对象 } } return null; } // ExtensionLoader public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError != null) { throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { // 如果不存在就创建 instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { createAdaptiveInstanceError = t; throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); } } } } return (T) instance; } // 获取 AdaptiveExtensionClass private Class<?> getAdaptiveExtensionClass() { // 获取当前接口的所有拓展类 getExtensionClasses(); // 缓存了 @Adaptive 注解标记类 if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } // 如果某个接口没有手动指定 Adaptive, 那么就生成一个 Adaptive 类 return cachedAdaptiveClass = createAdaptiveExtensionClass(); } // 创建代理类 private Class<?> createAdaptiveExtensionClass() { // 生成代码 String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); ClassLoader classLoader = findClassLoader(); org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
三. Dubbo 中的 AOP
dubbo中也实现了一套非常简单的 AOP,就是利用 Wrapper.class ,如果一个接口的扩展点中包含了多个 Wrapper 类,那么在实例化完某个扩展点后,就会利用这些 Wrapper 类对这个实例进行包裹,比如:现在有一个 DubboProtocol 的实例,同时对于 Protocol 这个接口还有很多的 Wrapper,比如 ProtocolFilterWrapper、ProtocolListenerWrapper,那么,当对 DubboProtocol 的实例完成了IOC之后,就会先调用 new ProtocolFilterWrapper(DubboProtocol实例) 生成一个新的Protocol的实例,再对此实例进行IOC,完了之后,会再调用new ProtocolListenerWrapper(ProtocolFilterWrapper实例)生成一个新的Protocol的实例,然后进行IOC,从而完成DubboProtocol实例的AOP。
// ExtensionLoader#createExtension if (wrap) { List<Class<?>> wrapperClassesList = new ArrayList<>(); if (cachedWrapperClasses != null) { wrapperClassesList.addAll(cachedWrapperClasses); wrapperClassesList.sort(WrapperComparator.COMPARATOR); Collections.reverse(wrapperClassesList); } if (CollectionUtils.isNotEmpty(wrapperClassesList)) { for (Class<?> wrapperClass : wrapperClassesList) { Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); if (wrapper == null || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } }
四. Dubbo 中的 Adaptive 机制
每个扩展点都有一个name,通过这个name可以获得该name对应的扩展点实例,但是有的场景下,希望一次性获得多个扩展点实例,可以通过传入多个name来获取,可以通过识别URL上的信息来获取:
extensionLoader.getActivateExtension(url, new String[]{"car1", "car2"}); 这个可以拿到name为car1和car2的扩展类实例,同时还会通过传入的url寻找可用的扩展类, 怎么找的呢?
在一个扩展点类上,可以添加 @Activate
注解,这个注解的属性有:
- String[] group():表示这个扩展点是属于拿组的,这里组通常分为
PROVIDER
和CONSUMER
,表示该扩展点能在服务提供者端,或者消费端使用
- String[] value():指示的是URL中的某个参数 key,当利用
getActivateExtension
方法来寻找扩展点时,如果传入的url中包含的参数的所有 key 中,包括了当前扩展点中的 value 值,那么则表示当前 url 可以使用该扩展。