@Condition 条件注册 bean
@Condition 来指定一定条件下注册组件对象,所有的条件必须实现 Condition 接口,重写 matches 方法,来决定组件是否注册。
判断注册哪个(注册bean的配置类)
@Configuration
public class BeanConfig {
@Bean(name = "bill")
public Person person1(){
return new Person("Bill Gates",62);
}
@Bean("linus")
public Person person2(){
return new Person("Linus",48);
}
}
Windows Condition类
public class WindowsCondition implements Condition {
/**
* @param conditionContext:判断条件能使用的上下文环境
* @param annotatedTypeMetadata:注解所在位置的注释信息
* */
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//获取当前环境信息
Environment environment = conditionContext.getEnvironment();
//获取bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//获得当前系统名
String property = environment.getProperty("os.name");
//包含Windows则说明是windows系统,返回true
if (property.contains("Windows")){
return true;
}
return false;
}
}
创建Linux Condition类
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Linux")){
return true;
}
return false;
}
}
@Import 与 @Bean 注解区别
两者都可以快速注入第三方 jar 包
@Bean 注解应用场景:注册外部 jar 包,作用在方法上。
为什么使用@Import?作用:主要将外部的 jar 包注入到 IOC 容器中。
@Import 中填入的类可以区分为三种:
- 实现ImportSelector 的类
- 实现ImportBeanDefinitionRegistrar 的类
- 其余的普通类
@Configuration
@Import(SelectDataVo.class)
public class MyConfig {
/**
* @Import 作用主要将外部的 jar 包注入到 springIoc容器中 等于 @Bean
* Import 注册的bean 对象id 为当前类全路劲
* @return
*/
@Bean
public SelectDataVo selectDataVo(){
return new SelectDataVo();
}
}
总结:@Import 和 @Bean 的区别
bean 注解注册的 bean 的id 是以方法名称, @Import 以当前类完整路径地址注册,相比来说@Import 注入类更加简单。
@Enable XXX功能性注解实现原理
主要使用 @Import 注解实现,引入对应的@EnableXXX注解后,会使用 @Import 注解注入对应的 bean,从而开启相应的功能。
使用 ImportSelector 注册bean
ImportSelector接口是至spring中导入外部配置的核心接口, 在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在,关于SpringBoot的分析可以参考: 深入理解SpringBoot的自动装配。
ImportSelector将允许我们根据条件动态选择想导入的配置类,换句话说,它具有动态性。
ImportSelector使用时, 我们要创建一个类实现ImportSelector接口,并重写其中的 String[] selectImports(AnnotationMetadata importingClassMetadata);
方法。
public class CustomImportSelector implements ImportSelector {
/**
* importingClassMetadata:被修饰的类注解信息
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 注意,自定义注解这里是拿不到的
System.out.println(importingClassMetadata.getAnnotationTypes());
// 如果被CustomImportSelector导入的组件是类,那么我们就实例化UserConfig
if (!importingClassMetadata.isInterface()) {
return new String[]{"com.example.UserConfig"};
}
// 此处不要返回null
return new String[]{"com.example.StudentConfig"};
}
}
该方法要求返回一个String数组,该数组的值为类的全包名。
应用场景:可以根据不同的情况来决定注入哪些类,在我们不考虑环境的情况下,可以直接@Bean注入类,也可以直接扫描, 而当我们考虑环境的情况下,就有可能某些类并不注入,而且甚至可能需要逻辑代码校验来决定, 那么就可以使用这个接口来进行逻辑代码校验并决定是否注入等。
ImportBeanDefinitionReqistar 注册bean
ImportBeanDefinitionRegistrar本质上是一个接口。在ImportBeanDefinitionRegistrar接口中, 有一个registerBeanDefinitions() 方法,通过registerBeanDefinitions()方法,我们可以向Spring容器中注册bean实例。
public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/* 假装这是我们扫描到的Mapper */
UserDao userDao;
/* 生成一个FactoryBean,Mybatis对应的 */
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestMyFactoryBean.class);
/* 从Builder中拿到BeanDefinition */
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
/* 添加构造器参数 */
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserDao.class.getName());
registry.registerBeanDefinition("userDao", beanDefinition);
}
}
使用 FactoryBean 注册对象
FactoryBean 和 BeanFactory 区别?
FactoryBean 往IOC容器中注入对象。
BeanFactory 从IOC容器获取bean对象。
后期基本不使用这种方式。
@Primary 与 @Qualifiler 区别
从下面的一个使用场景对应的解决方式来说明两个注解的区别。
当一个接口有多个实现类的时候,这时候使用 @Autowired 注解注入bean 时,这时候会报错,解决方式?
方式一:在其中的一个实现类上加上注解 @Primary ,表示为默认注入bean。
方式二:在使用 @Autowired 注解注入bean 时,@Qualifiler加上注解指定bean的名称。