dubbo 代理和自动注入原理

示例接口如下:

@SPI
public interface BallInterface {
    @Adaptive("ball")
    String getBall(URL url);
}

dubbo的代理有两种情况:

(1)基于构造函数的静态代理(通过简单的包装对象进行操作)

public class ConstructBallInterface implements BallInterface {
    private BallInterface ballInterface;

    //通过构造函数进行代理
    public ConstructBallInterface(BallInterface ballInterface) {
        this.ballInterface = ballInterface;
    }

    @Override
    public String getBall(URL url) {
        System.out.println("start");
        String bbb = ballInterface.getBall(url);
        System.out.println("end");
        return bbb;
    }
}

(2)动态代理有两种方式:

(2-1)通过@Adaptive注解的动态代理

@Adaptive//这个注解很关键,如果有了这个注解并实现接口,就不会动态生成代理类型load进行来
public class AnnotationBallInterface implements BallInterface {

    @Override
    public String getBall(URL url) {
        System.out.println("start");
        return "1";
    }
}

(2-2)通过AdaptiveClassCodeGenerator的字节码生成动态代理

在生成动态代理类的过程中,我们看下dubbo的自动注入机制,dubbo的自动注入机制是通过两个关键点:

1.判断是否有set方法

2.判断set方法参数是否为标记了@SPI注解

获取接口实现类:

  ExtensionLoader<BallInterface> service = ExtensionLoader.getExtensionLoader(BallInterface.class);
  URL url = new URL("", "", 12, new HashMap<String, String>() {{
put("ball", "ui");
}});
 BallInterface red = service.getExtension("red");

调用injectExtension方法,在这里通过AdaptiveExtensionFactory类的getExtension获取扩展,这里使用了我们上文提到了的基于注解的代理方式。

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        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);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

在这里间接获取的ExtensionFactory的SPI实现类是SpiExtensionFactory,而getAdaptiveExtension方法中就是获取动态代理对象

public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (!loader.getSupportedExtensions().isEmpty()) {
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }
}

 上面的方法中实际创建了动态代码对象后调用generate方法生成类:new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();,generate方法实现如下:

public String generate() {
        // no need to generate adaptive class since there's no adaptive method found.
        if (!hasAdaptiveMethod()) {
            throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
        }

        StringBuilder code = new StringBuilder();
        code.append(generatePackageInfo());
        code.append(generateImports());
        code.append(generateClassDeclaration());

        Method[] methods = type.getMethods();
        for (Method method : methods) {
            code.append(generateMethod(method));
        }
        code.append("}");

        if (logger.isDebugEnabled()) {
            logger.debug(code.toString());
        }
        return code.toString();
    }

生成的类内容如下,动态代理对象需要依赖外部的URL参数,来完成对持有对象的控制,URL是dubbo中的数据传递总线:

package test;

import org.apache.dubbo.common.extension.ExtensionLoader;

public class BallInterface$Adaptive implements test.BallInterface {
    public java.lang.String getBall(org.apache.dubbo.common.URL arg0) {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg0;
        String extName = url.getParameter("ball");//动态代理对象需要依赖外部的URL参数,来完成对持有对象的控制
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (test.BallInterface) name from url (" + url.toString() + ") use keys([ball])");
        test.BallInterface extension = (test.BallInterface) ExtensionLoader.getExtensionLoader(test.BallInterface.class).getExtension(extName);
        return extension.getBall(arg0);
    }
}

 我们回到injectExtension方法中,反射set方法将代理对象传入方法中:

  private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * Check {@link DisableInject} to see if we need auto injection for this property
                 */
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    String property = getSetterProperty(method);
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                        method.invoke(instance, object);//反射调用set方法进行注入
                    }
                } 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;
    }
原文地址:https://www.cnblogs.com/zzq-include/p/12258574.html