spring源码-注解启动分析

@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的名称。
在这里插入图片描述


版权声明:本文为weixin_44044929原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。