Spring拾遗(三)——ImportSelector和ImportBeanDefinitionRegistrar

在学习源码的过程中,读到@Import注解的时候,发现其底层有三种解析方式。进入到@Import注解中看到spring的说明如下

/**
 * Indicates one or more <em>component classes</em> to import &mdash; typically
 * {@link Configuration @Configuration} classes.
 *
 * 这里说明了,@Import注解中可以指定ImportSelector和ImportBeanDefinitionRegistrar
 * <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
 * Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
 * {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
 * classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
 *
 * <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
 * accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
 * injection. Either the bean itself can be autowired, or the configuration class instance
 * declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
 * navigation between {@code @Configuration} class methods.
 *
 * <p>May be declared at the class level or as a meta-annotation.
 *
 * <p>If XML or other non-{@code @Configuration} bean definition resources need to be
 * imported, use the {@link ImportResource @ImportResource} annotation instead.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.0
 * @see Configuration
 * @see ImportSelector
 * @see ImportResource
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	Class<?>[] value();

}

从spring的注释中可以看到这个注解支持ImportSelector和ImportBeanDefinitionRegistrar,但是这两个具体有什么区别,就是我们这篇博客需要讨论的。

ImportSelector

这里直接上实例,我们自己实现一个Selector,实现这个接口中的方法

/**
 * autor:liman
 * createtime:2020/3/21
 * comment:
 */
public class TestImportSelector implements ImportSelector {

    /**
     * 这个方法,单纯的返回需要注册的bean的全路径名,spring会自动注入进工厂,
     * @param annotationMetadata 这个参数是可获取bean上的注解内容
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{TestBean.class.getName()};
    }
}

不太重要的TestBean

/**
 * autor:liman
 * createtime:2020/3/21
 * comment:
 */
@Component
public class TestBean {

    public void testImportSelectorBean(){
        System.out.println("this is test bean for import selector");
    }

}

关于Import中的具体实现,这里在spring源码中可以看到相关实现,这里不再贴出。

ImportBeanDefinitionRegistrar

依旧直接上实例,自己实现的ImportBeanDefinitionRegistrar,实现了该接口中的方法

/**
 * autor:liman
 * createtime:2020/3/15
 * comment: 自己实现的ImportBeanDefinitionRegistrar
 */
public class SelfBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        Class testBeanClazz = TestBean.class;
        //自己构建BeanDefinition,将其交给spring托管,这个构建BeanDefinition的方法在spring源码中很常见。
        RootBeanDefinition testBeanDefinition = new RootBeanDefinition(testBeanClazz);
        String beanName = StringUtils.uncapitalize(testBeanClazz.getName());
        registry.registerBeanDefinition(beanName,testBeanDefinition);
    }
}

其余和ImportSelector一样,具体的Config类如下:

/**
 * autor:liman
 * createtime:2020/2/25
 * comment:
 */
@Configuration
@ComponentScan(value="com.learn.importselector")
//@Import(TestImportSelector.class) 如果需要测试ImportSelector,可以用这个
@Import(SelfBeanDefinitionRegistry.class)
public class AppConfig {
}

一个简单的小结

从功能上看,两者似乎差不多,最大的区别似乎就是ImportSelector是将类的全路径名直接注册给Spring的IOC,而ImportBeanDefinitionRegistrar就是通过BeanDefinition注册给spring。这里抛出一个问题,我们在使用MyBatis框架的时候,似乎并没有实现类,但是Spring却能完美的给我们注册相关的实现类,这是如何做到的?其实走到这里,应该能猜到,其实MyBatis的底层就是通过实现了ImportBeanDefinitionRegistrar来实现的,在构建真正需要注册进入到IOC的实现类之前,MyBatis动态实现了我们指定的数据访问层的接口,然后将其构建BeanDefinition并注入到了IOC中,这一点我们在阅读MyBatis源码的时候,再详细探讨。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章