在学习源码的过程中,读到@Import注解的时候,发现其底层有三种解析方式。进入到@Import注解中看到spring的说明如下
/**
* Indicates one or more <em>component classes</em> to import — 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源码的时候,再详细探讨。