在學習源碼的過程中,讀到@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源碼的時候,再詳細探討。