分布式RPC系统框架Dubbo-22Dubbo的内核解析-Adaptive机制

        Adaptive机制,即扩展类的自适应机制;其可以指定想要加载的扩展类名,也可以不指定,若不指定则直接加载默认的扩展类,会自动匹配,做到自适应,通过@Adaptive注解实现;

1 @Adaptive注解

@Adaptive注解可以修饰类与方法,其作用相差很大;

1.1 @Adaptive修饰类

被@Adaptive修饰的SPI接口扩展类称为Adaptive类,表示该SPI扩展类会按照该类中指定的方式获取,即用于固定实现方式,其是装饰者设计模式的应用;dubbo中只有两个@Adaptive修饰类;

1.1.1 dubbo源码

  • org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory

/**
 * AdaptiveExtensionFactory
 * 指定ExtensionFactory获取方式,就一种SPI
 * 由@Adaptive修饰的类,只能固定的使用getExtension(Class<T> type, String name) 
 * 方法中写死的方式获取Extension;
 */
@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);
    }
//@Adaptive修饰类固定的方式获取Extension的方法
    @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;
    }

}

adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
  • org.apache.dubbo.common.compiler.support.AdaptiveCompiler

提供两种编译方式:jdk与javassist,默认是javassist;

adaptive=org.apache.dubbo.common.compiler.support.AdaptiveCompiler
jdk=org.apache.dubbo.common.compiler.support.JdkCompiler
javassist=org.apache.dubbo.common.compiler.support.JavassistCompiler
/**
 * AdaptiveCompiler. (SPI, Singleton, ThreadSafe)
 * 限定只能通过两种方式编译,只提供了jdk与javassist
 */
@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }

    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }

}

1.1.2 示例

(1)创建工程adaptiveclass导入dubbo依赖

<!-- dubbo依赖 --> 
	<dependency>
	    <groupId>org.apache.dubbo</groupId>
	    <artifactId>dubbo</artifactId>
	    <version>2.7.0</version>
	</dependency>

(2)定义提供者路径及配置文件

alipay=com.zxy.spi.extension.AlipayOrder
wechat=com.zxy.spi.extension.WeChatOrder
adaptive=com.zxy.spi.extension.AdaptiveOrder

(3)定义接口及实现类

/**
 * SPI标签,设置默认为alipay阿里支付
 */
@SPI("alipay")
public interface Order {
	String way();
}
/**
 * 自适应(扩展)实现类
 */
@Adaptive
public class AdaptiveOrder implements Order{
	
	private String orderName;
	
	public void setOrderName(String orderName) {
		//通过名字(key)指定要加载哪一种支付方式
		this.orderName = orderName;
	}
	
	@Override
	public String way() {
		//获取ExtensionLoader
		ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
		Order order;
		
		if(StringUtils.isEmpty(orderName)) {
			//如果未指定则获取默认支付方式
			order = loader.getDefaultExtension();
		}else {
			//安装指定名称获取支付方式
			order = loader.getExtension(orderName);
		}
		return order.way();
	}

}
public class AlipayOrder implements Order{

	public String way() {
		// TODO Auto-generated method stub
		System.out.println("---支付宝way()---");
		return "支付宝支付方式";
	}
}
public class WeChatOrder implements Order{

	public String way() {
		System.out.println("---微信way()---");
		return "微信支付方式";
	}
}

(4)定义测试启动类

public class OrderTest {

	public static void main(String[] args) {
		
		ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
		// 获取自适应AdaptiveExtension
		Order adaptiveExtension = loader.getAdaptiveExtension();
		//未指定
		System.out.println(adaptiveExtension.way());
		
		//指定支付方式
		((AdaptiveOrder)adaptiveExtension).setOrderName("wechat");
		System.out.println(adaptiveExtension.way());
	}
}

1.2 @Adaptive修饰方法

        被@Adaptive修饰的SPI接口中的方法称为Adaptive方法,在SPI扩展类中若没有找到Adaptive类,但系统却发现了Adaptive方法,就会根据Adaptive方法自动为该SPI接口动态生成一个Adaptive扩展类,并自动将其编译,修饰方法非常多,例如Protocol接口中就包含两个Adaptive方法;

1.2.1 dubbo源码

filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol

(1)动态生成Adaptive类格式

