怀着激动,兴奋,忐忑的心情写下第一篇博客,希望以后能在CSDN和大家一起开心的玩耍!!!
我确实不太会擅长写博客,但还是想把一些技术分享给大家,一起进步。
也希望大家多多交流,指正。
下面我们话不多说,直接进入正题。深入SPI机制
一、SPI机制理解
SPI 全称为 Service Provider Interface 是一种服务发现机制。
它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
实现步骤:
1、在ClassPath路径下的META-INF/services文件夹下创建文件
2、文件名为接口服务的全限定名,文件内容是多个实现类
3、API加载实现类。
下面让我小试牛刀一把…
二、Java SPI 案例
1、首先编写一个接口服务 SPIService ,就一个execute方法
public interface SPIService {
void execute();
}
2、创建两个接口实现类 SPIServiceImpl1 和 SPIServiceImpl2,实现execute方法
public class SPIServiceImpl1 implements SPIService {
@Override
public void execute() {
System.out.println( this.getClass().getSimpleName() + "....execute..........");
}
}
public class SPIServiceImpl2 implements SPIService{
@Override
public void execute() {
System.out.println( this.getClass().getSimpleName() + "....execute..........");
}
}
3、在META-INF/services 下创建文件,文件名为com.xyy.spi.java.SPIService 即接口全限定名,文件内容为两个实现类的全限定名。
com.xyy.spi.java.SPIServiceImpl1
com.xyy.spi.java.SPIServiceImpl2
如图:
4、准备就绪,我们来编写一个测试类,看看效果
public class SPIMainClass {
@Test
public void test() {
//方式一:sun.misc.Service 加载
Iterator<SPIService> providers = Service.providers(SPIService.class);
while (providers.hasNext()) {
SPIService servcie = providers.next();
servcie.execute();
}
System.out.println("**************************************************");
//方式二:java.util.ServiceLoader 加载
ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
Iterator<SPIService> iterator = load.iterator();
while (iterator.hasNext()) {
SPIService servcie = iterator.next();
servcie.execute();
}
}
}
运行结果:
这里我们输出了实现类1和2 的execute方法。我们采用了两种加载的方式,sun.misc.Service 加载和
java.util.ServiceLoader 加载,大同小异。下面我们去看看源码他们是如何实现的。
三、Java SPI 源码分析
1、sun.misc.Service 加载源码
以这个代码为入口debug调试下,看下源码
Iterator<SPIService> providers = Service.providers(SPIService.class);
跟踪代码
public static <S> Iterator<S> providers(Class<S> var0) throws ServiceConfigurationError {
//获得当前线程的ClassLoader
ClassLoader var1 = Thread.currentThread().getContextClassLoader();
return providers(var0, var1);
}
实例化Service.LazyIterator
public static <S> Iterator<S> providers(Class<S> var0, ClassLoader var1) throws ServiceConfigurationError {
//实例化Service.LazyIterator
// var0 是com.xyy.spi.java.SPIService
// var1 是线程的ClassLoader
return new Service.LazyIterator(var0, var1);
}
属性赋值
private LazyIterator(Class<S> var1, ClassLoader var2) {
this.configs = null;
this.pending = null;
this.returned = new TreeSet();
this.nextName = null;
//service 是com.xyy.spi.java.SPIService
this.service = var1;
this.loader = var2;
}
这里LazyIterator是Service的内部类,实现Iterator接口,看名字就是个懒加载的迭代器…
private static class LazyIterator<S> implements Iterator<S> {
//保存我们的接口
Class<S> service;
//当前线程的ClassLoader
ClassLoader loader;
//我们的配置资源
Enumeration<URL> configs;
//配置内容信息,也就是实现类1和2
Iterator<String> pending;
Set<String> returned;
String nextName;
...
}
下面到了看看我们迭代的时候啦
while (providers.hasNext()) {
SPIService servcie = providers.next();
servcie.execute();
}
跟踪这个 providers.hasNext()
public boolean hasNext() throws ServiceConfigurationError {
//判断nextName 是否为空,不为空就返回true。后面直接next获取
if(this.nextName != null) {
return true;
} else {
if(this.configs == null) {
try {
//var1 是 META-INF/services/com.xyy.spi.java.SPIService
String var1 = "META-INF/services/" + this.service.getName();
if(this.loader == null) {
this.configs = ClassLoader.getSystemResources(var1);
} else {
this.configs = this.loader.getResources(var1);
}
} catch (IOException var2) {
Service.fail(this.service, ": " + var2);
}
}
while(this.pending == null || !this.pending.hasNext()) {
if(!this.configs.hasMoreElements()) {
return false;
}
//解析配置
this.pending = Service.parse(this.service, (URL)this.configs.nextElement(), this.returned);
}
//设置nextName
this.nextName = (String)this.pending.next();
return true;
}
}
下面我们看看parse解析方法
private static Iterator<String> parse(Class<?> var0, URL var1, Set<String> var2) throws ServiceConfigurationError {
InputStream var3 = null;
BufferedReader var4 = null;
ArrayList var5 = new ArrayList();
try {
var3 = var1.openStream();
var4 = new BufferedReader(new InputStreamReader(var3, "utf-8"));
int var6 = 1;
while(true) {
//解析行
if((var6 = parseLine(var0, var1, var4, var6, var5, var2)) >= 0) {
continue;
}
}
} catch (IOException var15) {
fail(var0, ": " + var15);
} finally {
try {
if(var4 != null) {
var4.close();
}
if(var3 != null) {
var3.close();
}
} catch (IOException var14) {
fail(var0, ": " + var14);
}
}
return var5.iterator();
}
hasNext主要是解析了我们的配置文件,赋值给迭代器。我们现在到了next方法
SPIService servcie = providers.next();
next方法
public S next() throws ServiceConfigurationError {
//先去判断hasNext
if(!this.hasNext()) {
throw new NoSuchElementException();
} else {
//有的话,直接获取nextName
String var1 = this.nextName;
this.nextName = null;
Class var2 = null;
try {
//类加载var1 使我们的实现类1或2的权限定名
var2 = Class.forName(var1, false, this.loader);
} catch (ClassNotFoundException var5) {
Service.fail(this.service, "Provider " + var1 + " not found");
}
if(!this.service.isAssignableFrom(var2)) {
Service.fail(this.service, "Provider " + var1 + " not a subtype");
}
try {
//反射创建实例,转化成接口
return this.service.cast(var2.newInstance());
} catch (Throwable var4) {
Service.fail(this.service, "Provider " + var1 + " could not be instantiated", var4);
return null;
}
}
}
现在我们就获得了配置的扩展类对象实例啦。
看了源码,大致画了个分析流程图,总体源码还是不难,大家只要debug跟踪下就理解啦。
总结:
1、创建Service.LazyIterator,设置service等属性
2、hasNext加载META-INF/services下接口文件内容,设置LazyIterator的nextName属性等
3、next方法获得nextName,Class.forName加载类,反射实例化
2、java.util.ServiceLoader 加载源码
看完了上面的加载方式的源码,我们再看看java.util.ServiceLoader 加载源码,就更简单啦
ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
debug下
public static <S> ServiceLoader<S> load(Class<S> service) {
//同样的当前线程的ClassLoader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
//调用load
return ServiceLoader.load(service, cl);
}
load方法
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
实例化ServiceLoader
private ServiceLoader(Class<S> svc, ClassLoader cl) {
//我们的接口服务 com.xyy.spi.java.SPIService
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
//重新加载
reload();
}
reload方法
public void reload() {
//清除缓存
providers.clear();
//创建LazyIterator
lookupIterator = new LazyIterator(service, loader);
}
我们看看ServiceLoader 类,实现Iterable
public final class ServiceLoader<S>
implements Iterable<S>
{
//加载配置目录
private static final String PREFIX = "META-INF/services/";
// 我们的接口
private final Class<S> service;
private final ClassLoader loader;
// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc;
// 类名和实例的映射,缓存
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// The current lazy-lookup iterator
private LazyIterator lookupIterator;
...
}
上面完成初始化,下面看下
Iterator<SPIService> iterator = load.iterator();
iterator方法
public Iterator<S> iterator() {
//新建一个Iterator 返回
return new Iterator<S>() {
//将缓存结果,设置给knownProviders
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
//这个判断是否hasNext
public boolean hasNext() {
//缓存有
if (knownProviders.hasNext())
return true;
//缓存没有,调用 LazyIterator 的hasNext
return lookupIterator.hasNext();
}
// 获取
public S next() {
//缓存有,从缓存中获取对象实例
if (knownProviders.hasNext())
return knownProviders.next().getValue();
// 缓存没有,调用 LazyIterator 的next
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
后面测试代码的迭代获取,会调用上面的Iterator的相关方法
while (iterator.hasNext()) {
SPIService servcie = iterator.next();
servcie.execute();
}
LazyIterator 的hasNext方法
public boolean hasNext() {
if (acc == null) {
//调用hasNextService
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
hasNextService方法,这个代码可真是太熟悉啦,上面第一个加载方式的源码分析过了类似。
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
LazyIterator 的next方法
public S next() {
if (acc == null) {
//调用nextService
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
//反射实例化
S p = service.cast(c.newInstance());
//放入缓存
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
到此源码就分析完了,其实和第一种真的没啥大区别,只是多了一个缓存。
源码大致的流程图
总结:
1、初始化 ServiceLoader,设置lookupIterator属性为LazyIterator
2、hasNext先从缓存的providers中获取,为空,则去加载META-INF/services下接口文件内容,设置LazyIterator的nextName属性等
3、next方法获得nextName,Class.forName加载类,反射实例化,放入providers
四、Java SPI 应用
1、JDBC驱动
1、我们自己创建一个驱动类,MyDriver,方便起见,我们需要extends com.mysql.cj.jdbc.NonRegisteringDriver implements java.sql.Driver
public class MyDriver extends com.mysql.cj.jdbc.NonRegisteringDriver implements java.sql.Driver{
public MyDriver() throws SQLException {
}
static {
try {
System.out.println("register MyDriver...");
//注册我们的驱动
DriverManager.registerDriver(new MyDriver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register MyDriver!");
}
}
@Override
public Connection connect(String url, Properties info) throws SQLException {
System.out.println("创建连接..."+ url);
System.out.println("jdbc配置信息..." + info);
Connection connect = super.connect(url, info);
System.out.println("数据库连接创建完成..."+ connect.toString());
return connect;
}
}
2、在META-INF/services下创建java.sql.Driver文件,内容为:com.xyy.spi.jdbc.MyDriver
com.xyy.spi.jdbc.MyDriver
3、测试类
@Test
public void test() throws Exception {
String url = "jdbc:mysql://127.0.0.1:3306/db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&autoReconnect=true&allowMultiQueries=true&useSSL=false";
String user = "root";
String password = "root";
/**
* 不需要这个啦
*/
//Class.forName("com.xyy.spi.jdbc.MyDriver");
Connection connection = DriverManager.getConnection(url, user, password);
PreparedStatement preparedStatement = connection.prepareStatement("SELECT id FROM table");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
Long id = resultSet.getLong(1);
System.out.println("id=="+ id);
}
preparedStatement.close();
connection.close();
}
运行结果:
看着结果就已经回调了我们的类。那么是如何加载到MyDriver?细节就不展开了,看着图debug跟踪下代码,就清楚啦
总结:
1、DriverManager类加载时,静态代码块调用loadInitialDrivers(),SPI机制加载META-INF/services/java.sql.Driver内的实现类
2、加载MyDriver的静态方法,注册MyDriver
3、DriverManager的getConnection方法,会遍历注册驱动,调用驱动类的connnect方法
源码分析流程图:
2、Dubbo应用
dubbo的SPI机制:
1、接口有@SPI注解,指定默认实现
2、加载三个路径: META-INF/services/、META-INF/dubbo/、META-INF/services/internal
示例1 、扩展dubbo的Protocol接口服务
1、创建类MyProtocol,实现Protocol
public class MyProtocol implements Protocol {
/**
* 我们重写了默认端口
* @return
*/
@Override
public int getDefaultPort() {
return 8888;
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return null;
}
@Override
public <T> Invoker<T> refer(Class<T> aClass, URL url) throws RpcException {
return null;
}
@Override
public void destroy() {
}
}
2、在META-INF/dubbo/下创建文件com.alibaba.dubbo.rpc.Protocol,内容
MyProtocol=com.xyy.spi.dubbo.MyProtocol
3、测试代码
@Test
public void testMyProtocol(){
ExtensionLoader<Protocol> extensionLoader = ExtensionLoader.getExtensionLoader(Protocol.class);
Protocol myProtocol = extensionLoader.getExtension("MyProtocol");
System.out.println(myProtocol.getDefaultPort());
}
运行结果:
示例2、我们自己定义接口服务
1、创建接口DubboService,写上 @SPI(“dubboService1”)注解,默认是dubboService1
@SPI("dubboService1")
public interface DubboService {
public void sayHello();
}
2、创建DubboService接口的两个实现类
public class DubboServiceImp1 implements DubboService {
@Override
public void sayHello() {
System.out.println("DubboServiceImp1...hello");
}
}
public class DubboServiceImp2 implements DubboService {
@Override
public void sayHello() {
System.out.println("DubboServiceImp2...hello");
}
}
3、在META-INF/dubbo/下创建文件com.xyy.spi.dubbo.DubboService,内容
dubboService1=com.xyy.spi.dubbo.DubboServiceImp1
dubboService2=com.xyy.spi.dubbo.DubboServiceImp2
4、测试代码
@Test
public void testDubboService(){
ExtensionLoader<DubboService> extensionLoader1 = ExtensionLoader.getExtensionLoader(DubboService.class);
DubboService dubboService = extensionLoader1.getExtension("dubboService1");
dubboService.sayHello();
}
运行结果:
源码分析
入口:
ExtensionLoader.getExtensionLoader(DubboService.class);
看下 ExtensionLoader.getExtensionLoader方法:
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
//必须是接口
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
//必须有@SPI注解
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
//从缓存中获取接口对应的ExtensionLoader,EXTENSION_LOADERS 是ConcurrentMap<Class<?>, ExtensionLoader<?>>
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
//创建ExtensionLoader,放入缓存
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
这个ExtensionLoader.withExtensionAnnotation方法,查看是否有SPI注解:
private static <T> boolean withExtensionAnnotation(Class<T> type) {
return type.isAnnotationPresent(SPI.class);
}
创建 new ExtensionLoader(type)方法:
private ExtensionLoader(Class<?> type) {
//接口服务的class
this.type = type;
//如果类型是ExtensionFactory.class 则设为null,否则就是再次使用SPI机制获得ExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
下面我们看下获得具体扩展的方法 这个getExtension(String name):
public T getExtension(String name) {
//为空,则报异常
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
//如是字符串"true",则获取默认的扩展实例。
if ("true".equals(name)) {
return getDefaultExtension();
}
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//创建指定的扩展实例
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
创建指定的扩展,createExtension方法:
private T createExtension(String name) {
//从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
//获得指定扩展的class对象
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//实例化,放入缓存
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//依赖注入和cachedWrapperClasses
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
获得所有的扩展getExtensionClasses()方法:
private Map<String, Class<?>> getExtensionClasses() {
//缓存中获取映射关系表
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//加载映射关系表
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
loadExtensionClasses()方法:
private Map<String, Class<?>> loadExtensionClasses() {
//获得注解指定的默认值
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
// 获取@SPI注解中的值,并缓存起来
if (names.length == 1) cachedDefaultName = names[0];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
//加载指定文件夹下的配置文件,META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
加载目录loadDirectory方法:
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
// fileName 是 META-INF/dubbo/com.xyy.spi.dubbo.DubboService
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
ClassLoader classLoader = findClassLoader();
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
//加载文件,一个resourceURL就是一个文件
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", description file: " + fileName + ").", t);
}
}
loadResource方法加载资源:
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
try {
String line;
while ((line = reader.readLine()) != null) {
//去掉# 后面的注释
final int ci = line.indexOf('#');
if (ci >= 0) line = line.substring(0, ci);
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
//包含等号,按等号切割
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
//加载类
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
}
} finally {
reader.close();
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
loadClass方法加载class:
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
// clazz 必须是type类型的
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error when load extension class(interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + "is not subtype of interface.");
}
//判断clazz是否为标注了@Adaptive注解
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
}
//判断是否是Wrapper类型
else if (isWrapperClass(clazz)) {
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} else {
//clazz是一个普通的拓展类
//获得默认构造
clazz.getConstructor();
if (name == null || name.length() == 0) {
//name 配置为空,去类上找@Extension注解
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
//判断clazz是否为标注了@Activate注解
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
// 存储名称到class的映射关系,这样就解析好了一行
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
}
}
}
}
}
查看处理@Extension注解,findAnnotationName方法:
private String findAnnotationName(Class<?> clazz) {
com.alibaba.dubbo.common.Extension extension = clazz.getAnnotation(com.alibaba.dubbo.common.Extension.class);
//没注解,再去判断
if (extension == null) {
String name = clazz.getSimpleName();
//扩展类名是否以接口的名称结尾,包含的话,就截取扩展类前面的部分,不包含的话就直接扩展类名
if (name.endsWith(type.getSimpleName())) {
name = name.substring(0, name.length() - type.getSimpleName().length());
}
//转成小写
return name.toLowerCase();
}
//有注解,返回注解value
return extension.value();
}
源码分析流程图:
示例3、dubbo的Adaptive及Wrapper详解
1、创建接口
@SPI("dubbo")
public interface AdaptiveExtService {
//@Adaptive
//@Adaptive({"param"})
String run(String msg, URL url);
}
2、创建多个实现类
public class DubboAdaptiveExt implements AdaptiveExtService {
@Override
public String run(String msg, URL url) {
return "dubbo";
}
}
public class SpringCloudAdaptiveExt implements AdaptiveExtService {
@Override
public String run(String msg, URL url) {
return "spring cloud";
}
}
//@Adaptive
public class ThriftAdaptiveExt implements AdaptiveExtService {
@Override
public String run(String msg, URL url) {
return "thrift";
}
}
3、在META-INF/dubbo下创建文件,文件名称:com.xyy.spi.dubbo.adaptive.DubboAdaptiveExt,内容为
dubbo=com.xyy.spi.dubbo.adaptive.DubboAdaptiveExt
cloud=com.xyy.spi.dubbo.adaptive.SpringCloudAdaptiveExt
thrift=com.xyy.spi.dubbo.adaptive.ThriftAdaptiveExt
4、编写测试类观察
(1)、测试1
/**
* SPI上有注解,@SPI("dubbo")
* url无参数
* 没有扩展类上添加@Adaptive注解
* 接口方法不加@Adaptive注解
*
*/
@Test
public void test1(){
ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
URL url = URL.valueOf("http://localhost/xxx");
System.out.println(adaptiveExtension.run("hello", url));
}
运行结果:
结论:使用getAdaptiveExtension()方法,没有@Adaptive注解的扩展类,则接口必须有@Adaptive注解的方法。
(2)、测试2
/**
* SPI上有注解,@SPI("dubbo")
* url无参数
* 没有扩展类上添加@Adaptive注解
* 方法上有@Adaptive注解,无参数
*/
@Test
public void test2(){
ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
URL url = URL.valueOf("http://localhost/xxx");
System.out.println(adaptiveExtension.run("hello", url));
}
运行结果:
结论:使用getAdaptiveExtension()方法,没有@Adaptive注解的扩展类,会得到@SPI(“dubbo”)指定的默认的扩展类。
(3)、测试3
/**
* SPI上有注解@SPI("dubbo")
* URL中也有具体的值
* 没有扩展类上添加@Adaptive注解
* 注意这里对方法标注有@Adaptive注解,
* 但是该注解没有值
*/
@Test
public void test3(){
ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
URL url = URL.valueOf("http://localhost/xxx?adaptive.ext.service=cloud");
System.out.println(adaptiveExtension.run("hello", url));
}
运行结果:
结论:使用getAdaptiveExtension()方法,没有@Adaptive注解的扩展类,有url参数,该参数通过AdaptiveExtService转小写生成(adaptive.ext.service=cloud),则会获得cloud对应的实例。
(4)、测试4
/**
* SPI上有注解,@SPI("dubbo")
* URL中也有具体的值
* ThriftAdaptiveExt实现类上面添加@Adaptive注解
*/
@Test
public void test4(){
ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
URL url = URL.valueOf("http://localhost/xxx?adaptive.ext.service=cloud");
System.out.println(adaptiveExtension.run("d", url));
}
运行结果:
结论:使用getAdaptiveExtension()方法,实现类上面添加@Adaptive注解的优先级高与url参数指定的
(5)、测试5
/**
* SPI上有注解,@SPI("dubbo")
* URL中也有具体的值,接口方法中加上注解@Adaptive({"param"}),
* 各个实现类上面没有@Adaptive注解
*/
@Test
public void test5(){
ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
URL url = URL.valueOf("http://localhost/xxx?param=cloud");
System.out.println(adaptiveExtension.run("d", url));
}
运行结果:
结论:使用getAdaptiveExtension()方法,方法上有注解@Adpative({“param”}),则URL中应当配上该参数param=cloud,创建cloud对应的实例
通过上面测试发现:
可以得出优先级: @Adaptive标注的类 > URL参数 > @SPI注解中的值
源码分析:
getAdaptiveExtension()方法为入口:
public T getAdaptiveExtension() {
//先从缓存中获取
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//创建自适应的扩展类
instance = createAdaptiveExtension();
//放入缓存
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
创建自适应的扩展类实例 createAdaptiveExtension()方法:
private T createAdaptiveExtension() {
try {
//getAdaptiveExtensionClass()获得自适应的扩展class
//反射获得扩展类的实例
//依赖注入
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
获得自适应的扩展类class方法 getAdaptiveExtensionClass:
private Class<?> getAdaptiveExtensionClass() {
//获得所有扩展类,加载配置文件,之前看过,这里就不展开了
getExtensionClasses();
//如果有标注了@Adaptive注解实现类,那么cachedAdaptiveClass不为空,直接返回,表明@Adaptive注解标明的扩展类优先级最高
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//创建自适应的扩展类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
创建自适应的扩展类class方法 createAdaptiveExtensionClass:
private Class<?> createAdaptiveExtensionClass() {
//创建扩展类class字符串
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
//获得自适应的扩展编译器
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
//编译我们生成的code字符串
return compiler.compile(code, classLoader);
}
生成扩展class内容字符串,createAdaptiveExtensionClassCode 方法:
private String createAdaptiveExtensionClassCode() {
StringBuilder codeBuilder = new StringBuilder();
//获取接口的方法
Method[] methods = type.getMethods();
boolean hasAdaptiveAnnotation = false;
for (Method m : methods) {
//方法是否有@Adaptive注解
if (m.isAnnotationPresent(Adaptive.class)) {
hasAdaptiveAnnotation = true;
break;
}
}
//方法没有注解,抛异常,至少有一个方法有注解
// no need to generate adaptive class since there's no adaptive method found.
if (!hasAdaptiveAnnotation)
throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
//生成包信息 package com.xyy.spi.dubbo.adaptive;r
codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
//生成import信息 import com.alibaba.dubbo.common.extension.ExtensionLoader;
codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");
生成类名 public class AdaptiveExtService$Adaptive implements com.xyy.spi.dubbo.adaptive.AdaptiveExtService {
codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");
//遍历所有方法
for (Method method : methods) {
//返回值类型
Class<?> rt = method.getReturnType();
//参数类型
Class<?>[] pts = method.getParameterTypes();
//异常类型
Class<?>[] ets = method.getExceptionTypes();
Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
StringBuilder code = new StringBuilder(512);
//没有 @Adaptive注解的方法 抛异常UnsupportedOperationException
if (adaptiveAnnotation == null) {
code.append("throw new UnsupportedOperationException(\"method ")
.append(method.toString()).append(" of interface ")
.append(type.getName()).append(" is not adaptive method!\");");
} else {
//找到URL类型参数
int urlTypeIndex = -1;
for (int i = 0; i < pts.length; ++i) {
if (pts[i].equals(URL.class)) {
urlTypeIndex = i;
break;
}
}
//存在url参数
// found parameter in URL type
if (urlTypeIndex != -1) {
//如果参数是空 if (arg1 == null) throw new IllegalArgumentException("url == null");
// Null Point check
String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
urlTypeIndex);
code.append(s);
//获取url com.alibaba.dubbo.common.URL url = arg1;
s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex);
code.append(s);
}
//没有URL参数
// did not find parameter in URL type
else {
String attribMethod = null;
// find URL getter method
LBL_PTS:
for (int i = 0; i < pts.length; ++i) {
Method[] ms = pts[i].getMethods();
for (Method m : ms) {
String name = m.getName();
if ((name.startsWith("get") || name.length() > 3)
&& Modifier.isPublic(m.getModifiers())
&& !Modifier.isStatic(m.getModifiers())
&& m.getParameterTypes().length == 0
&& m.getReturnType() == URL.class) {
urlTypeIndex = i;
attribMethod = name;
break LBL_PTS;
}
}
}
if (attribMethod == null) {
throw new IllegalStateException("fail to create adaptive class for interface " + type.getName()
+ ": not found url parameter or url attribute in parameters of method " + method.getName());
}
// Null point check
String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
urlTypeIndex, pts[urlTypeIndex].getName());
code.append(s);
s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
code.append(s);
s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod);
code.append(s);
}
//获取注解值, 我们配置的@Adaptive({"param"})
String[] value = adaptiveAnnotation.value();
//没有值的情况,我们获得接口名称,遇到大写字母,则追加.,大写转小写,如 adaptive.ext.service
// value is not set, use the value generated from class name as the key
if (value.length == 0) {
char[] charArray = type.getSimpleName().toCharArray();
StringBuilder sb = new StringBuilder(128);
for (int i = 0; i < charArray.length; i++) {
if (Character.isUpperCase(charArray[i])) {
if (i != 0) {
sb.append(".");
}
sb.append(Character.toLowerCase(charArray[i]));
} else {
sb.append(charArray[i]);
}
}
value = new String[]{sb.toString()};
}
//hasInvocation 暂不分析,TODO
boolean hasInvocation = false;
for (int i = 0; i < pts.length; ++i) {
if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) {
// Null Point check
String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\");", i);
code.append(s);
s = String.format("\nString methodName = arg%d.getMethodName();", i);
code.append(s);
hasInvocation = true;
break;
}
}
//defaultExtName是dubbo @SPI("dubbo")指定的
String defaultExtName = cachedDefaultName;
String getNameCode = null;
for (int i = value.length - 1; i >= 0; --i) {
//注解配置的最后一个值
if (i == value.length - 1) {
if (null != defaultExtName) {
if (!"protocol".equals(value[i]))
if (hasInvocation)
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);
} else {
if (!"protocol".equals(value[i]))
if (hasInvocation)
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
else
getNameCode = "url.getProtocol()";
}
} else {
if (!"protocol".equals(value[i]))
if (hasInvocation)
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
else
getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
}
}
// 获取扩展名 String extName = url.getParameter("param", "dubbo");
code.append("\nString extName = ").append(getNameCode).append(";");
//检查扩展名是否为空
// check extName == null?
String s = String.format("\nif(extName == null) " +
"throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");",
type.getName(), Arrays.toString(value));
code.append(s);
//生成 com.xyy.spi.dubbo.adaptive.AdaptiveExtService extension = (com.xyy.spi.dubbo.adaptive.AdaptiveExtService)ExtensionLoader.getExtensionLoader(com.xyy.spi.dubbo.adaptive.AdaptiveExtService.class).getExtension(extName);
s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
code.append(s);
//生成返回 return extension.run(arg0, arg1);
// return statement
if (!rt.equals(void.class)) {
code.append("\nreturn ");
}
s = String.format("extension.%s(", method.getName());
code.append(s);
for (int i = 0; i < pts.length; i++) {
if (i != 0)
code.append(", ");
code.append("arg").append(i);
}
code.append(");");
}
// 生成方法名,参数,返回值,异常 public java.lang.String run(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {
codeBuilder.append("\npublic ").append(rt.getCanonicalName()).append(" ").append(method.getName()).append("(");
for (int i = 0; i < pts.length; i++) {
if (i > 0) {
codeBuilder.append(", ");
}
codeBuilder.append(pts[i].getCanonicalName());
codeBuilder.append(" ");
codeBuilder.append("arg").append(i);
}
codeBuilder.append(")");
if (ets.length > 0) {
codeBuilder.append(" throws ");
for (int i = 0; i < ets.length; i++) {
if (i > 0) {
codeBuilder.append(", ");
}
codeBuilder.append(ets[i].getCanonicalName());
}
}
codeBuilder.append(" {");
codeBuilder.append(code.toString());
codeBuilder.append("\n}");
}
codeBuilder.append("\n}");
if (logger.isDebugEnabled()) {
logger.debug(codeBuilder.toString());
}
return codeBuilder.toString();
}
最终生成返回结果:
package com.xyy.spi.dubbo;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class AdaptiveExtService$Adaptive implements com.xyy.spi.dubbo.adaptive.AdaptiveExtService {
public java.lang.String run(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = url.getParameter("param", "dubbo");
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.xyy.spi.dubbo.adaptive.AdaptiveExtService) name from url(" + url.toString() + ") use keys([param])");
com.xyy.spi.dubbo.adaptive.AdaptiveExtService extension = (com.xyy.spi.dubbo.adaptive.AdaptiveExtService) ExtensionLoader.getExtensionLoader(com.xyy.spi.dubbo.adaptive.AdaptiveExtService.class).getExtension(extName);
return extension.run(arg0, arg1);
}
}
源码流程图:
依赖注入:
//依赖注入
private T injectExtension(T instance) {
try {
// objectFactory 实在实例化ExtensionLoader时以spi形式初始化的
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())) {
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
//@DisableInject标记的方法注解不注入
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
try {
//获取属性名
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
//获取容器中属性
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//反射赋值
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
初始化objectFactory,spi加载ExtensionFactory
//会初始化objectFactory,spi加载ExtensionFactory
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
SPI加载com.alibaba.dubbo.common.extension.ExtensionFactory文件内容:
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
AdaptiveExtensionFactory 存在@Adaptive 注解,默认会优先选中
//@Adaptive 存在,默认会优先选中
@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()) {
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;
}
}
遍历factory中所有的ExtensionFactory,先从SpiExtensionFactory中获取,获取不到在去Spring容器中获取
@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;
}
SpiExtensionFactory的getExtension方法
//SpiExtensionFactory中获取
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;
}
}
SpringExtensionFactory的getExtension方法
//Spring容器中获取
public class SpringExtensionFactory implements ExtensionFactory {
private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
public static void addApplicationContext(ApplicationContext context) {
contexts.add(context);
}
public static void removeApplicationContext(ApplicationContext context) {
contexts.remove(context);
}
// currently for test purpose
public static void clearContexts() {
contexts.clear();
}
@Override
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
//根据name找
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
if (Object.class == type) {
return null;
}
//根据类型查找
for (ApplicationContext context : contexts) {
try {
return context.getBean(type);
} catch (NoUniqueBeanDefinitionException multiBeanExe) {
logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
} catch (NoSuchBeanDefinitionException noBeanExe) {
if (logger.isDebugEnabled()) {
logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
}
}
}
logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");
return null;
}
}
Wrapper实现AOP
创建Wrapper
public class AdaptiveExtWrapper implements AdaptiveExtService {
private AdaptiveExtService adaptiveExtService;
//实现一个Wrapper类的关键就是提供一个带类似参数的构造函数
public AdaptiveExtWrapper(AdaptiveExtService adaptiveExtService){
this.adaptiveExtService = adaptiveExtService;
}
@Override
public String run(String msg, URL url) {
System.out.println("before");
adaptiveExtService.run(msg, url);
System.out.println("after");
return "wrapper";
}
}
DubboAdaptiveExt改造
public class DubboAdaptiveExt implements AdaptiveExtService {
private AdaptiveExtService adaptiveExtService;
public void setAdaptiveExtService(AdaptiveExtService adaptiveExtService) {
this.adaptiveExtService = adaptiveExtService;
}
@Override
public String run(String msg, URL url) {
System.out.println(adaptiveExtService.run(msg, url));
return "dubbo";
}
}
修改文件,追加com.xyy.spi.dubbo.adaptive.AdaptiveExtWrapper:
dubbo=com.xyy.spi.dubbo.adaptive.DubboAdaptiveExt
cloud=com.xyy.spi.dubbo.adaptive.SpringCloudAdaptiveExt
thrift=com.xyy.spi.dubbo.adaptive.ThriftAdaptiveExt
com.xyy.spi.dubbo.adaptive.AdaptiveExtWrapper
测试类:
@Test
public void test7(){
ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
AdaptiveExtService adaptiveExtension = loader.getExtension("dubbo");
URL url = URL.valueOf("http://localhost/xxx");
adaptiveExtension.run("d", url);
}
运行输出:
源码:
loadClass方法:
//是Wrapper类
else if (isWrapperClass(clazz)) {
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} else {
isWrapperClass(clazz)方法:
//存在构造,参数是type
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
createExtension 方法:
@SuppressWarnings("unchecked")
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
//Wrapper类
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
//实例化,返回Wrapper类
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
这样就调用了Wrapper类。
写到这里,本篇就结束了,让我们下一篇见!!!