spring-context注解源码系列七——@ImportResource

注解说明

Indicates one or more resources containing bean definitions to import.
指定导入一个或者多个包含了 BeanDefinition 的文件。

ImportResource和Import区别:

Import(详细说明点击查看)支持导入Class文件;ImportResource则可以导入任何类型的配置文件,默认是支持导入xml和groovy文件,如果要导入其他格式的文件,需要传入自定义的BeanDefinitionReader。
spring自带3种BeanDefinitionReader,它们分别是:XmlBeanDefinitionReader、PropertiesBeanDefinitionReader、GroovyBeanDefinitionReader。

属性说明

	/**
	 * 同locations
	 */
	@AliasFor("locations")
	String[] value() default {};

	/**
	 * 需要被导入的资源的路径
	 */
	@AliasFor("value")
	String[] locations() default {};

	/**
	 * 自定义资源解析器
	 */
	Class<? extends BeanDefinitionReader> reader() default BeanDefinitionReader.class;

使用示例

@SpringBootApplication
@ImportResource(locations={"classpath:/spring/*.xml"})
public class BackApplication {
    public static void main(String[] args) {
        SpringApplication.run(BackApplication.class, args);
    }
}

相关源码

ConfigurationClassParser

	/**
	 * Apply processing and build a complete {@link ConfigurationClass} by reading the
	 * annotations, members and methods from the source class. This method can be called
	 * multiple times as relevant sources are discovered.
	 * @param configClass the configuration class being build
	 * @param sourceClass a source class
	 * @return the superclass, or {@code null} if none found or previously processed
	 *
	 * 读取配置类中的注解、内部类、方法来完成配置类的解析
	 */
	@Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
		
		......
		
		// Process any @ImportResource annotations
		// 处理ImportResource注解,将locations的内容和reader对应的资源解析器放在importedResources存起来
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			// 取出配置的资源路径
			String[] resources = importResource.getStringArray("locations");
			// 取出解析器的类型
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				// 根据配置生成真正的资源路径
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				// 把信息放到配置类的importedResources中
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		......

		// No superclass -> processing is complete
		return null;
	}

ConfigurationClassBeanDefinitionReader

	/**
	 * Read a particular {@link ConfigurationClass}, registering bean definitions
	 * for the class itself and all of its {@link Bean} methods.
	 *
	 * 读取并注册单个配置类中的beanDefinition
	 */
	private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		......

		// 解析@ImportResource导入的资源文件(配置类的importedResources)并转化为BeanDefinition
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		
		......
	}
	/**
	 * 解析@ImportResource导入的资源文件并转化为BeanDefinition
	 */
	private void loadBeanDefinitionsFromImportedResources(
			Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

		Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();

		importedResources.forEach((resource, readerClass) -> {
			// Default reader selection necessary?
			// 如果没有设置解析器,则根据文件的后缀名选择对应的解析器
			if (BeanDefinitionReader.class == readerClass) {
				// 如果后缀名是 groovy,则使用 GroovyBeanDefinitionReader,否则使用 XmlBeanDefinitionReader
				if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
					// When clearly asking for Groovy, that's what they'll get...
					readerClass = GroovyBeanDefinitionReader.class;
				}
				else {
					// Primarily ".xml" files but for any other extension as well
					readerClass = XmlBeanDefinitionReader.class;
				}
			}

			BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
			if (reader == null) {
				try {
					// Instantiate the specified BeanDefinitionReader
					// 如果之前没有创建过解析器,则先创建解析器并缓存起来
					reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
					// Delegate the current ResourceLoader to it if possible
					if (reader instanceof AbstractBeanDefinitionReader) {
						AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
						abdr.setResourceLoader(this.resourceLoader);
						abdr.setEnvironment(this.environment);
					}
					readerInstanceCache.put(readerClass, reader);
				}
				catch (Throwable ex) {
					throw new IllegalStateException(
							"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
				}
			}

			// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
			// 使用对应的解析器解析配置文件
			reader.loadBeanDefinitions(resource);
		});
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值