文章目录

    • 1. @Value
    • 2. @ConfigurationProperties
    • 3. @Import
      • 3.1 直接导入普通的 Java 类
      • 3.2 配合自定义的 ImportSelector 使用
      • 3. 配合 ImportBeanDefinitionRegistrar 使用
    • 4. @Conditional


1. @Value

我们知道配置文件中的 value 的取值可以是:

  • 字面量
  • 通过 ${key} 方式从环境变量中获取值
  • 通过 ${key} 方式全局配置文件中获取值
  • #{SpEL}

例如:

@Component   
public class Person {   

@Value("i am name")   
private String name;   

}

2. @ConfigurationProperties

如果我们需要取 N 个配置项,通过 @Value 的方式去配置项需要一个一个去取,这就显得有点 low 了。我们可以使用 @ConfigurationProperties。

标有 @ConfigurationProperties 的类的所有属性和配置文件中相关的配置项进行绑定。(默认从全局配置文件中获取配置值),绑定之后我们就可以通过这个类去访问全局配置文件中的属性值了。

例如yaml配置:

person.name=kundy   
person.age=13   
person.sex=male

例如配置类:

@Component   
@ConfigurationProperties(prefix = "person")   
public class Person {   

private String name;   
private Integer age;   
private String sex;   
}

3. @Import

@Import 注解支持导入普通 java 类,并将其声明成一个bean。主要用于将多个分散的 java config 配置类融合成一个更大的 config 类。

@Import 注解在 4.2 之前只支持导入配置类。
在4.2之后 @Import 注解支持导入普通的 java 类,并将其声明成一个 bean。

@Import 三种使用方式

  • 直接导入普通的 Java 类。
  • 配合自定义的 ImportSelector 使用。
  • 配合 ImportBeanDefinitionRegistrar 使用。

3.1 直接导入普通的 Java 类

1.创建一个普通的 Java 类。

public class Circle {   
  public void sayHi() {   
    System.out.println("Circle sayHi()");   
  }    
}

2.创建一个配置类,里面没有显式声明任何的 Bean,然后将刚才创建的 Circle 导入。

@Import({Circle.class})   
@Configuration   
public class MainConfig {   
}

3.创建测试类。

public static void main(String[] args) {   
  ApplicationContext context = new  AnnotationConfigApplicationContext(MainConfig.class);   
  Circle circle = context.getBean(Circle.class);   
  circle.sayHi();   
}

4.运行结果:

Circle sayHi()

可以看到我们顺利的从 IOC 容器中获取到了 Circle 对象,证明我们在配置类中导入的 Circle 类,确实被声明为了一个 Bean。

3.2 配合自定义的 ImportSelector 使用

ImportSelector 是一个接口,该接口中只有一个 selectImports 方法,用于返回全类名数组。所以利用该特性我们可以给容器动态导入 N 个 Bean。

1.创建普通 Java 类 Triangle。

public class Triangle {   

  public void sayHi(){   
    System.out.println("Triangle sayHi()");   
  }   

}

2.创建 ImportSelector 实现类,selectImports 返回 Triangle 的全类名。

public class MyImportSelector implements ImportSelector {   
  @Override   
  public String[] selectImports(AnnotationMetadata annotationMetadata) {
    return new String[]{"annotation.importannotation.waytwo.Triangle"};   
  }
}

3.创建配置类,在原来的基础上还导入了 MyImportSelector。

@Import({Circle.class,MyImportSelector.class})   
@Configuration   
public class MainConfigTwo {   

}

4.创建测试类

public static void main(String[] args) {   
  ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigTwo.class);   
  Circle circle = context.getBean(Circle.class);   
  Triangle triangle = context.getBean(Triangle.class);   
  circle.sayHi();   
  triangle.sayHi();   

}

5.运行结果:

Circle sayHi() Triangle sayHi()

可以看到 Triangle 对象也被 IOC 容器成功的实例化出来了。

3. 配合 ImportBeanDefinitionRegistrar 使用

ImportBeanDefinitionRegistrar 也是一个接口,它可以手动注册bean到容器中,从而我们可以对类进行个性化的定制。(需要搭配 @Import 与 @Configuration 一起使用。)

1.创建普通 Java 类 Rectangle。

public class Rectangle {   

public void sayHi() {   
System.out.println("Rectangle sayHi()");   
}   

}

2.创建 ImportBeanDefinitionRegistrar 实现类,实现方法直接手动注册一个名叫 rectangle 的 Bean 到 IOC 容器中。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {   

    @Override   
  public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {   

  RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Rectangle.class);   
  // 注册一个名字叫做 rectangle 的 bean   
  beanDefinitionRegistry.registerBeanDefinition("rectangle", rootBeanDefinition);   
    }   

}

3.创建配置类,导入 MyImportBeanDefinitionRegistrar 类。

@Import({Circle.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})   
@Configuration   
public class MainConfigThree {   

}

4.创建测试类。

public static void main(String[] args) {   

  ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigThree.class);   
  Circle circle = context.getBean(Circle.class);   
  Triangle triangle = context.getBean(Triangle.class);   
  Rectangle rectangle = context.getBean(Rectangle.class);   
  circle.sayHi();   
  triangle.sayHi();   
  rectangle.sayHi();   

}

5.运行结果

Circle sayHi() Triangle sayHi() Rectangle sayHi()

嗯对,Rectangle 对象也被注册进来了。

4. @Conditional

@Conditional 注释可以实现只有在特定条件满足时才启用一些配置。

1.创建普通 Java 类 ConditionBean,该类主要用来验证 Bean 是否成功加载。

public class ConditionBean {   

public void sayHi() {   
System.out.println("ConditionBean sayHi()");   
}   

}

2.创建 Condition 实现类,@Conditional 注解只有一个 Condition 类型的参数,Condition 是一个接口,该接口只有一个返回布尔值的 matches() 方法,该方法返回 true 则条件成立,配置类生效。反之,则不生效。在该例子中我们直接返回 true。

public class MyCondition implements Condition {   

  @Override   
  public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {   
  return true;   
  }   

}

3.创建配置类,可以看到该配置的 @Conditional 传了我们刚才创建的 Condition 实现类进去,用作条件判断。

@Configuration   
@Conditional(MyCondition.class)   
public class ConditionConfig {   

  @Bean   
  public ConditionBean conditionBean(){   
  return new ConditionBean();   
  }   

}

4.编写测试方法。

public static void main(String[] args) {   

  ApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);   
  ConditionBean conditionBean = context.getBean(ConditionBean.class);   
  conditionBean.sayHi();   

}

5.结果分析因为
Condition 的 matches 方法直接返回了 true,配置类会生效,我们可以把 matches 改成返回 false,则配置类就不会生效了。

除了自定义 Condition,Spring 还为我们扩展了一些常用的 Condition。常用注解,

更多推荐

SpringBoot:SpringBoot常用注解