SpringBoot源码分析之BeanDefinitionLoader注册主Configuration的Java配置类

在上一篇中我们分析了SpringBootApplication的启动过程,在启动过程中通过调用BeanDefinitionLoader的load()方法来加载sources资源,也就是Application.class类。为了直观起见,还是将之前的示例写出来。

@SpringBootApplication
public class Application {
	/**
	 * 启动Spring Boot应用
	 */
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

SpringApplication.run()中的prepareContext() 

private void prepareContext(ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
   context.setEnvironment(environment);
   postProcessApplicationContext(context);
   applyInitializers(context);
   listeners.contextPrepared(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }

   // Add boot specific singleton beans
   context.getBeanFactory().registerSingleton("springApplicationArguments",
         applicationArguments);
   if (printedBanner != null) {
      context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
   }

   // Load the sources 加载Application.class
   Set<Object> sources = getSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   load(context, sources.toArray(new Object[sources.size()]));//主要方法
   listeners.contextLoaded(context);
}
protected void load(ApplicationContext context, Object[] sources) {
   if (logger.isDebugEnabled()) {
      logger.debug(
            "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
   }//创建BeanDefinitionLoader
   BeanDefinitionLoader loader = createBeanDefinitionLoader(
         getBeanDefinitionRegistry(context), sources);
   if (this.beanNameGenerator != null) {
      loader.setBeanNameGenerator(this.beanNameGenerator);
   }
   if (this.resourceLoader != null) {
      loader.setResourceLoader(this.resourceLoader);
   }
   if (this.environment != null) {
      loader.setEnvironment(this.environment);
   }
   loader.load();//该方法中加载注册Application.class进applicationContext
}

Application.class作为sources传入到SpringApplication中,最终处理sources的是BeanDefinitionLoader的load()方法。下面开始分析BeanDefinitionLoader。

BeanDefinitionLoader分析

BeanDefinitionLoader的构造方法如下:

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
	// Bean注册器和sources必须不为空
	Assert.notNull(registry, "Registry must not be null");
	Assert.notEmpty(sources, "Sources must not be empty");
	this.sources = sources;
	// 注解形式的Bean定义读取器
	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
	// XML形式的Bean定义读取器
	this.xmlReader = new XmlBeanDefinitionReader(registry);
	// Groovy形式的Bean定义读取器
	if (isGroovyPresent()) {
		this.groovyReader = new GroovyBeanDefinitionReader(registry);
	}
	// 类路径扫描器
	this.scanner = new ClassPathBeanDefinitionScanner(registry);
	// 扫描器添加排除过滤器
	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

在构造方法中我们可以知道,准备了几种Bean定义读取器,可以通过不同的方式来读取定义的Bean,以及提供了包扫描器。下面我们看看load()方法,看支持对哪些形式的Bean的加载。

public int load() {
	int count = 0;
	for (Object source : this.sources) {
		count += load(source);
	}
	return count;
}

private int load(Object source) {
	Assert.notNull(source, "Source must not be null");
	if (source instanceof Class<?>) {
		return load((Class<?>) source);
	}
	if (source instanceof Resource) {
		return load((Resource) source);
	}
	if (source instanceof Package) {
		return load((Package) source);
	}
	if (source instanceof CharSequence) {
		return load((CharSequence) source);
	}
	throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

从上面的方法很清楚看出,BeanDefinitionLoader可以从Class、Resource、Package和CharSequence中进行加载。对于我们上面的应用Application.class使用的是Class形式的加载。

说明: 对于Groovy部分我们不做分析。

加载Class

加载Class的方法如下:

private int load(Class<?> source) {
	if (isComponent(source)) {
		this.annotatedReader.register(source);
		return 1;
	}
	return 0;
}

首先通过isComponent方法进行判断,是否符合加载条件,然后使用注解形式的Bean定义读取器进行注册。isComponent方法主要判断source是否使用了@Component注解,另外,内部类不能加载。

在上面的示例中Application.class使用了@SpringBootApplication注解,@SpringBootApplication注解包含了@Component注解。关于@SpringBootApplication注解后面再详细分析。

加载Resource

使用XML形式的Bean定义读取器进行加载。

private int load(Resource source) {
	if (source.getFilename().endsWith(".groovy")) {
		if (this.groovyReader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load Groovy beans without Groovy on classpath");
		}
		return this.groovyReader.loadBeanDefinitions(source);
	}
	return this.xmlReader.loadBeanDefinitions(source);
}

加载Package

使用包扫描器进行加载。

private int load(Package source) {
	return this.scanner.scan(source.getName());
}

加载CharSequence

这种形式实际上可以等同于sources为字符串,根据解析sources,进行匹配Class、Resource或Package进行加载。具体细节不分析了,原理一样。

private int load(CharSequence source) {
	String resolvedSource = this.xmlReader.getEnvironment()
			.resolvePlaceholders(source.toString());
	// 尝试使用Class加载
	try {
		return load(ClassUtils.forName(resolvedSource, null));
	}
	catch (IllegalArgumentException ex) {
		// swallow exception and continue
	}
	catch (ClassNotFoundException ex) {
		// swallow exception and continue
	}
	// 尝试使用Resource加载
	Resource[] resources = findResources(resolvedSource);
	int loadCount = 0;
	boolean atLeastOneResourceExists = false;
	for (Resource resource : resources) {
		if (isLoadCandidate(resource)) {
			atLeastOneResourceExists = true;
			loadCount += load(resource);
		}
	}
	if (atLeastOneResourceExists) {
		return loadCount;
	}
	// 尝试使用Package加载
	Package packageResource = findPackage(resolvedSource);
	if (packageResource != null) {
		return load(packageResource);
	}
	throw new IllegalArgumentException("Invalid source '" + resolvedSource + "'");
}

BeanDefinitionLoader定义了不同形式的方式来对SpringApplication中的sources进行加载。

  • 加载Class。也就是我们使用的加载类注解的方式来加载Bean定义。
  • 加载Resource。典型的就是加载application.xml Bean配置文件。
  • 加载Package。以扫包的方式加载Bean定义。

AnnotatedBeanDefinitionReader分析

在上面我们分析过,当我们使用SpringApplication.run(Application.class, args)开始启动Spring Boot时,最终使用AnnotatedBeanDefinitionReader的register(Class<?>... annotatedClasses)方法进行注册Bean。在createContext()方法中context初始化时创建AnnotatedBeanDefinitionReader时已经调用过AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry),  见 https://blog.csdn.net/liaokailin/article/details/49048557

AnnotatedBeanDefinitionReader构造方法

我们还是从构造方法开始分析,AnnotatedBeanDefinitionReader的构造方法如下:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	// registry和environment是肯定不能为空
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
	this.registry = registry;
	// 条件评估器
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	// 使用注解配置时需要注入的一些后置处理器
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

注解配置时必须的后置处理器

首先,在AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)中向Spring容器注入了注解配置时需要使用的后置处理器。代码如下:

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, Object source) {

	// 将工厂使用的比较器和解析器设置成注解形式的实例
	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
	
	// 判断注册器中是否存在Spring内置的ConfigurationClassPostProcessor类型的Bean	// 如果没有则添加到注册器中
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// 判断注册器中是否存在Spring内置的AutowiredAnnotationBeanPostProcessor类型的Bean
	// 如果没有则添加到注册器中
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// 省略了其他的Bean注册

	return beanDefs;
}

