1

私は現在、サービスの実装者が定型的な統合コードではなくサービス固有のロジックに集中できるように、プラットフォーム内のサービスの青写真を提供するフレームワーク コードをいくつか書いています。依存性注入は Guice を介して行われます。

ブループリントには 2 種類の論理コンポーネントがあります。

  1. サービスを外部の世界と統合する唯一無二の統合コンポーネント (メッセージングミドルウェアなど)
  2. 1-n ビジネス ロジック コンポーネント

各ロジック コンポーネントは、統合コンポーネントに依存します。

統合コンポーネントは、すべてのロジック コンポーネントに依存します。

これはフレームワーク コードであるため、フレームワークは具体的な詳細を認識しないため、依存関係を静的に宣言して依存関係グラフを形成することはできません。サービスの実装者にこれを行わせることは避けたいと思います。これは、サービスの実装者が自分自身を繰り返すことを意味するためです (n 個のビジネス ロジック モジュールがあると宣言するだけで、この循環依存関係があることを意味します)。

私の質問は、サービスの実装者にその定型コードを書かせることなく、これを機能させるためにどのようなアプローチを取ることができるかということです.

この質問の範囲外のさまざまな理由により、各ビジネスロジックコンポーネントは PrivateModule でなければならないため、ここではマルチバインディングを使用できないことに注意してください。

どこを説明するための不自然な例

  1. ビジネス ロジック = ModuleA、ModuleB、ModuleC
  2. 統合によって提供される依存関係 = Wrapper
  3. ビジネス ロジックへの統合の依存関係は、ラッパーに何かを追加する各ロジック モジュールによってモデル化されます。

この例は、変更することで機能させることができます

@Provides @Exposed @Named("result")
public String go(Container in) {
    return in.format();
}

@Provides @Exposed @Named("result")
public String go(@Named("a") Container in, @Named("b") Container in2, @Named("c") Container in3) {
    return in.format();
}

つまり、実際に循環依存関係を作成します。

import com.google.inject.Exposed;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

import java.util.ArrayList;
import java.util.List;

public class GuiceCircularDependencyTest {

    public static void main(String[] args) {
        Injector in = Guice.createInjector(new Owner());
        String result = in.getInstance(Key.get(String.class, Names.named("result")));
        System.out.println("Result is: " + result);
    }

    public static class Owner extends PrivateModule {
        @Override
        protected void configure() {
            bind(Container.class).in(Singleton.class);
            install(new Integration());
            install(new ModuleA());
            install(new ModuleB());
            install(new ModuleC());
            expose(String.class).annotatedWith(Names.named("result"));
        }
    }

    public static class ModuleA extends PrivateModule {

        @Override
        protected void configure() {

        }

        @Provides @Exposed @Named("a")
        public Container go(Container in, Wrapper prefix) {
            in.add(prefix + "A");
            return in;
        }
    }

    public static class ModuleB extends PrivateModule {

        @Override
        protected void configure() {

        }

        @Provides @Exposed @Named("b")
        public Container go(Container in, Wrapper prefix) {
            in.add(prefix + "B");
            return in;
        }
    }

    public static class ModuleC extends PrivateModule {

        @Override
        protected void configure() {

        }

        @Provides @Exposed @Named("c")
        public Container go(Container in, Wrapper prefix) {
            in.add(prefix + "C");
            return in;
        }
    }

    public static class Integration extends PrivateModule {
        @Override
        protected void configure() {
            bind(Wrapper.class).toInstance(new Wrapper("Module"));
            expose(Wrapper.class);
        }

        @Provides @Exposed @Named("result")
        public String go(Container in) {
            return in.format();
        }
    }

    public static class Container {
        private List<String> strings = new ArrayList<>();

        public void add(String string) {
            strings.add(string);
        }

        public String format() {
            return strings.toString();
        }
    }

    public static class Wrapper {
        private final String prefix;

        public Wrapper(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public String toString() {
            return prefix;
        }
    }
}
4

1 に答える 1

0

Multibinderをプライベート モジュール間で共有できるようにする 1 つの回避策は、単に をインストールし、公開されたキーを にバインドするPrivateModule実装で をラップすることです。AbstractModulePrivateModuleMultibinder

import com.google.inject.AbstractModule;
import com.google.inject.Exposed;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.PrivateModule;
import com.google.inject.Provides;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

import java.util.Set;

public class GuiceCircularDependencyTest {

    public static void main(String[] args) {
        Injector in = Guice.createInjector(new Owner());
        String result = in.getInstance(Key.get(String.class, Names.named("result")));
        System.out.println("Result is: " + result);
    }

    public static class Owner extends PrivateModule {
        @Override
        protected void configure() {
            Multibinder<String> multi = Multibinder.newSetBinder(binder(), String.class);
            install(new Integration());
            install(new ModuleWrapper<>(new ModuleA(), multi));
            install(new ModuleWrapper<>(new ModuleB(), multi));
            install(new ModuleWrapper<>(new ModuleC(), multi));
            expose(String.class).annotatedWith(Names.named("result"));
        }
    }

    public static class ModuleWrapper<T> extends AbstractModule {
        private final WrappablePrivateModule<T> inner;
        private final Multibinder<T> multi;

        public ModuleWrapper(WrappablePrivateModule<T> inner,
                             Multibinder<T> multi) {
            this.inner = inner;
            this.multi = multi;
        }

        @Override
        protected void configure() {
            install(inner);
            multi.addBinding().to(inner.getExposedKey());
        }
    }

    public static abstract class WrappablePrivateModule<T> extends PrivateModule {

        @Override
        protected void configure() {

        }

        public abstract Key<T> getExposedKey();
    }

    public static class ModuleA extends WrappablePrivateModule<String> {

        private static final String SUFFIX = "A";

        @Override
        public Key<String> getExposedKey() {
            return Key.get(String.class, Names.named(SUFFIX));
        }

        @Provides @Exposed @Named(SUFFIX)
        public String expose(Wrapper prefix) {
            return prefix + SUFFIX;
        }
    }

    public static class ModuleB extends WrappablePrivateModule<String> {

        private static final String SUFFIX = "B";

        @Override
        public Key<String> getExposedKey() {
            return Key.get(String.class, Names.named(SUFFIX));
        }

        @Provides @Exposed @Named(SUFFIX)
        public String expose(Wrapper prefix) {
            return prefix + SUFFIX;
        }
    }

    public static class ModuleC extends WrappablePrivateModule<String> {

        private static final String SUFFIX = "C";

        @Override
        public Key<String> getExposedKey() {
            return Key.get(String.class, Names.named(SUFFIX));
        }

        @Provides @Exposed @Named(SUFFIX)
        public String expose(Wrapper prefix) {
            return prefix + SUFFIX;
        }
    }

    public static class Integration extends PrivateModule {
        @Override
        protected void configure() {
            bind(Wrapper.class).toInstance(new Wrapper("Module"));
            expose(Wrapper.class);
        }

        @Provides @Exposed @Named("result")
        public String go(Set<String> in) {
            return in.toString();
        }
    }

    public static class Wrapper {
        private final String prefix;

        public Wrapper(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public String toString() {
            return prefix;
        }
    }
}
于 2013-01-11T11:16:22.977 に答える