2021SC@SDUSC
一、代码分析内容
本次博客介绍ActiveJ中inject模块的第四个部分:module包。inject之所以需要module包是和binding这个绑定包是有关系的。
依赖关系图很难直接创建,因此我们使用一个简单但功能强大的DSL提供了自动图转换、生成和验证机制。
所有这些预处理步骤都是在启动时通过编译module来执行的。每个模块导出相互组合的绑定。如果任何一个键有两个或多个绑定,则使用用户提供的Multibinder reduce函数将它们简化为一个绑定。
我们可以看一下调用Module接口的使用代码:
public interface Module {
Trie<Scope, Map<Key<?>, Set<Binding<?>>>> getBindings();
Map<Integer, Set<BindingTransformer<?>>> getBindingTransformers();
Map<Class<?>, Set<BindingGenerator<?>>> getBindingGenerators();
Map<Key<?>, Multibinder<?>> getMultibinders();
}
二、module包结构
module包中有12个类,其中4个接口,1个注释,7个类。本次博客着重介绍其中几个。
三、代码解读
1.Module类:
模块是一个对象,它提供某些数据结构中由键排列的绑定集、转换器、生成器或多绑定器。
从下面的代码可以看出上面解释的意义,使用了Scope,Key和Binding。
Trie<Scope, Map<Key<?>, Set<Binding<?>>>> getBindings();
下面的代码是通过键排列获得绑定集。
default Trie<Scope, Set<Key<?>>> getExports() {
return getBindings().map(map -> map.keySet().stream().filter(key -> !isUnique(key.getQualifier())).collect(toSet()));
}
返回一个空的module:
static Module empty() {
return Modules.EMPTY;
}
从给定的绑定图trie创建Module:
static Module of(Trie<Scope, Map<Key<?>, Set<Binding<?>>>> bindings) {
return new SimpleModule(bindings, emptyMap(), emptyMap(), emptyMap());
}
2.Modules类
此类包含一组用于处理Module接口模块的实用程序。下面我介绍几个我认为比较有用的方法。
2.1combine(Collection< Module> modules)方法
将多个模块合并为一个模块:
这个方法式将多个Module类合并成一个SimpleModule类,这个方法可以简化Module,还是比较使用的。
public static Module combine(Collection<Module> modules) {
if (modules.size() == 1) {
return modules.iterator().next();
}
Trie<Scope, Map<Key<?>, Set<Binding<?>>>> bindings = Trie.merge(bindingMultimapMerger(), new HashMap<>(), modules.stream().map(Module::getBindings));
Map<KeyPattern<?>, Set<BindingGenerator<?>>> bindingGenerators = new HashMap<>();
Map<KeyPattern<?>, Set<BindingTransformer<?>>> bindingTransformers = new HashMap<>();
Map<Key<?>, Multibinder<?>> multibinders = new HashMap<>();
for (Module module : modules) {
combineMultimap(bindingTransformers, module.getBindingTransformers());
combineMultimap(bindingGenerators, module.getBindingGenerators());
mergeMultibinders(multibinders, module.getMultibinders());
}
return new SimpleModule(bindings, bindingTransformers, bindingGenerators, multibinders);
}
2.2override(List< Module> modules)方法
连续地用后面的下一个模块覆盖每个给定模块,并返回累积结果。
public static Module override(List<Module> modules) {
return modules.stream().reduce(Module.empty(), Modules::override);
}
2.3ignoreScopes(Module from)方法
创建一个模块,将所有trie节点合并为一个并放置在根节点上。基本上,任何作用域都被忽略。这对于某些测试很有用。
public static Module ignoreScopes(Module from) {
Map<Key<?>, Set<Binding<?>>> bindings = new HashMap<>();
Map<Key<?>, Scope[]> scopes = new HashMap<>();
from.getBindings().dfs(UNSCOPED, (scope, localBindings) ->
localBindings.forEach((k, b) -> {
bindings.merge(k, b, ($, $2) -> {
Scope[] alreadyThere = scopes.get(k);
String where = alreadyThere.length == 0 ? "in root" : "in scope " + getScopeDisplayString(alreadyThere);
throw new IllegalStateException("Duplicate key " + k + ", already defined " + where + " and in scope " + getScopeDisplayString(scope));
});
scopes.put(k, scope);
}));
return new SimpleModule(Trie.leaf(bindings), from.getBindingTransformers(), from.getBindingGenerators(), from.getMultibinders());
}
3.AbstractModule类
此类是围绕ModuleBuilder类的抽象模块包装器。为了便于转换,它提供了类似于其他一些DI框架的功能。
此类是实现Module接口的类。
构造方法如下:
public AbstractModule() {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
StackTraceElement found = null;
Class<?> cls = getClass();
for (int i = 2; i < trace.length; i++) {
StackTraceElement element = trace[i];
try {
String className = element.getClassName();
Class<?> traceCls = Class.forName(className);
if (!traceCls.isAssignableFrom(cls) && !className.startsWith("sun.reflect") && !className.startsWith("java.lang")) {
found = element;
break;
}
} catch (ClassNotFoundException ignored) {
break;
}
}
this.location = found;
this.builder = new ModuleBuilderImpl<>(getName(), location);
}
4.ModuleBuilder类
此接口用于限制DSL。基本上,它不允许调用下面未列出的ModuleBuilder0中的任何方法,而事先不调bind中的bind(…)}。
4.1install方法
将给定模块中的所有绑定、转换器、生成器和多绑定器添加到此模块。这就像您直接在本模块中定义所有这些一样。
ModuleBuilder install(Collection<Module> modules);
default ModuleBuilder install(Module... modules) {
return install(Arrays.asList(modules));
}
4.2scan方法
扫描类层次结构,然后将每个类中的提供程序作为模块安装,
这样导出就不会在类之间发生干扰。Class参数用于指定从层次结构中的哪个类开始。
ModuleBuilder scan(@NotNull Class<?> containerClass, @Nullable Object container);
//与scan相同,starting类默认为对象实例的类。
default ModuleBuilder scan(Object container) {
return scan(container.getClass(), container);
}
//和scan相同,但只扫描静态方法,不依赖于类的实例。
//非静态带注释的方法是IllegalStateException prohibited。
default ModuleBuilder scan(Class<?> container) {
return scan(container, null);
}
5.DefaultModule类
此模块提供一组默认生成器,也是实现Module接口的。
第一个尝试通过搜索Inject构造函数为任何缺少的键生成绑定。
第二个生成任意Key SomeType某个类型的实例。
其目的是从模板化提供程序中的泛型中获取具体化类型。
最后两个为InstanceProvider和InstanceInjector请求生成适当的实例。
public static class InstanceProviderImpl<T> implements InstanceProvider<T> {
private final Key<T> key;
private final CompiledBinding<T> compiledBinding;
private final AtomicReferenceArray[] scopedInstances;
private final int synchronizedScope;
public InstanceProviderImpl(Key<T> key, CompiledBinding<T> compiledBinding, AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
this.key = key;
this.compiledBinding = compiledBinding;
this.scopedInstances = scopedInstances;
this.synchronizedScope = synchronizedScope;
}
@Override
public Key<T> key() {
return key;
}
@Override
public T get() {
return compiledBinding.getInstance(scopedInstances, synchronizedScope);
}
@Override
public String toString() {
return "InstanceProvider<" + key.getDisplayString() + ">";
}
}
6.SimpleModule类
SimpleModule类也是implements Module接口。此类是为了实现简单形式模块。上面介绍的Modules类中有一个combine方法,就是把多个Module合并成一个SimpleModule。它的各项属性和Modules是一致的。
构造方法如下:
public SimpleModule(Trie<Scope, Map<Key<?>, Set<Binding<?>>>> bindings,
Map<KeyPattern<?>, Set<BindingTransformer<?>>> transformers,
Map<KeyPattern<?>, Set<BindingGenerator<?>>> generators,
Map<Key<?>, Multibinder<?>> multibinders) {
this.bindings = bindings;
this.transformers = transformers;
this.generators = generators;
this.multibinders = multibinders;
}
此类重写了getBindings(),getBindingTransformers(),getBindingGenerators(),getMultibinders()这四个方法,代码如下:
@Override
public Trie<Scope, Map<Key<?>, Set<Binding<?>>>> getBindings() {
return bindings;
}
@Override
public Map<KeyPattern<?>, Set<BindingTransformer<?>>> getBindingTransformers() {
return transformers;
}
@Override
public Map<KeyPattern<?>, Set<BindingGenerator<?>>> getBindingGenerators() {
return generators;
}
@Override
public Map<Key<?>, Multibinder<?>> getMultibinders() {
return multibinders;
}
7.OptionalGeneratorModule类
此类是扩展模块。它生成任意类型T的可选T绑定,如果未绑定T绑定或包含T实例,则生成的可选为空。OptionalGeneratorModule类继承AbstractModule类,重写了configure()方法:
protected void configure() {
generate(Optional.class, (bindings, scope, key) -> {
Binding<?> binding = bindings.get(key.getTypeParameter(0));
return binding != null ?
binding.mapInstance(Optional::of) :
Binding.toInstance(Optional.empty());
});
}
四、总结
本次分析的代码是module包中的七个类,这是module包中比较重要的几个类。ActiveJ中的module可提供简单而强大的DSL提供了自动图转换、生成和验证的机制。而且可以生成绑定,是非常有用的。