[Spring Boot]3.Spring Boot自動構成を実現するための基礎

13822 ワード

最初の記事では、Spring Bootの起動プロセスについて説明し、Spring Bootのコアコンピテンシーである自動構成について説明します.この能力もSpring Bootの非常に大きなセールスポイントの一つです.この能力に対して、多くの学生が好奇心を持っていると信じています.Spring Bootはどのようにそれを実現していますか.
しかし,Spring Bootがどのように自動構成を実現するかを詳細に探る前に,まず問題の出所を明確にし,現在のSpringフレームワークで提供されている関連能力を理解する必要がある.
リード
問題は何ですか.
Springの複雑なプロファイルは、多くの開発者に微語を持たせてきましたが、ビジネスの複雑さが高まるにつれて、これも避けられないことです.
簡単なWebアプリケーションを作成するにしても、構成する必要があるものは塊であり、このプロセスは複雑ではありませんが、煩雑で、エラーが発生しやすいです.だから賢い開発者は、MavenのArchetype作成や、各社内の足場小道具など、この問題を解決する方法をたくさん考えました.しかし、これらの案には、メンテナンスが不便で、カスタマイズが悪いなど、いつもこのような問題があります.
クラウドコンピューティング、フレックスコンピューティング、マイクロサービスがますます普及している今日、必要に応じて簡単に導入できる自動構成が必要です.そのためSpring Bootアプリケーションが誕生し、自動構成はSpring Bootの閃光点の一つとして注目されている.
Spring Bootの自動構成機能は、本質的には新しい機能は導入されておらず、Springの既存の能力を組み合わせてパッケージ化しただけです.では、Spring Bootの自動構成原理を深く理解する前に、Springのこれらの既知の能力を理解し、良い基礎を築くことができます.
構成に関連するSpringの既存の機能
@Profile
多くの場合,我々が開発したSpringアプリケーションは,環境に応じて対応するBeanをコンテキストに登録する必要がある.
たとえば、ローカル開発環境では、データベース接続オブジェクトが開発データベースを指すことが多い.テスト環境では、テストデータベースも指します.オンラインになると、自然に生産データベースを指します.
この一般的なニーズを満たすためにSpring 3.1にProfileの概念が導入された.たとえば、次のコードでは、構成クラスは環境(Profile)によって対応するBeanインスタンスをコンテキストに注入します.
@Configuration
public class DataSourceConfiguration
{
    @Bean
    @Profile("DEV")
    public DataSource devDataSource() {
        // ...
    }

    @Bean
    @Profile("TEST")
    public DataSource testDataSource() {
        // ...
    }

    @Bean
    @Profile("PROD")
    public DataSource prodDataSource() {
        // ...
    }
}

