這篇文章主要講解了“Dubbo的SPI機制介紹以及SPI加載class的方法”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Dubbo的SPI機制介紹以及SPI加載class的方法”吧!

成都創(chuàng)新互聯(lián)公司是專業(yè)的祿勸網(wǎng)站建設公司,祿勸接單;提供網(wǎng)站設計制作、成都網(wǎng)站制作,網(wǎng)頁設計,網(wǎng)站設計,建網(wǎng)站,PHP網(wǎng)站建設等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行祿勸網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!
@SPI
public interface Robot {
void sayHello();
}
public class OptimusPrime implements Robot{
@Override
public void sayHello() {
System.out.println("Hello, I am Optimus Prime.");
}
}
public class Bumblebee implements Robot{
@Override
public void sayHello() {
System.out.println("Hello, I am Bumblebee.");
}
}public class DubboSPITest {
@Test
public void sayHelloDubbo() throws Exception {
ExtensionLoader<robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
optimusPrime.sayHello();
Robot bumblebee = extensionLoader.getExtension("bumblebee");
bumblebee.sayHello();
}
}輸出: Hello, I am Optimus Prime. Hello, I am Bumblebee.
ExtensionLoader<robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
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!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
// 從緩存中獲取與拓展類對應的ExtensionLoader
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
// 若緩存未命中,則創(chuàng)建一個新的實例,先簡單看下new ExtensionLoader<T>(type)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}這里的objectFactory創(chuàng)建可以參考: Dubbo的SPI機制分析3-Dubbo的IOC依賴注入
private ExtensionLoader(Class<?> type) {
this.type = type;
// 這里的type是Robot.class,所以會執(zhí)行后面的代碼,加載并創(chuàng)建SpiExtensionFactory和SpringExtensionFactory,
objectFactory = (type == ExtensionFactory.class ? null :
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}Robot optimusPrime = extensionLoader.getExtension("optimusPrime");public T getExtension(String name) {
if ("true".equals(name)) {
return getDefaultExtension();
}
// Holder也是用于持有對象的,用作緩存
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) {
// 創(chuàng)建拓展實例,下面分析createExtension(name)
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}這里依賴注入可以參考: Dubbo的SPI機制分析3-Dubbo的IOC依賴注入
private T createExtension(String name) {
// 從配置文件中加載所有的拓展類,可得到“配置項名稱”到“配置類”的映射關(guān)系表
// 加載完后根據(jù)name獲取,得到形如com.alibaba.dubbo.demo.provider.spi.OptimusPrime
// 待會重點分析getExtensionClasses(),刪去了一些非關(guān)鍵代碼
Class<?> clazz = getExtensionClasses().get(name);
try {
// 也是嘗試先從緩存獲取,獲取不到通過反射創(chuàng)建一個并放到緩存中
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;
}
} private Map<String, Class<?>> getExtensionClasses() {
// 從緩存中獲取映射關(guān)系表
Map<string, class<?>> classes = cachedClasses.get();
// 雙重檢查
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
// 若緩存中沒有,去加載映射關(guān)系
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}private Map<string, class<?>> loadExtensionClasses() {
// 獲取SPI注解,這里的type是在調(diào)用getExtensionLoader方法時傳入的
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) {
// 拋異常
}
// 獲取@SPI注解中的值,并緩存起來,可以關(guān)注下,后面會用到
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;
}private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
// fileName是META-INF/dubbo/com.alibaba.dubbo.demo.provider.spi.Robot
String fileName = dir + type.getName();
try {
Enumeration<java.net.url> urls;
ClassLoader classLoader = findClassLoader();
// 根據(jù)文件名加載所有同名文件
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
// 一個resourceURL就是一個文件
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
}
}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;
// 按行讀取配置內(nèi)容
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);
}
}
}
}
}
}
}標注1,這里的可以參考: Dubbo的SPI機制分析2-Adaptive詳解
標注2,這里的可以參考: Dubbo的SPI機制分析4-Dubbo通過Wrapper實現(xiàn)AOP
標注3,這里的cachedActivates可以參考: Dubbo的SPI機制分析5-Activate詳解
private void loadClass(Map<string, Class<?>> extensionClasses, java.net.URL resourceURL,
Class<?> clazz, String name) throws NoSuchMethodException {
// clazz必須是type類型的,否則拋異常
if (!type.isAssignableFrom(clazz)) {
}
// 判斷clazz是否為標注了@Adaptive注解,標注1
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
// 拋異常,不能有多個標注有@Adaptive注解的類
}
}
// 判斷是否是Wrapper類型,標注2
else if (isWrapperClass(clazz)) {
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
}
// 程序進入此分支,表明clazz是一個普通的拓展類,Robot就是一個普通的拓展類
else {
// 檢測clazz是否有默認的構(gòu)造方法,如果沒有,則拋出異常
clazz.getConstructor();
if (name == null || name.length() == 0) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
// 拋異常
}
}
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
// 用于@Activate根據(jù)條件激活,標注3
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的映射關(guān)系,這樣就解析好了一行
extensionClasses.put(n, clazz);
} else if (c != clazz) {
// 拋異常
}
}
}
}
}感謝各位的閱讀,以上就是“Dubbo的SPI機制介紹以及SPI加載class的方法”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Dubbo的SPI機制介紹以及SPI加載class的方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
文章名稱:Dubbo的SPI機制介紹以及SPI加載class的方法
轉(zhuǎn)載來于:http://www.chinadenli.net/article34/gshose.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、域名注冊、搜索引擎優(yōu)化、網(wǎng)站設計、標簽優(yōu)化、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)