Apollo-Client 使用SPI和Guice创建加载实例对象
程序员文章站
2022-04-17 17:25:49
...
背景
Guide:https://www.jianshu.com/p/7fba7b43146a
SPI:https://www.jianshu.com/p/46b42f7f593c
1.Injector
/**
* @author Jason Song(aaa@qq.com)
*/
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(aaa@qq.com)
*/
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 目录下的类。内容填写的类必须实现文件名中的类,否则报错。
- 文件内容具体如下图所示:
流程图
若有错请留言,谢谢啦!
上一篇: Windows上安装Jekyll