一、为什么会想到定义@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"); } } }