1.引入
在开始介绍之前我们先了解一个问题:将一个类交给spring容器管理有哪些方式?
<bean id = "indexDao" class = "com.hz.dao.IndexDao">
说明:这种方式比较简单,相当于直接new了一个对象即 IndexDao indexDao = new IndexDao();
@Configuration
public class AppConfig {
@Bean
public IndexDao indexDao(){
return new IndexDao();
}
}
说明:这里加@Configuration注解和不加此注解有很大区别,后面会专门做讲解
- 方式三:使用@Import注解
说明:在类上面加Import注解,该注解通过快速导入的方式实现将类加入到spring容器中
2. @Import
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
3. @Import注解用法
3.1 导入普通类
public interface MyBaseDao {
void query();
}
public class IndexDao1 implements MyBaseDao {
@Override
public void query(){
System.out.println("<===> indexDao1");
}
}
@ComponentScan({"study"})
@Import(IndexDao1.class)
public class AppConfig {
}
public class Test2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.refresh();
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
- 测试结果
3.2 与ImportSelector接口配合使用
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{IndexDao3.class.getName()};
}
}
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportSelector.class)
public @interface EnableImport {
}
@ComponentScan({"study"})
@EnableImport
public class AppConfig {
}
public class Test2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.refresh();
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
- 测试结果
4.源码解析
- 入口处断点放在refresh()这里,我们可以看到此时beanDefinitionNames的size=6,也就是说register方法已经将我们AppConfig类注册到BeanDefinitionMap中了,具体过程可以debug register方法进行跟踪查看,这里不过多解释
- refresh()->invokeBeanFactoryPostProcessors(beanFactory) :执行自定义的ProcessBeanFactory 和spring内部自己定义的ProcessBeanFactory
- 进入AbstractApplicationContext # invokeBeanFactoryPostProcessors()
这个地方需要注意getBeanFactoryPostProcessors()是获取手动给spring的BeanFactoryPostProcessors - 继续跟进PostProcessorRegistrationDelegate #invokeBeanFactoryPostProcessors()
可以看到size =1 ,该方法是执行所有BeanDefinitionRegistryPostProcessor - 继续跟进到configurationClassPostProcessor # processConfigBeanDefinitions()
这里parser.parse()方法只会解析一个我们注册的类AppConfig - 继续跟进
图中划线方法是解析注解对象,并把解析处理的beanDefinition方法map中
- 前方高能
这个方法就是处理@Import注解的
说明:在处理实现ImportSelector接口的类是用到了递归处理,因为实现了此接口的类也有可能 使用了@ Improt注解
|