ActiveJ学习心得——inject(4)

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提供了自动图转换、生成和验证的机制。而且可以生成绑定,是非常有用的。

猜你喜欢

转载自blog.csdn.net/zth_idea/article/details/121024205