SpringBootチュートリアルシリーズは、自動設定オプションが有効になります

191214-SpringBootチュートリアルシリーズは、自動設定オプションが有効になります


その長い春シリーズボーエンを書いた後、私は問題を発見し、記事のすべての前に一つのことを中心に発効させている。そして、何の反対はそれがありませんか?

私たちは、それができる知っている@ConditionOnXxx、このようなシナリオがあることが想定され、クラスをロードすることが可能かどうかを決定するように構成すること

  • プリント抽象インタフェース、例えばデシベルDbPrintに出力するコンソールConsolePrint、FilePrintファイル出力への出力として複数の実装、
  • 私たちは実際に、ユーザの選択に応じて、特定の実装の使用いずれかを使用する場合

上記の場合には、もちろん、また、使用することができます@ConditionOnExpression注入法のよりエレガントな選択肢を推奨するだけでなく、実装しますImportSelector

I.設定オプション

2.1.2.RELEASEに使用されるこの記事の春ブーツバージョン

次に、我々は先に概説ImportSelectorケースを達成するために使用します

インターフェイスクラス、実装クラス3

public interface IPrint {
    void print();
}

public class ConsolePrint implements IPrint {
    @Override
    public void print() {
        System.out.println("控制台输出");
    }
}

public class DbPrint implements IPrint {
    @Override
    public void print() {
        System.out.println("db print");
    }
}

public class FilePrint implements IPrint {
    @Override
    public void print() {
        System.out.println("file print");
    }
}

2.クラス

選択するために、当社のカスタム注釈を通じて、主に実装クラスでは、PrintConfigSelector継承ImportSelectorをカスタマイズする3つの特定の負荷の設定クラスのどの

public class PrintConfigSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        AnnotationAttributes attributes =
                AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(PrintSelector.class.getName()));

        Class config = attributes.getClass("value");
        return new String[]{config.getName()};
    }

    public static class ConsoleConfiguration {
        @Bean
        public ConsolePrint consolePrint() {
            return new ConsolePrint();
        }
    }

    public static class FileConfiguration {
        @Bean
        public FilePrint filePrint() {
            return new FilePrint();
        }
    }

    public static class DbConfiguration {
        @Bean
        public DbPrint dbPrint() {
            return new DbPrint();
        }
    }
}

3. PrintSelectorコメント

主に注射のために使用PrintConfigSelectorを有効にするために使用されるプロパティの値は、コンフィギュレーションの特定の選択をするという効果を取るために、デフォルトの登録ConsolePrint

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(PrintConfigSelector.class)
public @interface PrintSelector {
    Class<?> value() default PrintConfigSelector.ConsoleConfiguration.class;
}

4.テスト

//@PrintSelector(PrintConfigSelector.FileConfiguration .class)
//@PrintSelector(PrintConfigSelector.DbConfiguration .class)
@PrintSelector
@SpringBootApplication
public class Application {

