前言

之前我们了解了整个class的加载过程,但是里面还有一些内容需要了解下,就是标记了adaptive的注解。

在 Dubbo 中,仅有两个类被 Adaptive 注解了,分别是 AdaptiveCompilerAdaptiveExtensionFactory。此种情况,表示拓展的加载逻辑由人工编码完成。更多时候,Adaptive 是注解在接口方法上的,表示拓展的加载逻辑需由框架自动生成。Adaptive 注解的地方不同,相应的处理逻辑也是不同的。一般类上的比较简单,方法上的比较复杂,这里根据上次的SPI继续了解分析。

目的

dubbo通过SPI机制就能加载类,但是有些类不希望直接加载,而是系统在扩展方法加载的时候,进行加载。所以才需要Adaptive方式。自适应拓展机制的实现逻辑比较复杂,首先 Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。最后再通过反射创建代理类

获取adaptive

下面是adaptive的源码。

  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target({ElementType.TYPE, ElementType.METHOD})
  4. public @interface Adaptive {
  5. String[] value() default {};
  6. }

当加载Loader时,我们首先要构建它。这里会设置下factory,会拿到默认的getAdaptiveExtension

  1. private ExtensionLoader(Class<?> type) {
  2. this.type = type;
  3. objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
  4. }

getAdaptiveExtension

  1. public T getAdaptiveExtension() {
  2. // 从缓存中获取自适应拓展
  3. Object instance = cachedAdaptiveInstance.get();
  4. if (instance == null) {
  5. if (createAdaptiveInstanceError != null) {
  6. throw new IllegalStateException("Failed to create adaptive instance: " +
  7. createAdaptiveInstanceError.toString(),
  8. createAdaptiveInstanceError);
  9. }
  10. synchronized (cachedAdaptiveInstance) {
  11. instance = cachedAdaptiveInstance.get();
  12. if (instance == null) {
  13. try {
  14. // 创建自适应拓展
  15. instance = createAdaptiveExtension();
  16. cachedAdaptiveInstance.set(instance);
  17. } catch (Throwable t) {
  18. createAdaptiveInstanceError = t;
  19. throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
  20. }
  21. }
  22. }
  23. }
  24. return (T) instance;
  25. }
  26. private T createAdaptiveExtension() {
  27. try {
  28. // 获取自适应拓展类,并通过反射实例化
  29. return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  30. } catch (Exception e) {
  31. throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
  32. }
  33. }

下面的create才是真正的方法,它包含了好几个逻辑。

  1. getAdaptiveExtensionClass()获取到这个class。
  2. 对这个class进行实例化。
  3. 进行扩展对象的注入。这里特别注入,我们的自适应扩展adapter有2种情况,一种是手动编码的,一种是自动生成的。手动编码的类可能需要我们注入其他的类依赖。

getAdaptiveExtensionClass

  1. private Class<?> getAdaptiveExtensionClass() {
  2. //加载该type所有的class
  3. getExtensionClasses();
  4. //上一步加载时,如果loadClass()方法里面有判断,如果class类上标记了Adaptive就会缓存进去
  5. //clazz.isAnnotationPresent(Adaptive.class)
  6. if (cachedAdaptiveClass != null) {
  7. return cachedAdaptiveClass;
  8. }
  9. //创建自适应类
  10. return cachedAdaptiveClass = createAdaptiveExtensionClass();
  11. }
  12. //使用class编译创建出来类
  13. private Class<?> createAdaptiveExtensionClass() {
  14. String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
  15. ClassLoader classLoader = findClassLoader();
  16. org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  17. return compiler.compile(code, classLoader);
  18. }

我们知道当ExtensionFactory的 AdaptiveExtensionFactory 就有这个Adapter标记,所以当时new ``ExtensionLoader 时,就直接返回了此类。对于没有标记这个的,我们后面再看下这个自动生成。先看下注入。

injectExtension

