18.spring源码之@Import注解

上篇文章讲了@ComponentScan,今天接着代码往后走

1.doProcessConfigurationClass()方法

2.进入processImports()方法

2.1如果Import导入的类是一个ImportSelect类型且是DeferredImportSelect类型,进入handle()方法

把这个类以及实例对象封装成一个DefreedImportSelectorHander()对象

进入register()方法

进入processGroupImport()方法

进入getImports()方法

2.2如果是一个ImportSelect,则调用它的selectImport()方法,把返回的类名封装成sourceClass,调用preocessImport()进行递归处理,因为方法返回的类上可以又有Import()注解

2.3如果是一个ImportBeanDefinitionRegistrar类型,实例化,然后放入一个容器,看addImportBeanDefinitionRegistrar()方法

这个容易的key是一个实现了ImportBeanDefinitionRegistrat接口的对象,value是他的metadata对象

2.4只是单纯的一个Import导入的类,没有实现上述的那些接口,调用processConfigurationClass()方法进行递归

asConfigClass()方法会把有@Import注解的这个类放入importedBy这个容器,前面@Component注解的内部类也会放入这个容器

进入processConfgurationClass()方法

进行递归处理,sourceClass为null的时候把configClass放入configurationClasses这个容器中。

@Import注解,相对而言有点复杂,我们举例来理解源码

3.示例1

创建一个类使用Import注解导入一个类

导入的类如下

测试

4.示例2

创建一个类是实现ImportSelector接口

这个方法返回的类的全限定名的类对应如下

创建一个类使用@Import注解导入是实现了ImportSelector接口的ImportSelectorBean类

 

结合源码与测试结果我们可以知道:

1.如果Import导入的类实现了ImportSelector接口,那么会调用它的selectImports()方法,ByImportSelectorBean导入了ImportSelectorBean,那么在ImportSelectorBean的selectImports()方法中可以获取ByImportSelectorBean类上面的注解信息

2.selectImports()方法返回的类Mico会被实例化,但是实现了ImportSelector接口的类ImportSelectorBean不会被实例化,

通过源码可以知道processImport()递归处理的是selectImports()方法返回的类Mico.class,如果想要ImportSelectorBean要实例化,那么需要加上@Component注解,或者不实现ImportSelector接口。

5.示例三

创建一个类实现DeferredImportSelector接口

创建一个类导入上面这个类

测试

根据测试结果,可以知道,如果Import导入的类实现了DeferredImportSelector,会先调用getImportGroup()方法,然后调用process()方法,再调用selectImports()方法

再次分析源码

这里调用了getimportGroup()方法,示例中返回的是DeferredImportSelectorGroupDemo.class,这是示例中的内部类,实现了Group接口,如果示例中没有重写getImportGroup方法,那么这里group就是为空,那么建立的映射关系就是DeferredImportSelectorBean和默认的实现了Group接口的实现类的映射关系。

再看processGroupImports()方法

 

调用DeferredImportSelectorGroupDemo对象的process方法和selectImports()方法。但是如果示例中没有重写getImportGroup方法,那么这么的group就是spring默认的实现了Group接口的对象DefaultDeferredImportSelectorGroup,我们看它的process方法

直接selector.selectImports(),这个selector就是我们实现了DeferredImportSelector接口的DeferredImportSelectorBean的示例对象。没有重写getImportGroup()方法的示例如下:

 

测试结果,直接调用了DeferredImportSelectorBean的selectImports()方法。

实在是不好用文字描述示例,总结一下吧:

如果A通过Import导入了B,那么B会 被实例化。

如果A通过Import导入了B,但是B实现了ImportSelector接口,那么B的selectImports()方法会被调用,且该方法中返回的类会被实例化,但是B不会被实例化,想要B被实例化,需要加上@Component注解。

如果A通过Import导入了B,但是B实现了DeferredImportSelector接口,会调用B的selectImports()方法,但是如果B中重写了getImportGroup()方法,该方法是返回一个实现了Group接口的类,假设为C,那么会先调用B的getImportGroup()方法,然后调用C的process()方法,再调用C的selectImports()方法。

如果A通过Import导入了B,但是B实现了ImportBeanDefinitionRegistrar接口,那么会调用B的registryBeanDefinitions()方法,调用该方法的时机不是今天讲的代码当中,后续在讲。

posted @ 2021-08-15 18:18  福福猿  阅读(166)  评论(0)    收藏  举报