    public Application(IPrint print) {
        print.print();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

実際のテストでは、変更することにより、@PrintSelector異なる実装クラス値を出力切り替え

II。拡張

上記のアプローチにより達成実用的な場合表示するながらImportSelectorジェスチャーの使用を特定のコンフィギュレーションクラスの効果を選択するために使用することができます。しかし、知識の他の点があり、何を指摘する必要があります

豆のロード・シーケンスによってImportSelectorは、それが何であるかの依存を強制せずに、コンフィギュレーション・クラスを選択しましたか?

1.デモ・デザイン

デフォルトの負荷条件では、以下の豆袋のロード・シーケンスは、の名前に従ってソートされた、のは、豆のロード順序をテストするためのケースを作成してみましょう

  • 同じパッケージの下で、6つのBeanを作成:Demo0DemoADemoBDemoCDemoDDemoE
  • これはDemo0 DemoE一般的な豆です
  • ここでDemoADemoCコンフィギュレーション・クラスによって登録された1
  • ここでDemoBDemoD2種類のコンフィギュレーション・レジスタがあります

次のように特定のコード

@Component
public class Demo0 {
    private String name = "demo0";
    public Demo0() {
        System.out.println(name);
    }
}
public class DemoA {
    private String name = "demoA";
    public DemoA() {
        System.out.println(name);
    }
}
public class DemoB {
    private String name = "demoB";
    public DemoB() {
        System.out.println(name);
    }
}
public class DemoC {
    private String name = "demoC";
    public DemoC() {
        System.out.println(name);
    }
}
public class DemoD {
    private String name = "demoD";
    public DemoD() {
        System.out.println(name);
    }
}
@Component
public class DemoE {
    private String name = "demoE";
    public DemoE() {
        System.out.println(name);
    }
}

対応する構成タイプ

public class ToSelectorAutoConfig1 {
    @Bean
    public DemoA demoA() {
        return new DemoA();
    }
    @Bean
    public DemoC demoC() {
        return new DemoC();
    }
}

public class ToSelectorAutoConfig2 {
    @Bean
    public DemoB demoB() {
        return new DemoB();
    }
    @Bean
    public DemoD demoD() {
        return new DemoD();
    }
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ConfigSelector.class)
public @interface DemoSelector {
    String value() default "all";
}
public class ConfigSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        AnnotationAttributes attributes =
                AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(DemoSelector.class.getName()));

        String config = attributes.getString("value");
        if ("config1".equalsIgnoreCase(config)) {
            return new String[]{ToSelectorAutoConfig1.class.getName()};
        } else if ("config2".equalsIgnoreCase(config)) {
            return new String[]{ToSelectorAutoConfig2.class.getName()};
        } else {
            return new String[]{ToSelectorAutoConfig2.class.getName(), ToSelectorAutoConfig1.class.getName()};
        }
    }
}

ノートConfigSelector、デフォルトのDemoSelector注釈は、2つの構成のクラスを含む全負荷、返された配列を表すConfgi1の前にCONFIG2

2.実際のロード順序

少し開始するクラスの前を変更し、プラス@DemoSelectorのコメント

PrintSelector(PrintConfigSelector.FileConfiguration .class)
//@PrintSelector(PrintConfigSelector.DbConfiguration .class)
//@PrintSelector
@DemoSelector
@SpringBootApplication
public class Application {
    public Application(IPrint print) {
        print.print();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

上記の場合、我々は、6つのBeanがデフォルトローディングシーケンスを出力判定結果に基づいて、ロードされる定義します

出力結果から、オブジェクトは通常Beanをロードし、次に豆とCONFIG2定義ロード、最後はCONFIG1ビーン定義されています。

次に、それは、Beanクラスで指定された設定をロードする順序に配列戻りを記述することができ、オブジェクトのアレイは、最終的な出力はCONFIG1 Beanが最初にロードされた定義されている場合ImportSelectorを順次、2つのクラスを配置戻さ調整します

結果の出力は、我々の推測を確認します

オーダーは私たちよりも優れている場合は、通常のBeanオブジェクトのロード中に豆のデフォルトの初期化シーケンスの最後の質問、ImportSelector豆も登録すること?

  • 出力からケースのようですが、この場合には十分ではなく、完全にこの見解を検証していない、あなたは(実際にはこれがあるが)まだソースコード解析を通じてに持っている、まさにこの点を知りたいです

ご注意ください

上面的分析只是考虑默认的 bean 初始化顺序,我们依然是可以通过构造方法引入的方式或者@DependOn注解来强制指定 bean 的初始化顺序的

小结

最后小结一下 ImportSelector 的用法

  • 实现接口,返回 String 数组,数组成员为配置类的全路径
  • 在配置类中定义 bean
  • 返回数组中配置类的顺序,指定了配置类中 bean 的默认加载顺序
  • 通过@Import直接来使ImportSelector接口生效

此外还有一个类似的接口DeferredImportSelector,区别在于实现DeferredImportSelector的类优先级会低与直接实现ImportSelector的类,而且可以通过@Order决定优先级;优先级越高的越先被调用执行

II. 其他

0. 项目

1. 一灰灰 Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现 bug 或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

一灰灰blog

おすすめ

転載: www.cnblogs.com/yihuihui/p/12045810.html