首先@Import标签可以引入三种类,分别说明其作用
一.@Import(ImportSelector实现类.class)
实现接口ImportSelector,重写抽象方法selectImports,返回类全限定名字符串数组
下面针对返回类全限定名三种不同场景分析:
1.selectImports方法返回的类全限定名是普通类(即没有实现ImportSelector和ImportBeanDefinitionRegistrar接口)
①编写实现ImportSelector接口的子类MyImportSelector,重写抽象方法selectImports,返回普通类全限定名字符串
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回的User就是普通类
return new String[]{"cn.zhutan.test.import_anno.User"};
}
}
②在测试类中,用@Import标签引入MyImportSelector
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(value = {MyImportSelector.class})
public class DemoTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(DemoTest.class);
User user = ac.getBean(User.class);
System.out.println(user);
}
}
运行结果如下,表明可以从spring已经创建User对象,并且可以从容器中获取到User对象
结论:
当你返回的类是普通类时,spring后续就会根据你返回的类全限定名字符串解析和创建bean定义,创建bean对象等等一系列操作,然后放到spring容器中
2.返回的类是ImportSelector子类
①编写ImportSelector的子类OtherImportSelector,重写抽象方法selectImports,返回MyImportSelector全限定名字符串
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class OtherImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回的MyImportSelector是实现了ImportSelector接口的类
//而MyImportSelector的selectImports方法又返回了User类
return new String[]{"cn.zhutan.test.import_anno.MyImportSelector"};
}
}
②在测试类中,用@Import标签引入OtherImportSelector
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(value = {OtherImportSelector.class})
public class DemoTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(DemoTest.class);
User user = ac.getBean(User.class);
System.out.println(user);
MyImportSelector mis = ac.getBean(MyImportSelector.class);
System.out.println(mis);
//OtherImportSelector ois = ac.getBean(OtherImportSelector.class);
//System.out.println(ois);
}
}
运行结果如下,User对象可以从spring容器中拿到,但是MyImportSelector不能从spring中拿到,同理OtherImportSelector也不能拿到
结论:
当返回的类是ImportSelector子类时,创建该类对象后(只是创建了临时变量),调用完selectImports方法后,对象就销毁了,其实就是局部变量而已,不会放到spring容器中
3.返回的类是ImportBeanDefinitionRegistrar子类
①编写ImportBeanDefinitionRegistrar的实现类MyImportBeanDefinitionRegistrar,重写抽象方法registerBeanDefinitions,注册了User对象
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
/**
* 注册了User对象
*/
registry.registerBeanDefinition("user", beanDefinition);
}
}
②编写ImportSelector的子类AnOtherImportSelector,重写抽象方法selectImports,返回MyImportBeanDefinitionRegistrar全限定名字符串
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class AnOtherImportSelector implements ImportSelector{
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回实现了接口ImportBeanDefinitionRegistrar的子类MyImportBeanDefinitionRegistrar
return new String[]{"cn.zhutan.test.import_anno.MyImportBeanDefinitionRegistrar"};
}
}
③在测试类中,用@Import标签引入AnOtherImportSelector
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(value = {AnOtherImportSelector.class})
public class DemoTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(DemoTest.class);
User user = ac.getBean(User.class);
System.out.println(user);
MyImportBeanDefinitionRegistrar mibdr = ac.getBean(MyImportBeanDefinitionRegistrar.class);
System.out.println(mibdr);
}
}
运行结果如下,可以从spring容器中获取User对象,但是不能获取MyImportBeanDefinitionRegistrar对象
结论:
当返回的类是ImportBeanDefinitionRegistrar子类时,创建该类对象后(只是创建了临时变量)并put到了importBeanDefinitionRegistrars这个map中,后续执行registerBeanDefinitions方法创建了User对象放到了spring容器中,但是MyImportBeanDefinitionRegistrar本身不会放到spring容器中
二.@Import(ImportBeanDefinitionRegistrar实现类.class)
①编写ImportBeanDefinitionRegistrar的实现类MyImportBeanDefinitionRegistrar,重写抽象方法registerBeanDefinitions,注册User对象
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
/**
* 注册了User对象
*/
registry.registerBeanDefinition("user", beanDefinition);
}
}
②在测试类中,用@Import标签引入MyImportBeanDefinitionRegistrar
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(value = {MyImportBeanDefinitionRegistrar.class})
public class DemoTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(DemoTest.class);
User user = ac.getBean(User.class);
System.out.println(user);
MyImportBeanDefinitionRegistrar mibdr = ac.getBean(MyImportBeanDefinitionRegistrar.class);
System.out.println(mibdr);
}
}
运行结果如下,可以从spring容器中获取User对象,但是不能获取MyImportBeanDefinitionRegistrar对象
结论:
实现接口ImportBeanDefinitionRegistrar,重写抽象方法registerBeanDefinitions,参数中提供了注册器,可以向容器中注册相关bean,但是从下面源码可以知道,实现ImportBeanDefinitionRegistrar的子类首先会put到importBeanDefinitionRegistrars这个map中,后续会取出importBeanDefinitionRegistrars调用registerBeanDefinitions方法,进行注册bean,MyImportBeanDefinitionRegistrar本身不会放到spring容器中
三.@Import(普通类.class)
①创建User对象
public class User {
}
②在测试类中,用@Import标签引入User
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(value = {User.class})
public class DemoTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(DemoTest.class);
User user = ac.getBean(User.class);
System.out.println(user);
}
}
运行结果如下,User对象可以从spring容器拿出来
结论:
普通对象会解析创建然后放到spring容器中
核心源码如下:
ConfigurationClassParser解析@Import标签,下面贴出核心方法
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
/**
* 处理ImportSelector
*/
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
/**
* 如果是这个接口的实现类DeferredImportSelector,那么就添加到集合中,延迟执行
*/
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
/**
* 这里调用了ImportSelector.selectImports方法
*/
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
/**
* 处理ImportBeanDefinitionRegistrar
*/
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
Class<?> candidateClass = candidate.loadClass();
// delegate to it to register additional bean definitions
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
/**
* 添加了ImportBeanDefinitionRegistrar到集合中,还未执行,后面会执行
*/
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
/**
* 处理普通的Import
*
* 注意:只有不实现ImportSelector和不实现ImportBeanDefinitionRegistrar的普通类才会注册解析并且注册到spring容器中
* (意思就是只要实现了ImportSelector和ImportBeanDefinitionRegistrar其中一个接口,即使贴上了@Configuration注解,也不解析该配置)
*/
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
/**
*
*/
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
总结:
不会放到spring容器中的情况:
1.使用@Import标签引入的ImportSelector或ImportBeanDefinitionRegistrar的实现类本身不会放到spring容器中
2.使用@Import标签引入的ImportSelector实现类,对应的实现方法selectImports返回的类,如果还是ImportSelector或者ImportBeanDefinitionRegistrar实现类,也不会放到容器中
放到spring容器中的情况:
1.直接通过@Import引入没有实现ImportSelector和ImportBeanDefinitionRegistrar接口的普通类
2.使用@Import引入一个ImportSelector实现类,selectImports方法返回没有实现ImportSelector和ImportBeanDefinitionRegistrar接口的普通类全限定名字符串
3.使用@Import引入ImportBeanDefinitionRegistrar的实现类,直接用方法registerBeanDefinitions中参数registry注册器,注册bean到spring容器中