一、條件注解@Conditional,組合注解,元注解
1.
@Conditional:滿足特定條件創建一個Bean,SpringBoot就是利用這個特性進行自動配置的。
例子:
首先,兩個Condition,判斷當前系統是否是Windows或者Linux(True False)
然后,2個ListService實現類,表明不同系統下的ListService實現。
主要,ConditionConfig使用了Java配置與@Conditional注解,根據LinuxCondition,或者WindowsCondition作為判斷條件
產生相應與系統匹配的實現類。
最后,App.java 測試成功。

package com.springboot.springboot_test2_1; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) { return arg0.getEnvironment().getProperty("os.name").contains("Linux"); } }

package com.springboot.springboot_test2_1; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) { return arg0.getEnvironment().getProperty("os.name").contains("Windows"); } }

package com.springboot.springboot_test2_1; public interface ListService { public String showListCmd(); }

package com.springboot.springboot_test2_1; public class LinuxListService implements ListService{ @Override public String showListCmd() { return "ls"; } }

package com.springboot.springboot_test2_1; public class WindowsListService implements ListService{ @Override public String showListCmd() { return "dir"; } }

package com.springboot.springboot_test2_1; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class ConditionConfig { @Bean @Conditional(WindowsCondition.class) public ListService windowsListService() { return new WindowsListService(); } @Bean @Conditional(LinuxCondition.class) public ListService linuxListService() { return new LinuxListService(); } }

package com.springboot.springboot_test2_1; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * Hello world! * */ public class App { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext( ConditionConfig.class); ListService ls = context.getBean(ListService.class); System.out.println(context.getEnvironment().getProperty("os.name") + "系統下的列表命令為:" + ls.showListCmd()); } }
2.
元注解:可以注解到別的注解上的注解。
組合注解:元注解+被注解=組合注解。
例子:

package com.springboot.springboot_test2_1; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @ComponentScan public @interface testConfig { String[] value() default{}; }
二、通過條件注解@Conditional,組合注解,元注解理解SpringBoot的自動配置
@SpringBootApplication,源碼:

@Target({java.lang.annotation.ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters={@org.springframework.context.annotation.ComponentScan.Filter(type=org.springframework.context.annotation.FilterType.CUSTOM, classes={org.springframework.boot.context.TypeExcludeFilter.class}), @org.springframework.context.annotation.ComponentScan.Filter(type=org.springframework.context.annotation.FilterType.CUSTOM, classes={AutoConfigurationExcludeFilter.class})}) public @interface SpringBootApplication { @AliasFor(annotation=EnableAutoConfiguration.class, attribute="exclude") Class<?>[] exclude() default {}; @AliasFor(annotation=EnableAutoConfiguration.class, attribute="excludeName") String[] excludeName() default {}; @AliasFor(annotation=ComponentScan.class, attribute="basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation=ComponentScan.class, attribute="basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; }
它的核心功能是由@EnableAutoConfiguration注解提供的,
@EnableAutoConfiguration,源碼:

@SuppressWarnings("deprecation") @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {}; }
@EnableAutoConfiguration其中的@AutoConfigurationPackage,會掃描/META-INF/spring.factories文件中的jar包,
spring.factories文件如下:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
……
2、核心注解
spring.factories文件里每一個xxxAutoConfiguration文件一般都會有下面的條件注解:
@ConditionalOnBean:當容器里有指定Bean的條件下
@ConditionalOnClass:當類路徑下有指定類的條件下
@ConditionalOnExpression:基於SpEL表達式作為判斷條件
@ConditionalOnJava:基於JV版本作為判斷條件
@ConditionalOnJndi:在JNDI存在的條件下差在指定的位置
@ConditionalOnMissingBean:當容器里沒有指定Bean的情況下
@ConditionalOnMissingClass:當類路徑下沒有指定類的條件下
@ConditionalOnNotWebApplication:當前項目不是Web項目的條件下
@ConditionalOnProperty:指定的屬性是否有指定的值
@ConditionalOnResource:類路徑是否有指定的值
@ConditionalOnSingleCandidate:當指定Bean在容器中只有一個,或者雖然有多個但是指定首選Bean
@ConditionalOnWebApplication:當前項目是Web項目的條件下。
上面@ConditionalOnXXX都是組合@Conditional元注解,使用了不同的條件Condition