@Import注解详解

@Import注解提供了三种用法

1、@Import一个普通类 spring会将该类加载到spring容器中

2、@Import一个类,该类实现了ImportBeanDefinitionRegistrar接口,在重写的registerBeanDefinitions方法里面,能拿到BeanDefinitionRegistry bd的注册器,能手工往beanDefinitionMap中注册 beanDefinition

3、@Import一个类 该类实现了ImportSelector 重写selectImports方法该方法返回了String[]数组的对象,数组里面的类都会注入到spring容器当中

接下来挨个测试:

场景一  import普通类

1. 自定义一个类 没有任何注解

public class MyClass {
	
	public void test() {
		System.out.println("test方法");
	}
}

2. 写一个importConfig类 import这个myClass类

@Import(MyClass.class)
public class ImportConfig {
	
}

 3. 通过AnnotationConfigApplicationContext 初始化spring容器 调用test方法 看输出, MyClass类被加载进了 spring容器当中

场景二、 实现ImportBeanDefinitionRegistrar

 1. 创建一个普通类MyClassRegistry

public class MyClassRegistry {
	
	public void test() {
		System.out.println("MyClassRegistry test方法");
	}
}

 2. 创建MyImportRegistry 实现ImportBeanDefinitionRegistrar接口 注册我们定义的普通类MyClassRegistry

public class MyImportRegistry implements ImportBeanDefinitionRegistrar{
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		RootBeanDefinition bd = new RootBeanDefinition();
		bd.setBeanClass(MyClassRegistry.class);
		registry.registerBeanDefinition("myClassRegistry", bd);
	}
}

 3. import该类

@Import(MyImportRegistry.class)
public class ImportConfig {
	
}

 4. 执行main方法 查看输出

 

 场景三、 实现ImportSelector

  1. 创建一个普通类MyClassImport 

public class MyClassImport {
	
	public void test() {
		System.out.println("MyClassImport test方法");
	}
}

   2. 创建MyImportSelector实现ImportSelector接口 注册我们定义的普通类MyClassImport

public class MyImportSelector implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return new String[] {MyClassImport.class.getName()};
	}

}

  3. import该类

@Import(MyImportSelector.class)
public class ImportConfig {
	
}

  4. 执行main方法 查看输出

场景二应用于spring-mybatis当中 扫描dao信息 生成代理类信息

场景三应用于springboot的自动装配当中 加载自动装配需要的类信息

源码分析:

org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClass, SourceClass, Collection<SourceClass>, boolean)方法中 就是处理Import注解类引入的bd信息

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) {
					if (candidate.isAssignable(ImportSelector.class)) {//拿ImportSelector类
					
						Class<?> candidateClass = candidate.loadClass();//获得class信息
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						if (selector instanceof DeferredImportSelector) {//判断是否是延迟加载的ImportSelector对象
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());//拿到selectImports方法返回的类信息
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {//扫描到类是继承ImportBeanDefinitionRegistrar 将配置类封装成ConfigurationClass类 后续会处理
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					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();
			}
		}
	}

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set<ConfigurationClass>)

在loadBeanDefinitions中会调用loadBeanDefinitionsFromRegistrars方法  最终执行到实现类的registerBeanDefinitions方法  继而将自定义的bd注册到beanDefinitionMap当中 交给spring去初始化

  • 33
    点赞
  • 126
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
@Import注解Java中用于导入其他配置类或组件的注解,它可以用在类级别上,用于导入其他类或组件,从而让它们成为当前类的依赖项。@Import注解支持三种不同的导入方式: 1. 导入配置类: 可以使用@Import注解来导入一个或多个配置类,这些配置类会被Spring容器加载并且进行解析,从而可以在应用程序中使用。例如: ``` @Configuration @Import({Config1.class, Config2.class}) public class AppConfig { // Configuration code... } ``` 在上面的例子中,AppConfig类使用@Import注解来导入了Config1和Config2两个配置类。 2. 导入普通的组件: 除了导入配置类外,@Import注解还可以用来导入普通的组件,例如一个普通的Java类、接口或枚举。例如: ``` @Configuration @Import(MyComponent.class) public class AppConfig { // Configuration code... } ``` 在上面的例子中,AppConfig类使用@Import注解来导入了一个名为MyComponent的普通Java组件。 3. 导入ImportSelector: @Import注解还可以使用ImportSelector类型的实现类来动态地导入一组组件,这些组件可以根据不同的条件进行选择。例如: ``` @Configuration @Import(MyImportSelector.class) public class AppConfig { // Configuration code... } ``` 在上面的例子中,AppConfig类使用@Import注解来导入了一个名为MyImportSelector的ImportSelector实现类,它会根据不同的条件来选择一组组件,然后将它们动态导入到应用程序中。 总之,@Import注解是一个非常有用的注解,它可以帮助我们方便地导入其他配置类或组件,从而让我们的应用程序更加灵活和可扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值