この記事は Spring Boot の条件判断の入門 (コード付き) です。一定の参考値があります。困っている友人は参考にしてください。お役に立てれば幸いです。
Spring Boot の条件文
Spring Boot には、プロジェクト内のコンテナに Bean を簡単に追加できる豊富な条件文セットが用意されています。この記事では主に各アノテーションについて説明し、コードでのその使用法を示します。
すべての ConditionalOnXXX アノテーションはクラスまたはメソッドに配置できます。メソッドがクラスにある場合は、クラス内のすべての @Bean アノテーション付きメソッドが実行されるかどうかが決定されます。
以下の他の条件付きアノテーションはすべて糖衣構文です。次のメソッドを使用して ConditionalOnXXX をカスタマイズできます。
条件付きアノテーションは次のように定義され、実装するクラス配列を受け取ります条件インターフェイス。
public @interface Conditional { Class extends Condition>[] value(); }
Condition インターフェイスには、マッチングの結果を返す match メソッドが 1 つだけあります。
public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }
オペレーティング システムを介して条件を設定し、Bean を設定します。 Window を使用する場合は Bill の Person オブジェクトがインスタンス化され、Linux を使用する場合は Linus の Person オブジェクトがインスタンス化されます。
//LinuxCondition,为方便起见,去掉判断代码,直接返回true了 public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return true; } }
//WindowsCondition,为方便起见,去掉判断代码,直接返回false了 public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) { return false; } }
@Data @ToString @AllArgsConstructor @NoArgsConstructor public class Person { private String name; private Integer age; }
//配置类 @Configuration public class BeanConfig { @Bean(name = "bill") @Conditional({WindowsCondition.class}) public Person person1(){ return new Person("Bill Gates",62); } @Bean("linus") @Conditional({LinuxCondition.class}) public Person person2(){ return new Person("Linus",48); } }
public class AppTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void test(){ String osName = applicationContext.getEnvironment().getProperty("os.name"); System.out.println("当前系统为:" + osName); Map<string> map = applicationContext.getBeansOfType(Person.class); System.out.println(map); } }</string>
出力結果:
現在のシステム: Mac OS X
{linus=person(name=Linus, age=48)}
これら 2 つのアノテーションは、Bean コンテナ内の Bean オブジェクトを判定します。使用例は構成時です。Computer インスタンスが存在しないことが判明した場合、バックアップ コンピュータがインスタンス化されます。
@Data @AllArgsConstructor @ToString public class Computer { private String name; }
@Configuration public class BeanConfig { @Bean(name = "notebookPC") public Computer computer1(){ return new Computer("笔记本电脑"); } @ConditionalOnMissingBean(Computer.class) @Bean("reservePC") public Computer computer2(){ return new Computer("备用电脑"); } }
public class TestApp { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void test1(){ Map<string> map = applicationContext.getBeansOfType(Computer.class); System.out.println(map); } }</string>
BeanConfig を変更します。最初の @Bean をコメントアウトすると、バックアップ コンピューターがインスタンス化されます。それ以外の場合、バックアップ コンピューターはインスタンス化されません。
このアノテーションは、クラスパス上に指定されたクラスがあるかどうかを判断します。最初に見たときはわかりにくかったです。クラスパス上に指定されたクラスがないとコンパイルが通りません...これは主に統合するために使用されますコンポーネントを使用する際、そのコンポーネントのクラスがクラスパス上に存在する限り、自動的に設定されます。例えば、Spring Boot Web が View コンポーネントを自動設定する場合、Velocity を使用します。 Thymeleaf、または freemaker これが使用される方法です。
例は、アーマー A (ライト スーツ) と B (ダーク スーツ) の 2 セットです。A が存在しない場合は、B を設定します。
public interface Fighter { void fight(); } public class FighterA implements Fighter { @Override public void fight() { System.out.println("使用光明套装"); } } public class FighterB implements Fighter { @Override public void fight() { System.out.println("使用暗黑套装"); } }
Van はサムライであり、戦闘にスーツを使用します
@Data @AllArgsConstructor @NoArgsConstructor public class Van { private Fighter fighter; public void fight(){ fighter.fight(); } }
VanConfigA/B はサムライをインスタンス化します
@Configuration @ConditionalOnClass({FighterA.class}) public class VanConfigA { @Primary @Bean public Van vanA(){ return new Van(new FighterA()); } } @Configuration @ConditionalOnClass({FighterB.class}) public class VanConfigB { @Bean public Van vanB(){ return new Van(new FighterB()); } }
テスト クラス (スーツ AB がクラスにある場合、デフォルトで) path、両方のセットがロードされ、A は PRIMARY に設定されます。ターゲット クラスで FightA.class が削除された場合、セット B のみがロードされます。
@SpringBootApplication public class TestApp implements CommandLineRunner { @Autowired private Van van; public static void main(String[] args) { SpringApplication.run(TestApp.class, args); } @Override public void run(String... args) throws Exception { //do something van.fight(); } }
さらに、2つのVanConfigA/Bをマージして、メソッドにConditionalOnClassというアノテーションを付けてみますが、スーツを削除するとエラーが発生します。
式に基づいて条件判定を行います。この関数はほとんどの場合に @ConditionalOnProperty で使用できます。SpEL が使用できるため、式はより柔軟になります。例ではプロパティのtest.enabledの値を判定します。 BeanConfigはBoolean、文字列、数値の3種類をそれぞれ判定します。他にも多くの方法を試しましたが、 == を直接使用するなど、どれも機能せず、設定された属性が文字列として扱われるようです。
@Data public class TestBean { private String name; }
@Configuration @ConditionalOnExpression("#{${test.enabled:true} }") //@ConditionalOnExpression("'zz'.equalsIgnoreCase('${test.name2}')") //@ConditionalOnExpression("new Integer('${test.account}')==1") public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean("我是美猴王"); } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner { @Autowired private TestBean testBean; public static void main(String[] args) { SpringApplication.run(TestAppCommand.class, args); } @Override public void run(String... args) throws Exception { System.out.println(testBean.getName()); } }
は、単一のプロパティの条件判断に適していますが、上記の @ConditionalOnExpress は、複数のプロパティの関連比較など、より複雑な状況に適しています。この例でも基本的な条件判定を3種類挙げていますが、どれも文字列として扱えるようです...
@Data @AllArgsConstructor @NoArgsConstructor public class TestBean { private String name; }
@Configuration @ConditionalOnProperty(prefix = "test", name="enabled", havingValue = "true",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="account", havingValue = "1",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="name1", havingValue = "zz",matchIfMissing = false) public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean("我是美猴王"); } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner { @Autowired private TestBean testBean; public static void main(String[] args) { SpringApplication.run(TestAppCommand.class, args); } @Override public void run(String... args) throws Exception { System.out.println(testBean.getName()); } }
Javaのバージョンで判定できます。
@Data public class TestBean { }
@Configuration @ConditionalOnJava(JavaVersion.EIGHT) public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean(); } }
public class TestApp { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void test(){ Map<string> map = context.getBeansOfType(TestBean.class); System.out.println(map); } }</string>
ehcache.properties を判断して ehcache コンポーネントを自動的にアセンブルするかどうかを判断するなど、指定されたリソース ファイルが存在するかどうかに基づいて条件判断が行われます。
@Data public class TestBean { }
@Configuration @ConditionalOnResource(resources = "classpath:application.yml") public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean(); } }
public class TestApp { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void test(){ Map<string> map = context.getBeansOfType(TestBean.class); System.out.println(map); } }</string>
アプリケーション シナリオについてはまだ考えていません。条件を渡すための条件は次のとおりです。 1. 対応する Bean コンテナが 1 つだけある。 2. 対応する Bean コンテナが複数ある。豆ですが、PRIMARYが配合されています。この例では、BeanB をアセンブルするときに、BeanA のアセンブリ状態をチェックする必要があるため、BeanBConfig は BeanAConfig の後にランク付けされる必要があります。BeanAConfig を変更して @Primary アノテーションを削除するか、3 つの @Bean アノテーションを削除すると、BeanB はアセンブルされなくなります。インスタンス化されました。
@Data @AllArgsConstructor @NoArgsConstructor public class BeanA { private String name; }
@Configuration public class BeanAConfig { @Bean @Primary public BeanA bean1(){ return new BeanA("bean1"); } @Bean(autowireCandidate = false) public BeanA bean2(){ return new BeanA("bean2"); } //@Bean(autowireCandidate = false) public BeanA bean3(){ return new BeanA("bean3"); } }
@Data public class BeanB { }
@Configuration @AutoConfigureAfter(BeanAConfig.class) @ConditionalOnSingleCandidate(BeanA.class) public class BeanBConfig { @Bean public BeanB targetBean(){ return new BeanB(); } }
public class TestApp { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAConfig.class, BeanBConfig.class); @Test public void test(){ Map<string> map = context.getBeansOfType(BeanA.class); System.out.println(map); Map<string> map2 = context.getBeansOfType(BeanB.class); System.out.println(map2); } }</string></string>
現在の環境が Web アプリケーションであるかどうかを確認します。
@Data @AllArgsConstructor @NoArgsConstructor public class TestBean { private String name; }
@Configuration @ConditionalOnProperty(prefix = "test", name="enabled", havingValue = "true",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="account", havingValue = "1",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="name1", havingValue = "zz",matchIfMissing = false) public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean("我是美猴王"); } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner { @Autowired private TestBean testBean; public static void main(String[] args) { SpringApplication.run(TestAppCommand.class, args); } @Override public void run(String... args) throws Exception { System.out.println(testBean.getName()); } }
@Data public class TestBean { }
@Configuration @ConditionalOnJava(JavaVersion.EIGHT) public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean(); } }
public class TestApp { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void test(){ Map<string> map = context.getBeansOfType(TestBean.class); System.out.println(map); } }</string>
@Data public class TestBean { }
@Configuration @ConditionalOnResource(resources = "classpath:application.yml") public class BeanConfig { @Bean public TestBean testBean(){ return new TestBean(); } }
public class TestApp { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void test(){ Map<string> map = context.getBeansOfType(TestBean.class); System.out.println(map); } }</string>
这个还没有想到应用场景,条件通过的条件是:1 对应的bean容器中只有一个 2.对应的bean有多个,但是已经制定了PRIMARY。例子中,BeanB装配的时候需要看BeanA的装配情况,所以BeanBConfig要排在BeanAConfig之后.可以修改BeanAConfig,将@Primary注解去掉,或者把三个@Bean注解去掉,BeanB就不会实例化了。
@Data @AllArgsConstructor @NoArgsConstructor public class BeanA { private String name; }
@Configuration public class BeanAConfig { @Bean @Primary public BeanA bean1(){ return new BeanA("bean1"); } @Bean(autowireCandidate = false) public BeanA bean2(){ return new BeanA("bean2"); } //@Bean(autowireCandidate = false) public BeanA bean3(){ return new BeanA("bean3"); } }
@Data public class BeanB { }
@Configuration @AutoConfigureAfter(BeanAConfig.class) @ConditionalOnSingleCandidate(BeanA.class) public class BeanBConfig { @Bean public BeanB targetBean(){ return new BeanB(); } }
public class TestApp { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAConfig.class, BeanBConfig.class); @Test public void test(){ Map<string> map = context.getBeansOfType(BeanA.class); System.out.println(map); Map<string> map2 = context.getBeansOfType(BeanB.class); System.out.println(map2); } }</string></string>
判断当前环境是否是Web应用。
评论
以上がSpring Bootの条件判定入門(コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。