简介
SPI全称Service Provider Interface,是Java供给的一套用来被第三方完成或者扩展的,它可以用来启用结构扩展和替换组件。
咱们体系里笼统的各个模块,往往有许多不同的完成计划,比方日志模块、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 Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.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 装备适配器的类,就支持一个场景使用多种完成类。