在能够使用AnnotatedBeanDefinitionReader开始对注解类注册Bean之前,Spring加入了一系列的BeanPostProcessor处理器。至于有哪些处理器,我们目前不关心。

注册Bean

在构造方法之后,开始对注解类进行注册,在我们的示例中也就是对Application.class进行注册处理。注册方法如下:

public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
	// 包装注解类
	AnnotatedGenericBeanDefinition abd =new AnnotatedGenericBeanDefinition(annotatedClass);
	// 判断是否应该跳过注册Bean
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	// 获取Scope元数据信息
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	// 生成Bean名称
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
	// 处理一些公共的注解
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
	
	// 创建Bean定义对象holder暂时保存对象
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	// 代理类
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	// 注册到Spring中
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

条件跳过Bean注册

下面我们需要看一下ConditionEvaluator的shouldSkip方法,该方法处理了是否需要跳过注册。在该方法中首先会检测是否是属于@Conditional注解,@Conditional注解可以包含Condition接口集合,根据这个接口集合来判断是否符合Bean的注册。方法如下:

public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
	// 首先判断是否属于@Conditional类型注解
	if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
		return false;
	}

	if (phase == null) {
		if (metadata instanceof AnnotationMetadata &&
				ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
			return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
		}
		return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
	}

	// 从@conditional中获取Condition集合
	List<Condition> conditions = new ArrayList<Condition>();
	for (String[] conditionClasses : getConditionClasses(metadata)) {
		for (String conditionClass : conditionClasses) {
			Condition condition = getCondition(conditionClass, this.context.getClassLoader());
			conditions.add(condition);
		}
	}
	
	// 进行排序
	AnnotationAwareOrderComparator.sort(conditions);

	// 一旦发现有不匹配的Condition就表示需要跳过注册
	for (Condition condition : conditions) {
		ConfigurationPhase requiredPhase = null;
		if (condition instanceof ConfigurationCondition) {
			requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
		}
		if (requiredPhase == null || requiredPhase == phase) {
			if (!condition.matches(this.context, metadata)) {
				return true;
			}
		}
	}

	return false;
}

在上面的代码分析中,我们使用的Application.class对象,最后被处理成AnnotatedGenericBeanDefinition对象,然后被注册到Spring容器中去。

参考于 https://my.oschina.net/xiaoqiyiye/blog/1624227

猜你喜欢

转载自blog.csdn.net/Bob_666/article/details/79716954
今日推荐