1、Dubbo的IOC例子
@Test
public void test1(){
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
URL url = URL.valueOf("test://localhost/test");
adaptiveExtension.echo("d", url);
}
public class DubboAdaptiveExt implements AdaptiveExt {
// dubbo中有依赖AdaptiveExt类型的变量
private AdaptiveExt adaptiveExt;
public void setAdaptiveExt(AdaptiveExt adaptiveExt) {
this.adaptiveExt = adaptiveExt;
}
@Override
public String echo(String msg, URL url) {
System.out.println(this.adaptiveExt.echo(msg, url));
return "dubbo";
}
}
// 此时ThriftAdaptiveExt上面是标注了@Adaptive注解的
@Adaptive
public class ThriftAdaptiveExt implements AdaptiveExt {
@Override
public String echo(String msg, URL url) {
return "thrift";
}
}
2、Dubbo的IOC需要用到的ExtensionFactory
Spring的IOC中,给生成的bean注入依赖,是调用context.getBean(name)去获得要注入的bean.Dubbo的IOC类似,它通过ExtensionFactory类型的变量objectFactory去dubbo中获取bean,核心代码objectFactory.getExtension(pt, property)
.下面先分析一下objectFactory的创建过程.objectFactory需要用到SpringExtensionFactory和SpiExtensionFactory
.先看一下ExtenionFactory的实现类,如下图.下面通过源码分析objectFactory的生成过程.
这里的getExtensionLoader()详细分析可以参见: Dubbo的SPI机制1-SPI简单分析
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
// 删去一些不必要的代码,详细分析可以看前面几篇分析
// 从缓存中获取与拓展类对应的ExtensionLoader
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
// 若缓存未命中,则创建一个新的实例,创建新的实例时会走
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
private ExtensionLoader(Class<?> type) {
this.type = type;
// 这里的type是AdaptiveExt.class,所以会执行后面的代码,加载并创建SpiExtensionFactory
// 和SpringExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null :
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 创建自适应拓展代理类对象并放入缓存,这里创建的就是ExtensionFactory的自适应拓展对象
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
// 抛异常
}
}
}
}
}
return (T) instance;
}
private T createAdaptiveExtension() {
try {
// 分为3步:1是创建自适应拓展代理类Class对象,2是通过反射创建对象,3是给创建的对象按需依赖注入
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
// 抛异常
}
}
getExtensionClasses()方法详细分析可以参见: Dubbo的SPI机制1-SPI简单分析
private Class<?> getAdaptiveExtensionClass() {
// 这里前面文章已经分析过了,它会去加载默认目录下的ExtensionFactory的实现类,总共有3个,目录是
// META-INF/dubbo/internal/,该目录对应两个文件,文件内容见下,由于AdaptiveExtensionFactory上面
// 标注了@Adaptive注解,所以它优先级最高,它就是ExtensionFactory的默认实现类
getExtensionClasses();
// 如果有标注了@Adaptive注解实现类,那么cachedAdaptiveClass不为空,直接返回
if (cachedAdaptiveClass != null) {
// 这里直接返回,cachedAdaptiveClass = AdaptiveExtensionFactory.class
return cachedAdaptiveClass;
}
// 不会再走这一步
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
文件1内容:
// 其中AdaptiveExtensionFactory上面标注了@Adaptive注解
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
文件2内容:
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// 分析完了getAdaptiveExtensionClass(),它是返回AdaptiveExtensionFactory,接下来newInstance会
// 调用它默认的构造方法
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// 里面维护SpringExtensionFactory和SpiExtensionFactory
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()) {
// 分别给SpringExtensionFactory和SpiExtensionFactory创建对象并放入list中
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
}
3、Dubbo的IOC源码分析
// 上面已经分析过了第一行代码,这里面会创建ExtensionFactory类型的变量objectFactory,这里面维护了一个list,
// list里面有SpringExtensionFactory和SpiExtensionFactory类型的实例,Dubbo的IOC获取bean就是通过这两个
// 变量去获取的
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
public T getExtension(String name) {
// 删去一些代码
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 创建拓展实例
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
private T createExtension(String name) {
// 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
// 这里我们指定了名字dubbo,并不是通过getAdaptiveExtension方法去获得自适应拓展类,这点要区分
// 所以这里拿到的是com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// 也是尝试先从缓存获取,获取不到通过反射创建一个并放到缓存中
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
// 这里直接通过反射创建DubboAdaptiveExt的实例,然后给他依赖注入
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 依赖注入
injectExtension(instance);
return instance;
}
}
private T injectExtension(T instance) {
// 这里为了排版好看,删去一些异常捕捉抛出代码
// objectFactory就是我们前面分析的,它里面维护了SpringExtensionFactory和SpiExtensionFactory类型的实例
if (objectFactory != null) {
// 遍历DubboAdaptiveExt实例的所有方法,寻找set开头且参数为1个,且方法权限为public的方法
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
// 获取参数类型,这里是AdaptiveExt.class
Class<?> pt = method.getParameterTypes()[0];
// 获取属性名,这里是adaptiveExt
String property =
method.getName().length() > 3 ?
method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
// 获取容器中AdaptiveExt.class类型的名字为adaptiveExt的实例
Object object = objectFactory.getExtension(pt, property);
// 获取之后通过反射赋值
if (object != null) {
method.invoke(instance, object);
}
}
}
}
return instance;
}
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
@Override
public <T> T getExtension(Class<T> type, String name) {
// 遍历factory中所有的ExtensionFactory,先从SpiExtensionFactory中获取,获取不到在去Spring容器中获取
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
这里获取自适应拓展可以参考: Dubbo的SPI机制分析2-Adaptive详解
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()) {
// 先看SpiExtensionFactory怎么获取,它是通过getAdaptiveExtension()去自适应获取,根本
// 没有用到name,所以这里返回ThriftAdaptiveExt的实例
return loader.getAdaptiveExtension();
}
}
return null;
}
}
public class SpringExtensionFactory implements ExtensionFactory {
// 可以看到Spring是先根据名字去取,取不到再根据类型去取
@Override
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
for (ApplicationContext context : contexts) {
try {
return context.getBean(type);
}
}
return null;
}
}
// 所以这段代码输出:thrift
@Test
public void test1(){
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
URL url = URL.valueOf("test://localhost/test");
adaptiveExtension.echo("d", url);
}
4、测试通过URL依赖注入
/**
* 测试通过URL依赖注入,将ThriftAdaptiveExt类上面的注解注释掉,同时给AdaptiveExt方法加上注解@Adaptive("t")
*/
@Test
public void test5(){
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
Map<String, String> map = new HashMap<>();
// t这个key就是根据@Adaptive("t")定的,两者要一致
map.put("t", "cloud");
URL url = new URL("", "", 1, map);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
adaptiveExtension.echo(" ", url);
}
上述代码输出spring cloud,创建完DubboAdaptiveExt的实例给其注入依赖时,调用injectExtension(instance),因为没有了@Adaptive标注的类,所以需要Dubbo自己生成自适应拓展代理类Class,生成过程可以参考: Dubbo的SPI机制分析2-Adaptive详解.生成的代理类中有这样一句关键代码: String extName = url.getParameter("t", "dubbo")
,因为url中有这个t参数,所以最后会调用cloud所对应的SpringCloudAdaptiveExt的echo方法,输出spring cloud.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。