では、アプリケーションが置かれているProfileをどのように宣言しますか?いくつかの選択肢があります
  • プロファイル(アプリケーション.propertiesでspring.profiles.active=DEV
  • と宣言するなど)
  • 起動パラメータ、例えば-Dspring.profiles.active=DEV
  • このProfileの概念は直感的ですが、文字列の値に依存して決定するだけなので、柔軟性と強さが足りません.そこで以下の@Conditional注釈とConditionインタフェースが誕生した.
    @ConditionalおよびConditionインタフェース
    Spring 4に導入された新機能です.
    Conditionインタフェースと@Conditionalインタフェースは通常一緒に使用されます.
    Conditionインタフェースの定義は次のとおりです.
    public interface Condition {
    
        /**
         *   Condition     
         * @param context      
         * @param metadata              
         */
        boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    
    }

    次に、インタフェースの実装クラスを示します.
    public class CustomCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            //          Condition     ,      true,    false
            return true;
        }
    }

    @Conditional注記の定義は次のとおりです.
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
    
        /**
         *                Class  ,  Class     Condition  ,      matches   true   ,   Bean     
         */
        Class extends Condition>[] value();
    
    }

    次に、Java Configクラスで一般的に使用されます.
    @Configuration
    public class CustomConfiguration {
        //  CustomCondition  matches  true       CustomClass      Bean。
        @Bean
        @Conditional(CustomCondition.class)
        public CustomClass customClass() {
            return new CustomClass();
        }
    }

    したがって,@Conditional注釈とConditionインタフェースの能力を組み合わせることで,外部条件に基づいてBeanがSpringコンテキストにロードされるべきかどうかを決定することができる.@Profile注記と比較すると、この方法はより柔軟性を提供することがわかります.
    @Profile注記では、Beanをロードするかどうかを唯一決定する文字列、すなわち、DEV、TEST、PRODUCTIONのような環境の識別子です.しかし,@Conditionalのスキームでは,ロードするか否かを決定する論理がConditionインタフェースに抽象化されており,これで可能な判断が非常に多い.
    @ConfigurationPropertiesおよび@E n a b l e ConfigurationProperties
    自動構成を実現するには、もう一つの重要な一環があります.Beanが意味を持つのは、各Beanに独自のフィールドがあるためであり、多くの場合、Beanのフィールドは構成可能であることを知っています.したがって、自動構成を実現するには、まずいくつかのキーフィールドにデフォルト値を与える必要があります.もちろん、ユーザーがこれらのフィールドを上書きできるようにするメカニズムも必要です.Spring Bootでは、コンフィギュレーション・プロパティという新しいメカニズムが提供されています.いくつかの特徴があります.
  • タイプのセキュリティ構成(Javaクラスベース)、Spring Conversion APIに基づいてタイプ変換
  • を完了
  • は、プロファイル、起動パラメータなど、さまざまな方法で上書き
  • を完了することができる.
  • とJavaConfigクラスシームレス統合
  • このメカニズムには、@ConfigurationPropertiesと@EnableConfigurationPropertiesの2つの重要な注釈タイプがあります.定義と適用方法を見てみましょう.
    定義方法
    @ConfigurationProperties
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ConfigurationProperties {
    
        @AliasFor("prefix")
        String value() default "";
    
        @AliasFor("value")
        String prefix() default "";
    
        // ...
    }

    主な属性紹介だけを拾い、この注釈で重要なのはvalue/prefix属性です.この2つの属性は1つの意味であり,@AliasForが互いに設定されている.
    @EnableConfigurationProperties
    /**
     *     @ConfigurationProperties   Beans。
     * @ConfigurationProperties   Bean         (    @Bean  ),                 。
     *
     * @author Dave Syer
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(EnableConfigurationPropertiesImportSelector.class)
    public @interface EnableConfigurationProperties {
    
        Class>[] value() default {};
    
    }

    アプリケーション
    Spring Webアプリケーションに必要なHttpEncodingFilterというFilterの自動構成を例に、この2つの注釈をどのように適用するかを見てみましょう.
    @ConfigurationProperties(prefix = "spring.http.encoding")
    public class HttpEncodingProperties {
    
        public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    
        private Charset charset = DEFAULT_CHARSET;
    
        private Boolean force;
    
        // ...
    
    }

    これはコンフィギュレーションクラスで、プレフィックスspring.http.encodingが設定されています.したがって、この構成クラスのフィールドは、charsetフィールドに対応する構成KEYがspring.http.encoding.charseであるなどの特定の構成KEYに対応する.forceフィールドはspring.http.encoding.forceに対応します.各フィールドにデフォルト値を設定することもできます.たとえば、上記のcharsetフィールドにデフォルト値DEFAULT_があります.CHARSETは、UTF-8の文字セットに対応しています.
    デフォルトのUTF-8符号化方式でGBKに変更したくない場合は、アプリケーション.propertiesなどのプロファイルで、次のように上書きできます.
    spring.http.encoding.charset=GBK

    ここでは、コンフィギュレーションファイルのGBKは文字列タイプの値であるのに、対応するコンフィギュレーション属性クラスという属性がCharsetタイプである場合、文字列からCharsetタイプへの変換を完了するステップがあるに違いない.この手順を完了したのがSpringフレームワークのConversion APIです.ここには関連する図を1枚だけ貼って、深く分析しないで、興味のある学生は属性クラスを配置するsetCharset方法にブレークポイントを打って深く掘ることができます.
    この図から、Spring Conversion APIでは、ソースタイプからターゲットタイプまでのMapオブジェクトである一連のConvertersが維持されていることがわかります.StringタイプからCharsetタイプへのConverterもこのMapオブジェクトに登録されています.したがって、コンフィギュレーション・ファイルの値タイプとコンフィギュレーション・Javaクラスのフィールド・タイプが一致しない場合、このMapから適切なConverterを見つけて変換しようとします.
    カスタム注釈自動構成
    次に、Beanのオンデマンド・ロードを実現するためのカスタム注釈を作成してみましょう.私たちが作成する注記の名前を@DatabaseTypeとします.
    具体的な要件は、起動パラメータのdbType=MYSQLのときに、MySQLのデータソースであるUserDAOオブジェクトを作成することです.パラメータのdbType=ORACLEを起動すると、OracleのデータソースであるUserDAOオブジェクトが作成されます.
    最終構成クラスのコードは次のようになります.
    @Configuration
    public class DatabaseConfiguration
    {
      @Bean
      @DatabaseType("MYSQL")
      public UserDAO mysqlUserDAO() {
          return new MySQLUserDAO();
      }
    
      @Bean
      @DatabaseType("ORACLE")
      public UserDAO oracleUserDAO() {
          return new OracleUserDAO();
      }
    }

    @DatabaseTypeという注記は、パラメータとして文字列を受け入れることができることがわかります.その後、このパラメータと起動パラメータのdbType値を比較し、等しければ対応するBeanの注入作業を行う.@DatabaseTypeの実装は次のとおりです.
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Conditional(DatabaseTypeCondition.class)
    public @interface DatabaseType {
        String value();
    }

    その中で重要なのは@Conditional(DatabaseTypeCondition.class)で、実際にはDatabaseType Conditionというクラスに委託されていると考えていることを示しています.
    public class DatabaseTypeCondition implements Condition {
        //       AnnotatedTypeMetadata       
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
            Map attributes = metadata.getAnnotationAttributes(DatabaseType.class.getName());
            String type = (String) attributes.get("value");
            String enabledDBType = System.getProperty("dbType", "MYSQL");
            return (enabledDBType != null && type != null && enabledDBType.equalsIgnoreCase(type));
        }
    }

    matchesメソッドの2番目のパラメータAnnotatedType Metadataにより、指定した注釈タイプのすべての属性を得ることができます.この例では@DatabaseTypeという注釈です.次に、注記のvalue値と起動パラメータdbType(存在しない場合はMYSQLをデフォルト値として使用)を比較し、対応する値を返してBeanを注入する必要があるかどうかを決定します.
    だから、この例を通して私たちも発見することができます.一般に、@ConditionalインタフェースおよびConditionインタフェースのインプリメンテーションクラスは、上記の@DatabaseTypeのような、より明確なビジネス意味を持つ注釈タイプにカプセル化することができる.その意味は、タイプがMySQLの場合はどうすればいいか、タイプがOracleの場合はどうすればいいかということです.
    後にSpring Bootの自動構成メカニズムを深く検討すると,@ConditionalとConditionインタフェースに基づいて,自動構成挙動をよりよく定義するために多くの関連タイプが定義されていることがわかる.
    まとめ
    この論文では、Springと自動構成に関する2つの概念について説明します.
  • @Profile
  • @ConditionalおよびConditionインタフェース
  • 次に、カスタム注釈を使用して自動構成を完了する例を挙げます.
    これらの知識に基づいて,次の文章ではSpring Bootの自動構成の原理を深く掘り下げることができる.