Springboot源码阅读前置知识【注解】

486 阅读4分钟

@ConfigurationProperties 【SpringBoot 提供】

配置项太多,通过 @Value 的方式一个一个从配置文件中取太麻烦。这玩意@ConfigurationProperties 就出场了。

标有 @ConfigurationProperties 的类的所有属性会从全局配置文件里取

下面看一个实例:

  1. 在主配置文件中添加如下配置
ftp:
 address: '192.168.1.1'
 account: 'admin'
 password: 'asdf'
 port: '20'
  1. 创建配置类使用
@Component 
@ConfigurationProperties(prefix = "ftp") 
public class MyFtp { 
    private String address; 
    private String account; 
    private String password; 
    private String port; 
} 

这里 @ConfigurationProperties 有一个 prefix 参数,主要是用来指定该配置项在配置文件中的前缀。

  1. SpringBoot 中 直接使用@Autowired 导入MyFtp即可

@Import 【Spring 提供】

@Import 三种使用方式

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

1. 直接导入普通的 Java 类

  1. 创建一个普通的 Java 类。
public class Yasuo { 

public void qFunction() { 
    System.out.println("疾风斩"); 
} 
} 
  1. 创建一个配置类并使用。
@Import({Yasuo.class}) 
@Configuration 
public class LolConfig { 

} 
  1. 创建测试类。
public static void main(String[] args) { 

ApplicationContext context = new AnnotationConfigApplicationContext(Lol.class); 
    Yasuo yasuo = context.getBean(Yasuo.class); 
    yasuo.qFunction(); 
} 
  1. 运行结果:

疾风斩

2. 配合自定义的 ImportSelector 使用

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

  1. 创建普通 Java 类 。
public class Reven { 

public void qFunction(){ 
System.out.println("qa qa qa"); 
} 

}
  1. 创建 ImportSelector 实现类,selectImports 返回 Reven 的全类名。
public class MyImportSelector implements ImportSelector { 

@Override 
public String[] selectImports(AnnotationMetadata annotationMetadata) { 
    return new String[]{"annotation.importannotation.Reven"}; 
} 

} 
  1. 创建配置类,在原来的基础上还导入了 MyImportSelector。
@Import({Yasuo.class,MyImportSelector.class}) 
@Configuration 
public class Lol { 

} 
  1. 创建测试类
public static void main(String[] args) { 

ApplicationContext context = new AnnotationConfigApplicationContext(Lol.class); 
    Yasuo yasuo = context.getBean(Yasuo.class); 
    yasuo.qFunction(); 
    Reven reven = context.getBean(Reven.class); 
    reven.qFunction(); 

} 
复制代码
  1. 运行结果:

疾风斩 qa qa qa

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

3. 配合 ImportBeanDefinitionRegistrar 使用

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

  1. 创建普通 Java 类 Jie。
public class Jie { 

public void qFunction() { 
    System.out.println("qqq"); 
} 
}
  1. 创建 ImportBeanDefinitionRegistrar 实现类,实现方法直接手动注册一个名叫 Jie 的 Bean 到 IOC 容器中。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 

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

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

} 

  1. 创建配置类,导入 MyImportBeanDefinitionRegistrar 类。
@Import({Yasuo.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) 
@Configuration 
public class LolV3 { 

} 
  1. 创建测试类。
public static void main(String[] args) { 

ApplicationContext context = new AnnotationConfigApplicationContext(LolV3.class); 
    Yasuo yasuo = context.getBean(Yasuo.class); 
    yasuo.qFunction(); 
    
    Reven reven = context.getBean(Reven.class); 
    reven.qFunction(); 
    
    Jie jie = context.getBean(Jie.class); 
    jie.qFunction(); 
} 

  1. 运行结果

疾风斩

qa qa qa

qqq

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

@Conditional 【Spring提供】

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

下面看一个简单的例子:

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

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

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

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

} 
复制代码
  1. 创建配置类,可以看到该配置的 @Conditional 传了我们刚才创建的 Condition 实现类进去,用作条件判断。
@Configuration 
@Conditional(MyCondition.class) 
public class ConditionConfig { 

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

} 
复制代码
  1. 编写测试方法。
public static void main(String[] args) { 

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

} 
复制代码
  1. 结果分析

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

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

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionalOnJava系统的java版本是否符合要求
@ConditionalOnBean容器中存在指定Bean;
@ConditionalOnMissingBean容器中不存在指定Bean;
@ConditionalOnExpression满足SpEL表达式指定
@ConditionalOnClass系统中有指定的类
@ConditionalOnMissingClass系统中没有指定的类
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty系统中指定的属性是否有指定的值
@ConditionalOnResource类路径下是否存在指定资源文件
@ConditionalOnWebApplication当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndiJNDI存在指定项