这里dubbo的IOC体现了,拿到class后会进行注入操作。

  1. private T injectExtension(T instance) {
  2. //如果是factory,没必要注入了
  3. if (objectFactory == null) {
  4. return instance;
  5. }
  6. try {
  7. // 遍历目标类的所有方法
  8. for (Method method : instance.getClass().getMethods()) {
  9. if (!isSetter(method)) {
  10. continue;
  11. }
  12. /**
  13. * Check {@link DisableInject} to see if we need auto injection for this property
  14. */
  15. if (method.getAnnotation(DisableInject.class) != null) {
  16. continue;
  17. }
  18. Class<?> pt = method.getParameterTypes()[0];
  19. if (ReflectUtils.isPrimitives(pt)) {
  20. continue;
  21. }
  22. try {
  23. // 获取属性名,比如 setName 方法对应属性名 name
  24. String property = getSetterProperty(method);
  25. //从dubbo总的factory加载容器中,找到这个class实例
  26. Object object = objectFactory.getExtension(pt, property);
  27. if (object != null) {
  28. //调用方法注入
  29. method.invoke(instance, object);
  30. }
  31. } catch (Exception e) {
  32. logger.error("Failed to inject via method " + method.getName()
  33. + " of interface " + type.getName() + ": " + e.getMessage(), e);
  34. }
  35. }
  36. } catch (Exception e) {
  37. logger.error(e.getMessage(), e);
  38. }
  39. return instance;
  40. }

这里的理解就是,当我们写了一个类时,需要Loader加载时,这时候Loader加载的时候,会帮我们将这个class的setting方法都注入好实例。例如:

  1. public class DubboBumbleBee implements DubboRobot {
  2. private ExtensionFactory extensionFactory;
  3. @Override
  4. public void sayHello() {
  5. System.out.println("dubbo spi amazing.");
  6. }
  7. public ExtensionFactory getExtensionFactory() {
  8. return extensionFactory;
  9. }
  10. //这里当ExtensionLoader加载这个class时,发现方法含有set注入,然后就会再次查找加载extensionFactory
  11. //循环加载到extensionLoader时,就会设置注入进去
  12. public void setExtensionFactory(ExtensionFactory extensionFactory) {
  13. this.extensionFactory = extensionFactory;
  14. }
  15. }

AdaptiveExtensionFactory

我们所有的dubbo相关的类,都是通过这个默认加载的。

  1. //标记了Adaptive,手动编写的
  2. @Adaptive
  3. public class AdaptiveExtensionFactory implements ExtensionFactory {
  4. //SpiExtensionFactory:dubbo自己的方式,通过spi获取到实例
  5. //SpringExtensionFactory:设置spring的ApplicationContext,然后获取拿到信息
  6. private final List<ExtensionFactory> factories;
  7. //创建时,拿到所有的factory,并注入进去
  8. public AdaptiveExtensionFactory() {
  9. ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
  10. List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
  11. for (String name : loader.getSupportedExtensions()) {
  12. list.add(loader.getExtension(name));
  13. }
  14. factories = Collections.unmodifiableList(list);
  15. }
  16. @Override
  17. public <T> T getExtension(Class<T> type, String name) {
  18. for (ExtensionFactory factory : factories) {
  19. T extension = factory.getExtension(type, name);
  20. if (extension != null) {
  21. return extension;
  22. }
  23. }
  24. return null;
  25. }
  26. }

AdaptiveClassCodeGenerator

如果类上标记了Adaptive 注解,那么再getAdaptiveExtension() 时,将会直接返回。如果没有标记,是class的方法上标记的,这时候就需要这个generator进行处理生成了。

generate

总的生成方法

  1. /**
  2. * generate and return class code
  3. */
  4. public String generate() {
  5. // no need to generate adaptive class since there's no adaptive method found.
  6. // 检测方法上是否有 Adaptive 注解
  7. if (!hasAdaptiveMethod()) {
  8. throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
  9. }
  10. StringBuilder code = new StringBuilder();
  11. // 生成 package 代码:package + type 所在包
  12. code.append(generatePackageInfo());
  13. // 生成 import 代码:import + ExtensionLoader 全限定名
  14. code.append(generateImports());
  15. // 生成类代码:public class + type简单名称 + $Adaptive + implements + type全限定名 + {
  16. code.append(generateClassDeclaration());
  17. Method[] methods = type.getMethods();
  18. for (Method method : methods) {
  19. //生成类的方法
  20. code.append(generateMethod(method));
  21. }
  22. code.append("}");
  23. if (logger.isDebugEnabled()) {
  24. logger.debug(code.toString());
  25. }
  26. return code.toString();
  27. }

