背景
Guide:https://www.jianshu.com/p/7fba7b43146a
SPI:https://www.jianshu.com/p/46b42f7f593c
1.Injector
/**
* @author Jason Song([email protected])
*/
public interface Injector {
/**
* Returns the appropriate instance for the given injection type
*/
<T> T getInstance(Class<T> clazz);
/**
* Returns the appropriate instance for the given injection type and name
*/
<T> T getInstance(Class<T> clazz, String name);
}
- Injector接口定義了 guice獲取實例的抽象方法。
1.1 DefaultInjector
該類是Inject的的實現類,初始化了Guice容器的過程。
/**
* Guice injector
* @author Jason Song([email protected])
*/
public class DefaultInjector implements Injector {
private com.google.inject.Injector m_injector;
public DefaultInjector() {
try {
// 實例化 Injector 對象
m_injector = Guice.createInjector(new ApolloModule());
} catch (Throwable ex) {
ApolloConfigException exception = new ApolloConfigException("Unable to initialize Guice Injector!", ex);
Tracer.logError(exception);
throw exception;
}
}
@Override
public <T> T getInstance(Class<T> clazz) {
try {
//通過類型獲取實例對象
return m_injector.getInstance(clazz);
} catch (Throwable ex) {
Tracer.logError(ex);
throw new ApolloConfigException(
String.format("Unable to load instance for %s!", clazz.getName()), ex);
}
}
@Override
public <T> T getInstance(Class<T> clazz, String name) {
//該方法直接返回null,Guice不支持通過類型和類名查找實例。
//Guice does not support get instance by type and name
return null;
}
private static class ApolloModule extends AbstractModule {
@Override
protected void configure() {
bind(ConfigManager.class).to(DefaultConfigManager.class).in(Singleton.class);
bind(ConfigFactoryManager.class).to(DefaultConfigFactoryManager.class).in(Singleton.class);
bind(ConfigRegistry.class).to(DefaultConfigRegistry.class).in(Singleton.class);
bind(ConfigFactory.class).to(DefaultConfigFactory.class).in(Singleton.class);
bind(ConfigUtil.class).in(Singleton.class);
bind(HttpUtil.class).in(Singleton.class);
bind(ConfigServiceLocator.class).in(Singleton.class);
bind(RemoteConfigLongPollService.class).in(Singleton.class);
bind(YamlParser.class).in(Singleton.class);
}
}
}
- Guice不支持通過類型和對象名獲取實例。
- 靜態內部類ApolloModule繼承com.google.inject.AbstractModule重寫configure方法,綁定指定類。
2. ApolloInjector
2.1 getInjector
#getInjector獲取Injector實例,即爲了獲取DefaultInjector,從而獲取Guice容器內的已綁定的實例對象。
private static volatile Injector s_injector;
private static final Object lock = new Object();
/**
* 獲取 Injector 實例
* @return
*/
private static Injector getInjector() {
if (s_injector == null) {
synchronized (lock) {
if (s_injector == null) {
try {
//創建Injector實例
s_injector = ServiceBootstrap.loadFirst(Injector.class);
} catch (Throwable ex) {
ApolloConfigException exception = new ApolloConfigException("Unable to initialize Apollo Injector!", ex);
Tracer.logError(exception);
throw exception;
}
}
}
}
return s_injector;
}
- 這裏獲取Injector是線程安全的,懶漢模式創建實例對象。ServiceBootstrap#loadFirst是通過SPI創建指定類型的對象,下面會詳細說明。
2.2 getInstance
通過Injector獲取Guice容器內綁定的類。
public static <T> T getInstance(Class<T> clazz) {
try {
return getInjector().getInstance(clazz);
} catch (Throwable ex) {
Tracer.logError(ex);
throw new ApolloConfigException(String.format("Unable to load instance for type %s!", clazz.getName()), ex);
}
}
public static <T> T getInstance(Class<T> clazz, String name) {
try {
//目前只支持Guice獲取指定類型對象,但Guice不支持通過類型和名字獲取
return getInjector().getInstance(clazz, name);
} catch (Throwable ex) {
Tracer.logError(ex);
throw new ApolloConfigException(
String.format("Unable to load instance for type %s and name %s !", clazz.getName(), name), ex);
}
}
- Guice只能通過 Injector指定類型 創建/獲取 綁定的類,不支持通過類型和命令獲取。
3.ServiceBootstrap
封裝了SPI 通用的操作方法
public class ServiceBootstrap {
/**
* 返回指定類型的第一個實例
*
* @param clazz
* @param <S>
* @return
*/
public static <S> S loadFirst(Class<S> clazz) {
//獲取所有實例
Iterator<S> iterator = loadAll(clazz);
// 目錄/META-INF/services/{clazzName} 下沒有找到該類型的文件則拋出 IllegalStateException異常
if (!iterator.hasNext()) {
throw new IllegalStateException(String.format(
"No implementation defined in /META-INF/services/%s, please check whether the file exists and has the right implementation class!",
clazz.getName()));
}
//返回第一個實例
return iterator.next();
}
/**
* 指定類型創建配置文件中所有的實例
*
* @param clazz
* @param <S>
* @return
*/
public static <S> Iterator<S> loadAll(Class<S> clazz) {
// 加載 /META-INF/services/{clazzName} 文件內填寫的所有類並創建對象
ServiceLoader<S> loader = ServiceLoader.load(clazz);
// 獲取 /META-INF/services/{clazzName} 填寫的所有類並返回對應的集合
return loader.iterator();
}
/**
* 返回order排序後的對象集合
*
* @param clazz
* @param <S>
* @return
*/
public static <S extends Ordered> List<S> loadAllOrdered(Class<S> clazz) {
Iterator<S> iterator = loadAll(clazz);
// 目錄/META-INF/services/{clazzName} 下沒有找到該類型的文件則拋出 IllegalStateException異常
if (!iterator.hasNext()) {
throw new IllegalStateException(String.format(
"No implementation defined in /META-INF/services/%s, please check whether the file exists and has the right implementation class!",
clazz.getName()));
}
List<S> candidates = Lists.newArrayList(iterator);
Collections.sort(candidates, new Comparator<S>() {
@Override
public int compare(S o1, S o2) {
// the smaller order has higher priority
// 順序越小優先級越高
return Integer.compare(o1.getOrder(), o2.getOrder());
}
});
return candidates;
}
/**
* 返回 優先級越高的 實例(Order最小)
* @param clazz
* @param <S>
* @return
*/
public static <S extends Ordered> S loadPrimary(Class<S> clazz) {
List<S> candidates = loadAllOrdered(clazz);
return candidates.get(0);
}
}
- ServiceLoader#load加載的是 /META-INF/services/%s 目錄下的類。內容填寫的類必須實現文件名中的類,否則報錯。
- 文件內容具體如下圖所示:
流程圖
若有錯請留言,謝謝啦!