package<SPI 接口所在包>
	
	public class SPI接口名$Adpative implements SPI接口{
        //arg参数要么是URL类型,要么是能获取到URL
		public adaptiveMethod(arg0,arg1,...) {
			//注意,下面的判断仅对URL类型,或可以获取到URL类型值的参数进行判断
			//例如,dubbo的Invoker类型中就包含有URL属性
			if(arg1==null) throw new IllegalArgumentException(异常信息)
			if(arg1.getUrl()==null) throw new IllegalArgumentException(异常信息)
		
			URL url = arg1.getUrl();
			/*其会根据@Adaptive注解上声明的Key的顺序,从URL获取Value,
			 * 作为实际扩展类,若有默认扩展类,则获取默认扩展类名,否则获取指定扩展名;
			 */
			String exName = url.get接口名()==null?默认扩展前缀名:url.get接口名();
			
			if(extName==null)throw new IllegalArgumentException(异常信息);
			SPI接口  extension = ExtensionLoader.getExtensionLoader(SPI接口.class).getExtension(exName);
			
			return extension.adaptiveMethod(arg0,arg1,...);
		}
		//非Adaptive方法
		public unAdaptiveMethod(arg0,arg1,...) {
			throw new UnsupportedOperationException(异常信息);
		}
	}

(2)方法规范

        从前面的动态生成的Adaptive类中的adpativeMethod()方法体可知,其对于要加载的扩展名的指定方式是通过URL类型的方法参数指定的,所以对于Adaptive方法的定义规范仅一条:其参数包含URL类型参数,或参数可以获取到URL类型的值;方法调用者是通过URL传递要加载的扩展名;

1.2.2 示例

(1)创建工程adaptivemethod导入dubbo依赖

<!-- dubbo依赖 --> 
	<dependency>
	    <groupId>org.apache.dubbo</groupId>
	    <artifactId>dubbo</artifactId>
	    <version>2.7.0</version>
	</dependency>

(2)创建提供者路径及配置文件

alipay=com.zxy.spi.extension.AlipayOrder
wechat=com.zxy.spi.extension.WeChatOrder

(3)创建接口及实现类

/**
 * SPI标签,设置默认为alipay阿里支付
 */
@SPI("alipay")
public interface Order {
	//支付方式
	String way();
	
	//支付
	@Adaptive
	String pay(URL url);
}
public class AlipayOrder implements Order{

	public String way() {
		System.out.println("---支付宝way()---");
		return "支付宝支付方式";
	}

	@Override
	public String pay(URL url) {
		System.out.println("---支付宝pay()---");
		return "使用支付宝支付";
	}

}
public class WeChatOrder implements Order{

	public String way() {
		System.out.println("---微信way()---");
		return "微信支付方式";
	}

	@Override
	public String pay(URL url) {
		System.out.println("---微信pay()---");
		return "使用微信支付";
	}

}

(4)定义测试启动类

public class OrderTest {

	public static void main(String[] args) {
		
		ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
		// 获取自适应AdaptiveExtension
        // 此处设置Debug断点,将自动生成的Order$Adaptive类手动取出
		Order adaptiveExtension = loader.getAdaptiveExtension();
		//模拟一个URL,不指定支付方式使用默认
		URL url = URL.valueOf("xxx://localhost/ooo");
		System.out.println(adaptiveExtension.pay(url));
		
		/*
		 * 指定支付方式,参数必须为业务接口名(order 手动小写)
		 * 注意:此处有一个细节,如果接口名是两个单词构成,如OrderService,
		 * 那么此处参数为order.service
		 */
		URL url1 = URL.valueOf("xxx://localhost/ooo?order=wechat");
		System.out.println(adaptiveExtension.pay(url1));
	}

}

(5)将自动生成的Order$Adaptive类手动取出

从code的value中获取生成的Order$Adaptive代码;

在指定包创建Order$Adaptive,复制此代码:

package com.zxy.spi;

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

/**
 * 将自动生成的Order$Adaptive类手动取出
 *
 */
public class Order$Adaptive implements com.zxy.spi.Order {
	
	//此方法是Adaptive方法可以调用,可以做自适应
	public java.lang.String pay(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("order", "alipay");
		if(extName == null) throw new IllegalStateException("Fail to get extension(com.zxy.spi.Order) name from url(" + url.toString() + ") use keys([order])");
		com.zxy.spi.Order extension = (com.zxy.spi.Order)ExtensionLoader.getExtensionLoader(com.zxy.spi.Order.class).getExtension(extName);
		
		//程序最终走到此处
		return extension.pay(arg0);
		
	}
	
	//此方法不是Adaptive方法不可以做自适应,调用抛出异常
	public java.lang.String way() {
		
		throw new UnsupportedOperationException("method public abstract java.lang.String com.zxy.spi.Order.way() of interface com.zxy.spi.Order is not adaptive method!");
	
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值