所以他们俩的区别就很明显了,API的调用方只能依赖使用提供方的实现,SPI就如同可定制化的API一样,调用方可以自定义实现替换API提供的默认实现
public interface Car {
@Adaptive
String getCarName(URL url);
String sayHell();
}
public class BlackCar implements Car {
@Override
public String getCarName(URL url) {
return "black";
}
@Override
public String sayHell() {
return null;
}
}
public class SpiTest {
public static void main(String[] args) {
// javaSPI
ServiceLoader<Car> cars = ServiceLoader.load(Car.class);
for (Car car : cars) {
System.out.println(car.getCarName(null));
}
}
// 需要在classpath:META-INFO.services 下配置一个与接口全类名的文件(com.spi.Car)
// 内容: com.spi.BlackCar
// com.spi.RedCar
为什么Dubbo还要自己搞SPI?
javaSPI 的局限性:
1、没法给实现类起别名
2、没法实现包装类。类似AOP的原理
3、没法实现自动注入
4、没法实现按需加载。一次性就会加载配置文件中配置的所有类
public class SpiTest {
public static void main(String[] args) {
ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);
Car person = extensionLoader.getExtension("black"); // BlackPerson
System.out.println(c.getCarName()); // 代理逻辑
}
public class CarWrapper implements Car {
private Car car;
public CarWrapper(Car car) {
this.car = car;
}
@Override
public String getCarName() {
System.out.println("wrapper...");
return car.getCarName();
}
@Override
public String sayHell() {
return null;
}
}
public class BlackCar implements Car {
@Override
public String getCarName() {
return "black";
}
@Override
public String sayHell() {
return null;
}
}
@SPI
public interface Car {
String getCarName();
String sayHell();
}
red=com.spi.RedCar
black=com.spi.BlackCar
com.spi.CarWrapper
wrapper...
black
使用:
1、@SPI 注解需要打在接口上
2、META-INFO.dubbo下需要创建一个与接口全类名相同的文件
3、配置文件内需要配置实现类全类名
4、Wrapper类(类似AOP)需要通过有参构造方法来注入
大致梳理流程:
1、根据指定的接口加载配置文件
2、根据配置文件加载对应的类 缓存起来
3、根据加载的类按需反射生成对象 缓存起来
4、完成自动注入
ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);
// 该方法就是生成一个Loader对象其中包括指定的接口
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!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
Car car = extensionLoader.getExtension(“red”);
@SuppressWarnings("unchecked")
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
// 获取默认扩展类 @SPI 注解上标注的value
if ("true".equals(name)) {
return getDefaultExtension();
}
// 为什么要用一个holder来包装?
// 思考: 要加锁,如果不用holder来包装的话锁的对象不好弄。
// 因为一开始创建都是null会导致全都拿null来当锁。就单线程了。
// 如果直接拿name当锁不优雅
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
// 如果有两个线程同时来获取同一个name的扩展点对象,那只会有一个线程会进行创建
if (instance == null) {
synchronized (holder) { // 一个name对应一把锁
instance = holder.get();
if (instance == null) {
// 创建扩展点实例对象
instance = createExtension(name); // 创建扩展点对象
holder.set(instance);
}
}
}
return (T) instance;
}
instance = createExtension(name);
private T createExtension(String name) {
// 获取扩展类 {name: Class} key-Value 接口的所有实现类
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);
}
// 依赖注入 IOC
injectExtension(instance);
// AOP,cachedWrapperClasses无序
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);
}
}
1、读取META-INF下 的配置文件加载类
2、将类分几种情况
2.1 接口上@SPI 注解value 为默认实现类extensionLoader.getExtension(“true”) 既可直接获取默认实例
2.2 实现类上加了@Adaptive 注解,当调用extensionLoader.getActivateExtension()既可直接获取自适应实例。
2.3 有 一个有参构造函数(参数就是该接口)的为wapper类
2.4 剩下的就是普通的一个实现类
getExtensionClasses() 这里终于去加载配置文件了
getExtensionClasses
– loadExtensionClasses
– loadDirectory
private Map<String, Class<?>> loadExtensionClasses() {
// cache接口默认的扩展类
cacheDefaultExtensionName();
// 这里都是调用同一个方法。只是路径传的不同。这些路径都是固定的就包括了META-INF.dubbo
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;
}
// 接口的@SPI注解上可以制定一个默认的实现类
private void cacheDefaultExtensionName() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation == null) {
return;
}
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));
}
if (names.length == 1) {
cachedDefaultName = names[0];
}
}
}
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
String fileName = dir + type;
try {
// 根据文件中的内容得到urls, 每个url表示一个扩展 http=org.apache.dubbo.rpc.protocol.http.HttpProtocol
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();
// 遍历url进行加载,把扩展类添加到extensionClasses中
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
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) {
// 加载类,并添加到extensionClasses中
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);
}
}
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
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.");
}
// 当前接口手动指定了Adaptive类
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
} else if (isWrapperClass(clazz)) {
// 是一个Wrapper类
cacheWrapperClass(clazz);
} else {
// 需要有无参的构造方法
clazz.getConstructor();
// 在文件中没有name,但是在类上指定了Extension的注解上指定了name
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)) {
// 缓存一下被Activate注解了的类
cacheActivateClass(clazz, names[0]);
// 有多个名字
for (String n : names) {
// clazz: name
cacheName(clazz, n);
// name: clazz
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
ExtensionLoader.injectExtension() 对前面创建出来的对象进行属性自动注入
1、通过seter方法来获取需要注入的实例名
2、从ioc中获取。 dubbo支持从 spring和spi两种方式来注入
private T injectExtension(T instance) {
if (objectFactory == null) {
return instance;
}
try {
for (Method method : instance.getClass().getMethods()) {
if (!isSetter(method)) {
continue;
}
// 利用set方法注入
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
// set方法中的参数类型
Class<?> pt = method.getParameterTypes()[0]; // Person接口
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
// 得到setXxx中的xxx
String property = getSetterProperty(method); // person
// 根据参数类型或属性名,从objectFactory中获取到对象,然后调用set方法进行注入
// AdaptiveExtensionFactory
Object object = objectFactory.getExtension(pt, property); // User.class, user
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;
}
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
// 支持哪些ExtensionFactory (Spi, SPring)
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) { // spi, spring
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
@Override
public <T> T getExtension(Class<T> type, String name) {
// 遍历两个ExtensionFactory,从ExtensionFactory中得到实例,只要从某个ExtensionFactory中获取到对象实例就可以了
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name); // SpringExtensionFactory,, SpiExtensionFactory
if (extension != null) {
return extension;
}
}
return null;
}
}
@Override
public <T> T getExtension(Class<T> type, String name) {
// 遍历两个ExtensionFactory,从ExtensionFactory中得到实例,只要从某个ExtensionFactory中获取到对象实例就可以了
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name); // SpringExtensionFactory,, SpiExtensionFactory
if (extension != null) {
return extension;
}
}
return null;
}
/**
* SpiExtensionFactory
*/
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
// 接口上存在SPI注解
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension(); // 接口的Adaptive类(代理对象)
}
}
return null;
}
}
/**
* SpringExtensionFactory
*/
public class SpringExtensionFactory implements ExtensionFactory {
private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();
private static final ApplicationListener SHUTDOWN_HOOK_LISTENER = new ShutdownHookListener();
public static void addApplicationContext(ApplicationContext context) {
CONTEXTS.add(context);
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).registerShutdownHook();
DubboShutdownHook.getDubboShutdownHook().unregister();
}
BeanFactoryUtils.addApplicationListener(context, SHUTDOWN_HOOK_LISTENER);
}
public static void removeApplicationContext(ApplicationContext context) {
CONTEXTS.remove(context);
}
public static Set<ApplicationContext> getContexts() {
return CONTEXTS;
}
// currently for test purpose
public static void clearContexts() {
CONTEXTS.clear();
}
// 从Spring容器中获取bean
// 先根据name拿,再根据类型拿
@Override
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
//SPI should be get from SpiExtensionFactory
// 如果接口上存在SPI注解,就不从spring中获取对象实例了
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
return null;
}
// 从ApplicationContext中获取bean, byname
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;
}
// byType
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;
}
private static class ShutdownHookListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextClosedEvent) {
DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();
shutdownHook.doDestroy();
}
}
}
}
dubbo的aop就很简单就是通过wapper接口来实现
例如上面WapperCar:
即在获取black时会把BlackCar通过构造方法传给WapperCar,然后返回WapperCar对象。
所有AOP代理逻辑都在WapperCar里面实现。
private T createExtension(String name) {
// 获取扩展类 {name: Class} key-Value 接口的所有实现类
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);
}
// 依赖注入 IOC
injectExtension(instance);
// AOP,cachedWrapperClasses无序
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);
}
}
@Adaptive 打在类上
@Adaptive 打在方法上
ExtensionLoader 类的构造方法中有一段逻辑。ExtensionFactory的Adaptive实现类
private ExtensionLoader(Class<?> type) {
this.type = type;
// objectFactory表示当前ExtensionLoader内部的一个对象工厂,可以用来获取对象 AdaptiveExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
//其中AdaptiveExtensionFactory就是在类上加了@Adaptive注解
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory
//这段代码就是会获取被@Adaptive标注的实现类
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError != null) {
throw new IllegalStateException("Failed to create adaptive instance: " +
createAdaptiveInstanceError.toString(),
createAdaptiveInstanceError);
}
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
return (T) instance;
}
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);
}
}
private Class<?> getAdaptiveExtensionClass() {
// 获取当前接口的所有扩展类
getExtensionClasses();
// 缓存了@Adaptive注解标记的类
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 如果某个接口没有手动指定一个Adaptive类,那么就自动生成一个Adaptive类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
private Class<?> createAdaptiveExtensionClass() {
// cachedDefaultName表示接口默认的扩展类
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
上面如果没有找到@Adaptive标注的类。则会去动态代理生成一个类。@Adaptive在方法上的作用就体现出来了
1、加了@Adaptive 的方法会被代理。其他的方法则默认方法体都是抛异常
2、加了@Adaptive 的方法的形参上必须有URL类型的参数或者对象有getURL的方法。可以看代理类的源代码。
public String generate() {
// no need to generate adaptive class since there's no adaptive method found.
if (!hasAdaptiveMethod()) {
throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
}
StringBuilder code = new StringBuilder();
code.append(generatePackageInfo());
code.append(generateImports());
code.append(generateClassDeclaration());
// 遍历接口中的方法,生成代理方法
Method[] methods = type.getMethods();
for (Method method : methods) {
code.append(generateMethod(method));
}
code.append("}");
if (logger.isDebugEnabled()) {
logger.debug(code.toString());
}
return code.toString();
}
/**
* generate method declaration
*/
private String generateMethod(Method method) {
String methodReturnType = method.getReturnType().getCanonicalName();
String methodName = method.getName();
// 生成方法体很重要
String methodContent = generateMethodContent(method);
String methodArgs = generateMethodArguments(method);
String methodThrows = generateMethodThrows(method);
return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
}
/**
* generate method content
*/
private String generateMethodContent(Method method) {
// 方法上存在Adaptive注解才进行代理
Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
StringBuilder code = new StringBuilder(512);
if (adaptiveAnnotation == null) {
return generateUnsupported(method);
} else {
// 方法中URL类型参数的下标
int urlTypeIndex = getUrlTypeIndex(method);
// found parameter in URL type
// 寻找URL
// 1. 如果当前方法中有URl类型的参数,那么url就是该参数值
// 2. 如果当前方法中没有URL类型的参数,但是当前方法中有某个类型中的get方法返回了URl类型,那么就调用那个get方法得到一个url对象
if (urlTypeIndex != -1) {
// Null Point check
code.append(generateUrlNullCheck(urlTypeIndex));
} else {
// did not find parameter in URL type
code.append(generateUrlAssignmentIndirectly(method));
}
// 根据这个value去找具体的扩展类
String[] value = getMethodAdaptiveValue(adaptiveAnnotation);
// 方法中有Invocation类型的参数
boolean hasInvocation = hasInvocationArgument(method);
code.append(generateInvocationArgumentNullCheck(method));
code.append(generateExtNameAssignment(value, hasInvocation));
// check extName == null?
code.append(generateExtNameNullCheck(value));
code.append(generateExtensionAssignment());
// return statement
code.append(generateReturnAndInvocation(method));
}
return code.toString();
}
原接口
@SPI
public interface Car {
@Adaptive
String getCarName(URL url);
String sayHell();
}
代理生成的类代码:
package com.spi;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Car$Adaptive implements com.spi.Car {
public java.lang.String sayHell() {
throw new UnsupportedOperationException("The method public abstract java.lang.String com.spi.Car.sayHell() of interface com.spi.Car is not adaptive method!");
}
public java.lang.String getCarName(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("car");
if (extName == null)
throw new IllegalStateException("Failed to get extension (com.spi.Car) name from url (" + url.toString() + ") use keys([car])");
com.spi.Car extension = (com.spi.Car) ExtensionLoader.getExtensionLoader(com.spi.Car.class).getExtension(extName);
return extension.getCarName(arg0);
}
}