您的位置:首页 > 编程语言 > Java开发

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

2018-03-27 18:00 1011 查看
在上一篇中我们分析了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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