
2021SC@SDUSC
一、Inject概述ActiveJ Inject是一个轻量级的、强大的依赖注入库,具有极强的性能,没有第三方的依赖性。 它对多线程友好,功能丰富,可以夸耀的是,它的启动时间和运行时间非常快,大大超过了Spring DI或Guice。 ActiveJ Inject是ActiveJ技术之一,但它对第三方的依赖性很小,可以作为一个独立的组件使用。
ActiveJ Inject特点:
依赖性注入: 重定义
利用各种强大的工具享受开发。 ActiveJ Inject简化了开发、调试、重构和重用你的代码,没有限制和开销。
注释处理被分离到一个标准插件中,该插件默认使用,并允许生成缺失的依赖。 然而,如果你需要实现复杂的业务逻辑,你可以使用 ActiveJ Inject DSL(DSL即Domain Specific Language,中文翻译为领域特定语言),甚至可以创建自己的注解处理插件。
DSL提供了对编程式绑定生成的支持,对依赖关系图的反省,转换,自动生成缺失的绑定,以及对已经存在的绑定的修改。通过这种方式,您可以使用Java的全部功能,在运行时直接根据运行时信息和设置,通过算法创建复杂的绑定和依赖关系图。
Module cookbook = new AbstractModule() {
@Provides
Sugar sugar() { return new Sugar("Sugar", 10.f); }
@Provides
Butter butter() { return new Butter("Butter", 20.0f); }
@Provides
Flour flour() { return new Flour("Flour", 100.0f); }
@Provides
Pastry pastry(Sugar sugar, Butter butter, Flour flour) {
return new Pastry(sugar, butter, flour);
}
@Provides
cookie cookie(Pastry pastry) {
return new cookie(pastry);
}
};
Injector.of(cookbook).getInstance(cookie.class);
二、core-inject结构
源代码中core-inject结构如下:
如上图所示,io.activej.inject下属annotation、binding、impl、module、util这五个包,而且还有Inject、InstanceInjector、InstanceProvider、Key、KeyPattern、Qualifiers、ResourceLocator、Scope这8个单独的类。这一次的博客就是读一下这8个单独的类的功能。
三、代码解读3.1 Injector
Injector是ActiveJ Injector的主要工作部件。
它存储绑定图的trie和已生成的单例缓存。
每个注入器与每个Key正好零个或一个实例关联。
Injector使用trie根目录下的绑定图递归创建并存储与某些Key关联的对象实例。trie的分支用于enter scopes。
Injector为组件 ,以后序方式递归地遍历依赖关系图,并首先创建它们,提供所有需要的依赖关系(注入)。
绑定是默认的单子–如果一个实例被创建过一次,就不会再从头开始创建。 如果 ,它被其他绑定所需要,Injector将从缓存中获取它。 你不需要为它应用任何额外的注释。
为了提供请求的密钥,Injector递归地创建它的所有依赖,如果在它的范围内没有找到绑定,则退回到其父范围的Injector。
下面看一下Injector类里面的方法:
构造方法:
private Injector(@Nullable Injector parent, TriescopeDataTree) { this.parent = parent; this.scopeDataTree = scopeDataTree; ScopeLocalData data = scopeDataTree.get(); this.localSlotMapping = data.slotMapping; this.localCompiledBindings = data.compiledBindings; AtomicReferenceArray[] scopeCaches = parent == null ? new AtomicReferenceArray[1] : Arrays.copyOf(parent.scopeCaches, parent.scopeCaches.length + 1); AtomicReferenceArray localCache = new AtomicReferenceArray(data.slots); localCache.set(0, this); scopeCaches[scopeCaches.length - 1] = localCache; this.scopeCaches = scopeCaches; }
useSpecializer方法:
此方法启用编译绑定的专门化。依赖于ActiveJ Specializer模块。
public static void useSpecializer() {
try {
Class> aClass = Class.forName("io.activej.specializer.Utils$InjectorSpecializer");
Constructor> constructor = aClass.getConstructor();
constructor.setAccessible(true);
Object specializerInstance = constructor.newInstance();
Function, CompiledBinding>> specializer = (Function, CompiledBinding>>) specializerInstance;
Injector.bytecodePostprocessorFactory = () -> specializer;
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException | ClassNotFoundException | InstantiationException e) {
throw new IllegalStateException("Can not access ActiveJ Specializer", e);
}
}
几个of方法:
此构造函数将给定的模块(以及DefaultModule)组合在一起,然后compile(Injector,Module)编译它们。
public static Injector of(Module... modules) {
return compile(null, Modules.combine(Modules.combine(modules), new DefaultModule()));
}
public static Injector of(@Nullable Injector parent, Module... modules) {
return compile(parent, Modules.combine(Modules.combine(modules), new DefaultModule()));
}
public static Injector of(@NotNull Trie, Binding>>> bindings) {
return compile(null, UNSCOPED,
bindings.map(map -> map.entrySet().stream().collect(toMap(Entry::getKey, entry -> singleton(entry.getValue())))),
errorOnDuplicate(),
identity(),
refusing());
}
compile方法:
我认为这个编译方法还是比较重要的。它是最成熟的编译方法,允许您创建任何配置的Injector。需要注意的是,任何Injector都会设置一个Injector key绑定,以提供其自身。下面介绍一下这些key:
public static Injector compile(@Nullable Injector parent, Scope[] scope, @NotNull Trie, Set >>> bindingsMultimap, @NotNull Multibinder> multibinder, @NotNull BindingTransformer> transformer, @NotNull BindingGenerator> generator) { Trie , Binding>>> bindings = Preprocessor.reduce(bindingsMultimap, multibinder, transformer, generator); Set > known = new HashSet<>(); known.add(Key.of(Injector.class)); // injector is hardcoded in and will always be present if (parent != null) { known.addAll(parent.localCompiledBindings.keySet()); } Preprocessor.check(known, bindings); Trie scopeDataTree = compileBindingsTrie( parent != null ? parent.scopeCaches.length : 0, scope, bindings, parent != null ? parent.localCompiledBindings : emptyMap() ); return new Injector(parent, scopeDataTree); }
Injector中还有一些其他方法,以上是我挑出的我认为比较重要的几个方法。
3.2 InstanceInjector接口
这是一个函数,可以将实例注入{@link io.activej.inject.annotation.inject}
某些已存在对象的字段和方法。
这就是所谓的“post-injections(后注入)”,因为这种注入不是对象创建的一部分。
它有一个io.activej.inject.module.DefaultModule default generator,只能通过依赖它然后从Injector请求它来获得。
源代码如下:
public interface InstanceInjector{ Key key(); void injectInto(T existingInstance); }
它可以将实例注入到 Inject 一些已经存在的对象的字段和方法。 看一下这个简单的例子。
@Inject
String message;
@Provides
String message() {
return "Hello, world!";
}
@Override
protected void run() {
System.out.println(message);
}
public static void main(String[] args) throws Exception {
Launcher launcher = new InstanceInjectorExample();
launcher.launch(args);
}
可能会有些疑惑的问题是Launcher ,实际上如何知道消息变量包含 “Hello, world!” 字符串,以便在 run() 方法中显示它? 在这里,在DI的内部工作中, InstanceInjector 实际上是给launcher提供了帮助。
3.3 InstanceProvider接口
与其他DI框架不同,提供程序只是{Injector.getInstance}的一个版本,带有一个烘焙键。
如果您需要一个每次返回一个新对象的函数,那么您需要使绑定{@link Transient}。
它存在的主要原因是它的绑定有一个{io.activej.inject.module.DefaultModule default generator},因此{io.activej.inject.annotation.provider methods}等可以流畅地请求它。
此外,它还可以用于延迟依赖循环解析。
public interface InstanceProvider{ Key key(); T get(); }
3.4 ResourceLocator接口
作为资源定位器,其中一些方法也是getInstance方法的改写。
public interface ResourceLocator {
@NotNull T getInstance(@NotNull Key key);
@NotNull T getInstance(@NotNull Class type);
@Nullable T getInstanceOrNull(@NotNull Key key);
@Nullable T getInstanceOrNull(@NotNull Class type);
T getInstanceOr(@NotNull Key key, T defaultValue);
T getInstanceOr(@NotNull Class type, T defaultValue);
}
3.5 Qualifiers
此类包含用于验证和创建用作限定符的对象的实用程序方法。
限定符用作附加标记,以区分具有相同类型的不同Key。
public final class Qualifiers {
public static Object uniqueQualifier() {
return new UniqueQualifierImpl();
}
public static Object uniqueQualifier(@Nullable Object qualifier) {
return qualifier instanceof UniqueQualifierImpl ? qualifier : new UniqueQualifierImpl(qualifier);
}
public static boolean isUnique(@Nullable Object qualifier) {
return qualifier instanceof UniqueQualifierImpl;
}
}
3.6 Key
Key定义绑定的标识。在任何DI中,Key通常是一种对象类型以及一些可选标记,用于区分使对象具有相同类型的绑定。
在ActiveJ Inject中,Key也是一个类型标记特殊的抽象类,可以用Java中最短的语法存储类型信息。
例如,要创建一个key的类型:Map
public Key() {
this.type = getTypeParameter();
this.qualifier = null;
}
public Key(@Nullable Object qualifier) {
this.type = getTypeParameter();
this.qualifier = qualifier;
}
Key(@NotNull Type type, @Nullable Object qualifier) {
this.type = type;
this.qualifier = qualifier;
}
qualified方法:
返回具有相同类型的新键,但限定符已替换为给定的键
public Keyqualified(Object qualifier) { return new KeyImpl<>(type, qualifier); }
getRawType()方法:
{Types#getRawType(Type)}(key.getType())的快捷方式。
还将结果强制转换为正确参数化的类。
public @NotNull ClassgetRawType() { return (Class ) Types.getRawType(type); }
getDisplayString方法:
如果此key具有限定符,则返回具有显示字符串格式(包名称已剥离)和前置限定符显示字符串的基础类型。
public String getDisplayString() {
return (qualifier != null ? Utils.getDisplayString(qualifier) + " " : "") + ReflectionUtils.getDisplayName(type);
}
3.7 KeyPattern
匹配依赖项注入Key的模式
如果Key#getType()Key的类型可分配给此模式的类型,并且此模式的限定符为null或匹配 Key#getQualifier()Key的限定符,则Key匹配。
构造方法:
public KeyPattern() {
this.type = getTypeParameter();
this.qualifier = null;
}
public KeyPattern(Object qualifier) {
this.type = getTypeParameter();
this.qualifier = predicateOf(qualifier);
}
public KeyPattern(Predicate> qualifier) {
this.type = getTypeParameter();
this.qualifier = qualifier;
}
KeyPattern(@NotNull Type type, Predicate> qualifier) {
this.type = type;
this.qualifier = qualifier;
}
3.8 Scope
Scope 给我们提供了 “local singletons”,它的寿命与scope本身一样长。 ActiveJ Inject的作用域与其他DI库有些不同。
构造方法:
private Scope(@NotNull Class extends Annotation> annotationType, boolean threadsafe) {
this.annotationType = annotationType;
this.threadsafe = threadsafe;
}
of方法:
从标记(或无状态)注释创建范围,仅由其类标识。
public static Scope of(Class extends Annotation> annotationType) {
checkArgument(isMarker(annotationType), "Scope by annotation type only accepts marker annotations with no arguments");
ScopeAnnotation scopeAnnotation = annotationType.getAnnotation(ScopeAnnotation.class);
checkArgument(scopeAnnotation != null, "only annotations annotated with @ScopeAnnotation meta-annotation are allowed");
return new Scope(annotationType, scopeAnnotation.threadsafe());
}
从真实(或其自定义代理impl)注释实例创建范围。
public static Scope of(Annotation annotation) {
return of(annotation.annotationType());
}
四、总结
本次解读的代码时core-inject中独立于几个包之外的类或接口,有些是其他类的依赖,有些是需要在其他类中实现的接口,都是比较重要的。