示例接口如下:
@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; }