Dubbo之SPI机制简介分享
SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。
我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块、xml解析模块、jdbc模块等方案。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。 Java SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。
Java的SPI机制: ServiceLoader
用法
// java.sql.Driver
// 1.new一个ServiceLoader
ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
Iterator<Driver> iterator = drivers.iterator();
// 2.调用延迟加载器的hashNext
while (iterator.hasNext()) {
// 3.调用延迟加载器的next
Driver next = iterator.next();
System.out.println(next.getClass());
}
// result:
class com.mysql.jdbc.Driver
class com.mysql.fabric.jdbc.FabricMySQLDriver
class com.alibaba.druid.proxy.DruidDriver
class com.alibaba.druid.mock.MockDriver
原理
ServiceLoader并不会在load的时候去加载所有 接口对应实现类的文件。而是在执行接口的时候去遍历加载。
ServiceLoader的核心属性
// 接口全限定名的文件的路径前缀
private static final String PREFIX = "META-INF/services/";
// 被加载的接口
private final Class<S> service;
// 类的加载器
private final ClassLoader loader;
// 创建serviceLoader时 访问控制上下文
private final AccessControlContext acc;
// 服务缓存池(k-> 类全报名 v-> 实现类信息)
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// 延迟加载的迭代器
private LazyIterator lookupIterator;
LazyIterator的核心属性
// 接口类型
Class<S> service;
// 接的加载器
ClassLoader loader;
// META-INF/services/内配置文件的URL集合
Enumeration<URL> configs = null;
// 需加载的实现类的全包名集合
Iterator<String> pending = null;
// 下一个实现类的全报名,用于迭代器延迟加载的下一个类
String nextName = null;
源码解析
1、load方法
// 1、load方法
public static <S> ServiceLoader<S> load(Class<S> service) {
// 获取当前线程的类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// 继续调用重载的方法
return ServiceLoader.load(service, cl);
}
// 2、调用重载方法
public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) {
// new 一个ServiceLoader对象
return new ServiceLoader<>(service, loader);
}
// 3、new 一个serviceLoader对象
private ServiceLoader(Class<S> svc, ClassLoader cl) {
// PS:服务接口不能为空
service = Objects.requireNonNull(svc, "Service interface cannot be null");
// 指定加载器
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
// 指定下上容器(默认为null)
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
// 刷新:1.重置服务缓冲池 2.new一个延迟加载的迭代器
reload();
}
// 4、刷新
public void reload() {
// 重置服务缓存池
providers.clear();
// 构造一个延迟加载的迭代器
lookupIterator = new LazyIterator(service, loader);
}
// 5、new LazyIterator
private LazyIterator(Class<S> service, ClassLoader loader) {
// 指定接口的类信息
this.service = service;
// 指定类加载器
this.loader = loader;
}
2、获取延迟加载的迭代器
3、调用延迟加载迭代器的hasNext()方法
// 1、调用hasNext()方法
public boolean hasNext() {
// 默认 acc为null
if (acc == null) {
// 执行hasNextService()方法
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
// 2、调用hasNextService()方法
private boolean hasNextService() {
// 默认第一次执行 nextName为null
if (nextName != null) {
return true;
}
// 默认第一次执行 configs为null, 通过类加载器加载类的全报名,然后获取URL。
if (configs == null) {
try {
// "META-INF/services/" + java.sql.Driver
// 1.file:/Users/zhouzeng/.m2/repository/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar!/META-INF/services/java.sql.Driver
// 2.file:/Users/zhouzeng/.m2/repository/com/alibaba/druid/1.0.28/druid-1.0.28.jar!/META-INF/services/java.sql.Driver
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);
}
}
// 默认第一次执行 pending为null
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
// 根据 接口+ URL 解析
/**
* 1.0 = "com.mysql.jdbc.Driver" 1 = "com.mysql.fabric.jdbc.FabricMySQLDriver"
* 2.0 = "com.alibaba.druid.proxy.DruidDriver" 1 = "com.alibaba.druid.mock.MockDriver"
**/
pending = parse(service, configs.nextElement());
}
// com.mysql.jdbc.Driver
nextName = pending.next();
return true;
}
4、next()方法
// 1.执行next方法
public S next() {
// 默认 acc为null
if (acc == null) {
// 调用nexrService()方法
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
// 2.执行nextService()方法
private S nextService() {
// 判断是否还有下一个类需要加载
if (!hasNextService()) {
throw new NoSuchElementException();
}
// 1.com.mysql.jdbc.Driver
// 2.com.mysql.fabric.jdbc.FabricMySQLDriver
// 3.com.alibaba.druid.proxy.DruidDriver
// 4.com.alibaba.druid.mock.MockDriver
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();
}
优缺点
优点:将业务代码和具体实现类解耦,方便扩展。如需增加新逻辑,无需修改主流程,直接在PI配置文件增加实现类的全限定名即可。
缺点:颗粒度不够细,无法准确定位某一个实现类。要执行就执行所有的实现类。
SpringBoot 之SPI机制:SpringFactoriesLoader
应用
1.创建一个enableConfiguration
@Configuration
@EnableConfigurationProperties({MybatisProperties.class})
public class MybatisAutoConfiguration {
}
2.在resources下定义META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
3.用SpringBoot启动
@SpringBootApplication
public class CarCreateApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(CarCreateApplication.class, args);
}
}
在springbot启动时回去加载MybatisAutoConfiguration这个类。
原理
1、在SpringBoot启动时,在refreshContext()时,回去调用@Import的selector。
2、然后执行 AutoConfigurationImportSelector的process()方法 获取对应的configuration的List。
3、由Spring 去加载实例化configuration的配置类。
// 1.SpringBootApplication中的SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
// 2.SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
// 3.查看 AutoConfigurationImportSelector的selectImports()方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 获取enableautoconfiguration相关的类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
// 4. 执行getCandidateConfigurations()方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 获取configurations
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
// 5. 执行loadFactoryNames()方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
// org.springframework.boot.autoconfigure.EnableAutoConfiguration
String factoryClassName = factoryClass.getName();
// 加载spring.fatories的配置项,然后获取key为EnableAutoConfiguration的value
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
SpringFactoriesLoader的核心属性
// 1.spring 资源加载的默认路径
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 2.缓存池 K为类加载器 HK为接口全包名 HV为实现类
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
// 6.执行loadSpringFactories()方法,根据类加载器,获取META-INF/spring.factories下的配置
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 在缓存池中获取,有则直接返回。
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 获取"META-INF/spring.factories"的URL
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
List<String> factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
// 将解析出来的数据放到缓存池中。
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
Dubbo的SPI机制
用法
代码
// 1.定义接口
@SPI("wechat")
public interface Order {
/**
* 支付方法
*
* @return 结果
*/
String way();
}
// 2.接口实现AlipayOrder
public class AlipayOrder implements Order {
@Override
public String way() {
System.out.println("--- 支付宝way() ---");
return "支付宝支付方式";
}
}
// 3.接口实现WeChatOrder
public class WeChatOrder implements Order {
@Override
public String way() {
System.out.println("--- 微信way() ---");
return "微信支付方式";
}
}
配置
在META-INF/dubbo目录下添加配置文件(com.example.spidemo.dubbo.base.Order)
wechat,wechat2=com.example.spidemo.dubbo.base.impl.WeChatOrder
alipay=com.example.spidemo.dubbo.base.impl.AlipayOrder
测试类
public static void test1() {
ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
Order alipay = loader.getExtension("alipay");
System.out.println(alipay.way());
//同一个实现类,多个名称,是同一个实例
Order wechat = loader.getExtension("wechat");
System.out.println(wechat.way());
Order wechat2 = loader.getExtension("wechat2");
System.out.println(wechat2 == wechat);
/**
* 结果:
* --- 支付宝way() ---
* 支付宝支付方式
* --- 微信way() ---
* 微信支付方式
* true
*/
}
public static void test2() {
ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
//验证不指定前缀的情况,这里会报错
Order alipay = loader.getDefaultExtension();
System.out.println(alipay.way());
/**
* 结果:
* Exception in thread "main" java.lang.IllegalArgumentException: Extension name == null
* at org.apache.dubbo.common.extension.ExtensionLoader.getExtension(ExtensionLoader.java:340)
* at com.example.spidemo.dubbo.adaptive.DubboSpiTest02.main(DubboSpiTest02.java:14)
*/
}
流程
// 1.构造Order的ExtensionLoader,其中还构造了对应的ExtensionFactory -》AdaptiveExtensionFactory();
1.ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
2.1.loader.getExtension("alipay");
2.2.loader.getDefaultExtension();
2.3.loader.getAdaptiveExtension();
2.4.loader.getActivateExtension(url, "", "online");
ExtensionLoader的核心属性
// 加载文件的路径
// "META-INF/services/"、"META-INF/dubbo/" 、"META-INF/dubbo/internal/"
private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
// 存储的是 SPI接口类和ExtensionLoader对象的映射关系 缓存池
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
// 存储的是 每个SPI接口的多个实现类和对应实例之间的关系
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
// 接口的类型
private final Class<?> type;
// 获取工厂类,用于获取Spring容器中的Bean
private final ExtensionFactory objectFactory;
// 扩展类和扩展名称映射关系
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
// 扩展名称和扩展类类型映射关系
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
// 扩展名称和自动激活扩展类映射关系
private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
// 扩展名称和扩展类实例映射关系
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
// 自适应扩展类实例缓存
private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
// 自适应扩展类
private volatile Class<?> cachedAdaptiveClass = null;
// 默认的服务提供者的名称
private String cachedDefaultName;
// 包装扩展类集合
private Set<Class<?>> cachedWrapperClasses;
源码解析
ExtensionLoader.getExtensionLoader(Order.class);
流程
代码解析
// 1.ExtensionLoader.getExtensionLoader源码
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 an interface!");
}
// 必须有@SPI注解
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @"
+ SPI.class.getSimpleName() + "!");
}
// 在ExtensionLoader缓存池中获取
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
// 不存在,则new一个对应SPI的ExtensionLoader(***重点***)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
// 添加到缓存池中
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
// withExtensionAnnotation方法
private static <T> boolean withExtensionAnnotation(Class<T> type) {
return type.isAnnotationPresent(SPI.class);
}
// 2.new ExtensionLoader<T>(type)源码解析
private ExtensionLoader(Class<?> type) {
// 设置SPI的类型
this.type = type;
// type是不是为ExtensionFactory?是则返回null, 不是则去获取一个ExtensionFactory的ExtensionLoader的适配器扩展器
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
// 3.getAdaptiveExtension()方法
public T getAdaptiveExtension() {
// 从当前的SPI的ExtensionLoader中的缓存池中获取适配器
Object instance = cachedAdaptiveInstance.get();
// dubbo check
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 创建一个SPI的适配器扩展器,并放入的缓存池中(***重点***)
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
// 4.createAdaptiveExtension()方法
private T createAdaptiveExtension() {
try {
// 获取适配器扩展器,然后在获取实例对象,再注入属性(injectExtension,IOC的实现)
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
// 5.获取扩展器的适配器
private Class<?> getAdaptiveExtensionClass() {
// 1.加载默认的扩展器的名称
// 2.加载各个目录下的SPI的服务提供者:
// 2.1.如果是适配器,则加载到适配器的缓存中(PS:在方法上加@Adaptive,不会被加载到适配器缓存池中)
// 2.2.如果是装饰器,则加载到装饰器的缓存中
// 2.3.加载自动激活的缓存中
// 2.4 加载到缓存cachedNames中(k->class,v->name)
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 如果没有扩展器的适配器,则去动态创建一个(比较复杂)
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
// 6. loadExtensionClasses()方法
private Map<String, Class<?>> loadExtensionClasses() {
// 1.获取SPI的value获取默认名字 加载默认的扩展器的名称
cacheDefaultExtensionName();
// 2. 加载各个目录下的SPI的配置文件
// 2.1.如果是适配器,则加载到适配器的缓存中
// 2.2.如果是装饰器,则加载到装饰器的缓存中
// 2.3.把name加载自动激活的缓存中,把name到SPI的name缓存池,把SPI name和类的对应关系缓存到
Map<String, Class<?>> extensionClasses = new HashMap<>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
// 7.loadDirectory加载目录下的类
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
String fileName = dir + type;
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();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
// 8.加载资源loadResource
// 9.加载类
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
// 如果是适配器,则加载到适配器的缓存中
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
// 如果是装饰器,则加载到装饰器的缓存中
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
} else {
clazz.getConstructor();
if (StringUtils.isEmpty(name)) {
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 (ArrayUtils.isNotEmpty(names)) {
// 把name加载自动激活的缓存中
cacheActivateClass(clazz, names[0]);
for (String n : names) {
// 把name到SPI的name缓存池,把SPI name和类的对应关系缓存到
cacheName(clazz, n);
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
其实我们不难发现上述只是加载的我们SPI对应ExtensionLoader的ExtensionFactory的getAdaptiveExtension()
–> AdaptiveExtensionFactory
1.常用方法extensionLoader.getExtension(“alipay”);
流程
代码解析
// 1.获取Order的名称为"alipay"的SPI
public T getExtension(String name) {
// 校验
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
// 如果名字为true,则返回默认的SPI
if ("true".equals(name)) {
return getDefaultExtension();
}
// 从cachedInstances缓存池中获取"alipay"的实现类。
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
// dubbo check
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 创建一个实现类的实例Bean,并设置到缓存池中。
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
// 2.创建Extension createExtension(name);
private T createExtension(String name) {
// 1.加载默认的扩展器的名称
// 2.加载各个目录下的SPI的服务提供者:
// 2.1.如果是适配器,则加载到适配器的缓存中(PS:在方法上加@Adaptive,不会被加载到适配器缓存池中)
// 2.2.如果是装饰器,则加载到装饰器的缓存中
// 2.3.加载自动激活的缓存中
// 2.4 加载到缓存cachedNames中(k->class,v->name)
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
// 在配置文件中找不到,则抛异常。
throw findException(name);
}
try {
// 实例化class对象,并放在缓存池中
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 注入数据
injectExtension(instance);
// 判断是否有装饰器,有则遍历装饰器
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
// 一套又一套
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 + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
// 3.注入属性
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
// 只能注入setter方法的属性。
if (isSetter(method)) {
/**
* 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);
// 调用AdaptiveExtensionFactory的 方法获取属性值。
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
} 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;
}
// 3.1. 调用AdaptiveExtensionFactory的getExtension(pt, property)
public <T> T getExtension(Class<T> type, String name) {
// 循环遍历SpiExtensionFactory和SpringExtensionFactory。
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
2.常用方法loader.getAdaptiveExtension();
流程
代码解析
// loader.getAdaptiveExtension() ,整体逻辑和getExtension("alipay") 差不多。
// 唯一有区别的是
// getAdaptiveExtension()是createAdaptiveExtension()
// getExtension("alipay")是createExtension("alipay")
public T getAdaptiveExtension() {
// 从适配器缓存池中拿,如果没有则用createAdaptiveExtension()生成一个,再设置到缓存池中。
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 生成适配器类的实例对象instance,并设置到缓存中
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
// 2.createAdaptiveExtension()
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
// 3.getAdaptiveExtensionClass()
private Class<?> getAdaptiveExtensionClass() {
// 1.加载默认的扩展器的名称
// 2.加载各个目录下的SPI的服务提供者:
// 2.1.如果是适配器,则加载到适配器的缓存中(PS:在方法上加@Adaptive,不会被加载到适配器缓存池中)
// 2.2.如果是装饰器,则加载到装饰器的缓存中
// 2.3.加载自动激活的缓存中
// 2.4 加载到缓存cachedNames中(k->class,v->name)
getExtensionClasses();
// 如果在适配器的缓存池有对应的适配器类,则返回对应的适配器类
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 如果在适配器缓存池中没有对应的适配类,则创建一个。
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
// 4.createAdaptiveExtensionClass() 创建一个适配器类
private Class<?> createAdaptiveExtensionClass() {
// 生成适配器的源码
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
// 类加载器
ClassLoader classLoader = findClassLoader();
// 通过SPI获取编译器的适配器类,再动态编译这个适配器的源码,生成类。
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
// 5.new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
public String generate() {
// 如果方法中没有@Adaptive注解,则抛异常
if (!hasAdaptiveMethod()) {
throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
}
StringBuilder code = new StringBuilder();
// 生成package信息
code.append(generatePackageInfo());
// 生成import信息
code.append(generateImports());
// 生成类信息 public class %s$Adaptive implements....
code.append(generateClassDeclaration());
// 获取type的方法,生成方法信息 public %s %s(%s) %s {%s}
Method[] methods = type.getMethods();
for (Method method : methods) {
code.append(generateMethod(method));
}
code.append("}");
if (logger.isDebugEnabled()) {
logger.debug(code.toString());
}
return code.toString();
}
3.常用方法loader.getActivateExtension(url, “”, “online”);课后讨论:
// 1.生成自动激活的扩展类集合
public List<T> getActivateExtension(URL url, String key, String group) {
// 获取URL的key对应的value
String value = url.getParameter(key);
// value即name,可以用","分隔
return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
}
// 2,获取getActivateExtension()
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<>();
List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
// 名字中不包含"-default"
if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
// 1.加载默认的扩展器的名称
// 2.加载各个目录下的SPI的服务提供者:
// 2.1.如果是适配器,则加载到适配器的缓存中(PS:在方法上加@Adaptive,不会被加载到适配器缓存池中)
// 2.2.如果是装饰器,则加载到装饰器的缓存中
// 2.3.加载自动激活的缓存中(cachedActivates)
// 2.4 加载到缓存cachedNames中(k->class,v->name)
getExtensionClasses();
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Object activate = entry.getValue();
String[] activateGroup, activateValue;
if (activate instanceof Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
// 适配alibaba版本的,现在的是apache版本
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
// activateGroup中包含了group
if (isMatchGroup(group, activateGroup)) {
// 获取扩展类的实例
T ext = getExtension(name);
if (!names.contains(name)
&& !names.contains(REMOVE_VALUE_PREFIX + name)
&& isActive(activateValue, url)) {
// 符合上述要求则加到集合中
exts.add(ext);
}
}
}
// 根据@Activate 排序
exts.sort(ActivateComparator.COMPARATOR);
}
List<T> usrs = new ArrayList<>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
// value的值不是以"-"开始,且 不包含"-"+$name
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX + name)) {
// 如果名字为"default"
if (DEFAULT_KEY.equals(name)) {
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
// 根据name获取Extension的实例,并放入usrs
T ext = getExtension(name);
usrs.add(ext);
}
}
}
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}
总结
Dubbo 的SPI的优势:
- 有缓存(都有缓存)
- 可以结合Spring容器实现属性注入。
- 通过wrapper 装饰器实现类似AOP的功能。
- 通过@Adaptive 配置适配器的类,就支持一个场景使用多种实现类。
觉得博主写的还可以的,帮忙点个赞呗。