generateMethod

这里面主要的方法就是生产方法的主体

  1. private String generateMethod(Method method) {
  2. String methodReturnType = method.getReturnType().getCanonicalName();
  3. String methodName = method.getName();
  4. //生成方法主体
  5. String methodContent = generateMethodContent(method);
  6. String methodArgs = generateMethodArguments(method);
  7. String methodThrows = generateMethodThrows(method);
  8. return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
  9. }

generateMethodContent

  1. private String generateMethodContent(Method method) {
  2. Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
  3. StringBuilder code = new StringBuilder(512);
  4. if (adaptiveAnnotation == null) {
  5. //不存在,生成不支持的方法
  6. return generateUnsupported(method);
  7. } else {
  8. //遍历method.getParameterTypes()获取参数URL
  9. int urlTypeIndex = getUrlTypeIndex(method);
  10. // found parameter in URL type
  11. if (urlTypeIndex != -1) {
  12. // Null Point check,添加判空处理
  13. code.append(generateUrlNullCheck(urlTypeIndex));
  14. } else {
  15. // did not find parameter in URL type
  16. // 如果参数中没有找到URL,那么继续通过method.getParameterTypes()获取所有的参数
  17. // 找下哪个参数含有getUrl()方法
  18. code.append(generateUrlAssignmentIndirectly(method));
  19. }
  20. //获取方法注解的Adaptive的值,如果没有获取类名,并将类名转换为字符数组
  21. String[] value = getMethodAdaptiveValue(adaptiveAnnotation);
  22. //是否含有Invocation参数
  23. boolean hasInvocation = hasInvocationArgument(method);
  24. //含有Invocation参数进行判空处理
  25. code.append(generateInvocationArgumentNullCheck(method));
  26. //开始从参数中获取真正的方法,获取路径有
  27. //url.getParameter url.getMethodParameter url.getProtocol()
  28. code.append(generateExtNameAssignment(value, hasInvocation));
  29. // check extName == null? 判空处理
  30. code.append(generateExtNameNullCheck(value));
  31. // 生成Loder
  32. code.append(generateExtensionAssignment());
  33. // return statement
  34. code.append(generateReturnAndInvocation(method));
  35. }
  36. return code.toString();
  37. }

经过如上方法,便生成了代理class的文件,然后进行代理class的生成。

例子

这里以ProxyFactory 为例,自适应加载类。ProxyFactory 的源码如下:

  1. @SPI("javassist")
  2. public interface ProxyFactory {
  3. @Adaptive({"proxy"})
  4. <T> T getProxy(Invoker<T> invoker) throws RpcException;
  5. @Adaptive({"proxy"})
  6. <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
  7. @Adaptive({"proxy"})
  8. <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
  9. }

结果代理类后,生成的代理类如下:

  1. package org.apache.dubbo.rpc;
  2. import org.apache.dubbo.common.extension.ExtensionLoader;
  3. public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory {
  4. public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
  5. if (arg0 == null)
  6. throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
  7. if (arg0.getUrl() == null)
  8. throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
  9. org.apache.dubbo.common.URL url = arg0.getUrl();
  10. String extName = url.getParameter("proxy", "javassist");
  11. if(extName == null)
  12. throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
  13. org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
  14. return extension.getProxy(arg0);
  15. }
  16. public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) throws org.apache.dubbo.rpc.RpcException {
  17. if (arg0 == null)
  18. throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
  19. if (arg0.getUrl() == null)
  20. throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
  21. org.apache.dubbo.common.URL url = arg0.getUrl();
  22. String extName = url.getParameter("proxy", "javassist");
  23. if(extName == null)
  24. throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
  25. org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
  26. return extension.getProxy(arg0, arg1);
  27. }
  28. public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException {
  29. if (arg2 == null) throw new IllegalArgumentException("url == null");
  30. org.apache.dubbo.common.URL url = arg2;
  31. String extName = url.getParameter("proxy", "javassist");
  32. if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
  33. org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
  34. return extension.getInvoker(arg0, arg1, arg2);
  35. }
  36. }

当使用这个方法时,我们才会从代理类中,进行加载类。由url.getParameter url.getMethodParameter url.getProtocol() 不同方法来获取处理。

参考