0
点赞
收藏
分享

微信扫一扫

Spring 手动注册之条件装配

其生 2022-12-22 阅读 164


Spring 条件装配有两种方式:

  • ​@Profile​​:基于当前环境配置方式;
  • ​@Conditional​​:基于编程方式;

@Profile

先看一个例子:

@SpringBootApplication
public class ConditionBootstrap {

public static void main(String[] args) {
SpringApplication springBootApplication = new SpringApplication(ConditionBootstrap.class);
springBootApplication.setWebApplicationType(WebApplicationType.NONE);
springBootApplication.setAdditionalProfiles("dev");
ConfigurableApplicationContext context = springBootApplication.run(args);
System.out.println(context.getBeansOfType(User.class));
}

@Bean
@Profile("dev")
public User user1(){
User user = new User();
user.setName("dev");
return user;
}

@Bean
@Profile("prod")
public User user2(){
User user = new User();
user.setName("prod");
return user;
}
}

输出结果:

{user1=User{name='dev', age=null}}

同样地,也可以在 application.properties 文件里面指定 profile:

spring.profiles.active = prod

那么如果在 application.properties 中指定为 prod,在 SpringApplication 中指定为 dev 会怎么样呢,运行结果:

{user1=User{name='dev', age=null}, user2=User{name='prod', age=null}}

也就是说这两个的 profile 的配置优先级是一致的。

在刚刚的配置的基础上再尝试下,先打个包:

mvn clean package -Dmaven.test.skip=true -X

执行 jar:

java -jar /Users/dongguabai/IdeaProjects/dongguabai/spring-boot-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev

运行结果:

{user1=User{name='dev', age=null}}

也就是说 ​​--spring.profiles.active​​ 的优先级是最高的。

@Conditional

​@Profile​​​ 使用虽然很简单,但是功能很单一,而 ​​@Conditional​​ 基于接口编程,有着更丰富的功能,在 Spring Boot 中有大量的应用。

其实 ​​@Profile​​​ 在后续版本也是基于 ​​@Conditional​​ 实现:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

/**
* The set of profiles for which the annotated component should be registered.
*/
String[] value();

}

​@Conditional​​​ 注解里面需要传入 ​​Condition​​ 的实现:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

/**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();

}

可以看到 ​​@Conditional​​​ 注解可以标注在类上,也可以标注在方法上,如果是在方法上,比如 ​​@Bean​​​ 这种,符合条件就会注入这个 Bean,如果标注在类上,比如 ​​@Configuration​​,就决定了这一批 Bean 是否注入。

看看 ​​ProfileCondition​​ 类:

class ProfileCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
return true;
}
}
return false;
}
return true;
}

}

实现了 ​​Condition​​​ 接口,根据 ​​matches​​​ 方法进行匹配。看看 ​​Condition​​ 接口:

@FunctionalInterface
public interface Condition {

/**
* Determine if the condition matches.
* @param context the condition context
* @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
* or {@link org.springframework.core.type.MethodMetadata method} being checked
* @return {@code true} if the condition matches and the component can be registered,
* or {@code false} to veto the annotated component's registration
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

是一个函数式接口。可以参照这个实现自己来一个,这里根据当前的系统操作环境决定注入哪个 Bean。 先定义一个注解:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnOSTypeCondition.class)
public @interface ConditionalOnOSType {

Type type() default Type.ANY;

enum Type {

MAC,

WINDOWS,

ANY

}

}

​Condition​​ 的实现:

public class OnOSTypeCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnOSType.class.getName());
ConditionalOnOSType.Type osType = (ConditionalOnOSType.Type)attributes.get("type");
return System.getProperty("os.name").toUpperCase().contains(osType.name());
}

}

测试:

@SpringBootApplication
public class ConditionBootstrap {

public static void main(String[] args) {
SpringApplication springBootApplication = new SpringApplication(ConditionBootstrap.class);
springBootApplication.setWebApplicationType(WebApplicationType.NONE);
//springBootApplication.setAdditionalProfiles("dev");
ConfigurableApplicationContext context = springBootApplication.run(args);
System.out.println(context.getBeansOfType(User.class));
}

@Bean
@ConditionalOnOSType(type = ConditionalOnOSType.Type.MAC)
public User user1(){
User user = new User();
user.setName("MAC");
return user;
}

@Bean
@ConditionalOnOSType(type = ConditionalOnOSType.Type.WINDOWS)
public User user2(){
User user = new User();
user.setName("WINDOWS");
return user;
}

}

输出:

{user1=User{name='MAC', age=null}}

​​​​​

Spring 手动注册之条件装配_jar


举报

相关推荐

0 条评论