이 솔루션을 사용할 수는 있지만 약간 다른 제안을하고 싶습니다.
특히 깊은 개체 구조를 트래버스하기 때문에 Visitor 패턴의 작업과 비슷합니다. 또한 설명하는 내용은 2 단계 인젝터를 호출하는 것으로 보입니다. 피벗로 만든 계층 구조에서 필요한 요소를 주입 할 수있는 "부트 스트랩"단계 (그러나 피벗 생성 요소는 주입 할 수 없음)와 두 번째 단계 그것은 앱에서 사용하는 실제 인젝터입니다 (아무 것도 주입 할 수 있음).
나는이 기본 패턴을 제안합니다. 방문객이 계층 구조를 가로 지르는 방문자를 만들어야합니다. 필요로하는 것들을 주입하고 다른 곳에 주입해야하는 것들을 기록합니다. 그런 다음 모든 것이 완료되면 Injector.createChildInjector
을 사용하여 원래 Injector
의 항목을 주입 할 수있는 새로운 Injector
을 만들고 피벗 생성 계층 구조의 항목을 만듭니다.
public interface InjectionVisitor {
void needsInjection(Object obj);
<T> void makeInjectable(Key<T> key, T instance);
}
그런 다음 모든 피벗 만든 요소에 대한 인터페이스를 정의 :
먼저이 계층 구조에 모든 것을 칠 수 방문자 정의 당신은이 인터페이스를 구현하는 것
public interface InjectionVisitable {
void acceptInjectionVisitor(InjectionVisitor visitor);
}
당신의 피벗 생성 클래스 (FooContainer
클래스의이 코드로 가정) :
public void acceptInjectionVisitor(InjectionVisitor visitor) {
visitor.needsInjection(this);
visitor.makeInjectable(Key.get(FooContainer.class), this);
for (InjectionVisitable child : children) {
child.acceptInjectionVisitor(visitor);
}
}
처음 두 문장은 선택 사항입니다. 피벗 계층 구조의 일부 객체는 주입이 필요하지 않을 수도 있으며 나중에 주입 가능성을 원하지 않을 수도 있습니다.
이제
visitor.makeInjectable(Key.get(Foo.class, Names.named(this.getName())), this);
, 어떻게 InjectionVisitor
을 구현합니까 : - 또한, Key
의 사용에 주목이 당신이 원하는 경우 일부 클래스는 당신이 뭔가를 할 수있는 특정 주석을 주사 할 것을 의미?
이
public class InjectionVisitorImpl implements InjectionVisitor {
private static class BindRecord<T> {
Key<T> key;
T value;
}
private final List<BindRecord<?>> bindings = new ArrayList<BindRecord<?>>();
private final Injector injector;
public InjectionVisitorImpl(Injector injector) {
this.injector = injector;
}
public void needsInjection(Object obj) {
injector.injectMemebers(obj);
}
public <T> void makeInjectable(Key<T> key, T instance) {
BindRecord<T> record = new BindRecord<T>();
record.key = key;
record.value = instance;
bindings.add(record);
}
public Injector createFullInjector(final Module otherModules...) {
return injector.createChildInjector(new AbstractModule() {
protected void configure() {
for (Module m : otherModules) { install(m); }
for (BindRecord<?> record : bindings) { handleBinding(record); }
}
private <T> handleBinding(BindRecord<T> record) {
bind(record.key).toInstance(record.value);
}
});
}
}
당신은 다음과 같이 main
방법이 사용 방법은 다음과 같습니다
PivotHierarchyTopElement top = ...; // whatever you need to do to make that
Injector firstStageInjector = Guice.createInjector(
// here put all the modules needed to define bindings for stuff injected into the
// pivot hierarchy. However, don't put anything for stuff that needs pivot
// created things injected into it.
);
InjectionVisitorImpl visitor = new InjectionVisitorImpl(firstStageInjector);
top.acceptInjectionVisitor(visitor);
Injector fullInjector = visitor.createFullInjector(
// here put all your other modules, including stuff that needs pivot-created things
// injected into it.
);
RealMainClass realMain = fullInjector.getInstance(RealMainClass.class);
realMain.doWhatever();
주 createChildInjector
작품은 당신이 물건에 바인딩 어떤 @Singleton
일이있는 경우 피벗 계층 구조에 주입되도록하는 방식이 , 실제 인젝터에서 동일한 인스턴스를 주입하게됩니다. firstStageInjector
이 주사를 처리 할 수있는 한 fullInjector
은 firstStageInjector
에 인젝션을 위임합니다.
추가 편집 : InjectionImpl
을 수정하여 makeInjectable
이라는 소스 코드의 위치를 기록하도록 수정하는 것이 좋습니다 (Guice의 깊은 마법을 탐구하려는 경우). 그러면 Guice에서 실수로 코드가 방문자에게 동일한 키에 바인딩 된 두 가지 점에 대해 알릴 때 더 나은 오류 메시지를 얻을 수 있습니다. 당신은 중첩 된 필드를 주입하는 MembersInjectors를 주입 할 수
private <T> handleBinding(BindRecord<T> record) {
binder().withSource(record.stackTraceElem).bind(record.key).toInstance(record.value);
}
와우! 이것은 매우 철저하고 정교한 대답입니다. 나는 그것을 많이 고맙다. 그리고 Guice 마법을 공유 주셔서 감사합니다 :) 나는 제안 된 접근 방식을 시도합니다. (답변은 내일 허용됩니다.) – dragonfly