一、為什么會想到定義@SpringCloudProfile這樣的注解
首頁提一下@Profile注解:它主要用與Spring Boot多環境配置中,指定某個類只在指定環境中生效,比如swagger的配置只允許開發和測試環境開發,線上需要禁止使用。
使用@Profile進行如下配置:
@Configuration @EnableSwagger2
@Profile({"dev", "test"}) public class Swagger2Config { @Bean public Docket docket() { return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select() //當前包路徑 .apis(RequestHandlerSelectors.basePackage("com.zbq.springbootbase.controller")) .paths(PathSelectors.any()).build(); } //構建api文檔的詳細信息函數 private ApiInfo apiInfo() { return new ApiInfoBuilder() //頁面標題 .title("springboot-base-frame,使用Swagger2構建RESTful API") //創建人 .contact(new Contact("張波清", "756623607@qq.com", "")) //版本號 .version("1.0") //描述 .description("API 描述") .build(); } }
但是在Spring Cloud中由於使用了配置中心,導致啟動項目時沒有指定spring.profiles.active屬性導致@Profile注解失效,原因就是@Profile通過獲取環境變量中spring.profiles.active屬性值,與注解中設置的值進行比較,包含就生效。
所有在Spring Cloud中需要換一個環境變量來實現,正好有spring.cloud.config.profile這個變量,該變量用於指定讀取配置中心那個環境配置的,一般有這些值,dev、test、prod
二、自定義@SpringCloudProfile注解的實現
1)定義@SpringCloudProfile注解
/** * @author zhangboqing * @date 2019/11/12 */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(SpringCloudProfileCondition.class) public @interface SpringCloudProfile { /** * The set of profiles for which the annotated component should be registered. */ String[] value(); }
2)實現SpringCloudProfileCondition類,用於條件匹配
/** * @author zhangboqing * @date 2019/11/12 */ public class SpringCloudProfileCondition implements Condition { public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.cloud.config.profile"; @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(SpringCloudProfile.class.getName()); if (attrs != null) { for (Object value : attrs.get("value")) { if (acceptsProfiles(context,(String[]) value)) { return true; } } return false; } return true; } public boolean acceptsProfiles(ConditionContext context,String... profiles) { Assert.notEmpty(profiles, "Must specify at least one profile"); for (String profile : profiles) { if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') { if (!isProfileActive(context,profile.substring(1))) { return true; } } else if (isProfileActive(context,profile)) { return true; } } return false; } protected boolean isProfileActive(ConditionContext context,String profile) { validateProfile(profile); String property = context.getEnvironment().getProperty(ACTIVE_PROFILES_PROPERTY_NAME); return property.equals(profile); } protected void validateProfile(String profile) { if (!StringUtils.hasText(profile)) { throw new IllegalArgumentException("Invalid profile [" + profile + "]: must contain text"); } if (profile.charAt(0) == '!') { throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not begin with ! operator"); } } }