文章目录
前言
本篇章仅仅就讲一个方法的调用流程,这里当然还是涉及到了其他知识点,建议先看一下
- ApplicationContext-2
- AnnotationMetadata 注解元数据
- BeanDefinition
register
用于注册我们的启动类,简单来说其实就是用于注册 带有@ComponentScan
注解的 目标类,当然不带也无所谓,只是简简单单注册一个Bean而已,但是这个方法的主要作用其实还是 为了注册 一个目标类,
代码分析
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//主要分析这段代码
register(componentClasses);
}
调用register()
看到这里我们可以清晰的了解到 其实还是委托为 AnnotatedBeanDefinitionReader 去做了
@Override
public void register(Class<?>... componentClasses) {
this.reader.register(componentClasses);
}
调用register()
this.reader
指的我们最开始创建的AnnotatedBeanDefinitionReader
对象
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
调用doRegisterBean()
- 传递了我们扫描的Class
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
// 将Bean配置类信息转成容器中 AnnotatedGenericBeanDefinition 数据结构,
// AnnotatedGenericBeanDefinition 继承自 BeanDefinition 作用是定义一个bean的数据结构,
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// getMetadata可以获取到该bean上的元数据
// @Conditional 装配条件判断是否需要跳过注册,如果是跳过注册则不会将当前Bean注入到Spring容器中
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//在初始化的时候为Null
abd.setInstanceSupplier(supplier);
//解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//生成bean配置类beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//通用注解解析到 abd 结构中,主要是处理 Lazy, primary DependsOn, Role ,Description 这五个注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// @Qualifier 特殊限定符处理,
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
// 如果配置@Primary注解,则设置当前 Bean为 自动装配 autowire 时首选bean
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
//设置当前bean为延迟加载
abd.setLazyInit(true);
} else {
//其他注解,则添加到abd结构中
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
//初始化是不会走这个方法的
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
//自定义bean添加到BeanDefinition
customizer.customize(abd);
}
}
//这类:简单理解就是将 AnnotatedGenericBeanDefinition 和beanName 做一个映射
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//创建代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 用于保存注bean定义信息(beanname 和 beandefine映射)
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
判断是否需要跳过-shouldSkip()
- shouldSkip()
- shouldSkip()
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 如果元数据是一个 null 或者 不存在 @Conditional 注解
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
// 第一次进来本来就是NUll~~
if (phase == null) {
// 判断 matadata
// 并且 是特定注解
if (metadata instanceof AnnotationMetadata &&
// 判断不是接口 是一些特定的注解 或者 包含了 @Bean注解的 方法的
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
// @Configuration 配置类的处理
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
// 只有 @Conditional 注解的处理
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
// 要解析的配置类的条件集合
List<Condition> conditions = new ArrayList<>();
//获取 @Conditional 注解的里面的所有 条件类全限定类名
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 获取条件对象,这里可以理解为 @Conditional({A.class}) 这个A 类型的 对象,由于我们的A类实现了 Condition 这个接口,所以在上传直接进行了强转
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
//添加到集合当中去
conditions.add(condition);
}
}
// 排序
AnnotationAwareOrderComparator.sort(conditions);
// 遍历conditions,进行判断
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
// 判断是不是实现了这个接口的 这个接口 比 Condition 更加高级一点
if (condition instanceof ConfigurationCondition) {
// 执行这个方法
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
//阶段不满足条件的话,返回true并跳过这个bean的解析
if ((requiredPhase == null || requiredPhase == phase) &&
// 去执行控制的方法,如果返回的 true 则代表可以创建,如果返回 false 认为不可以创建
// 不可以创建 结果取反 !false 就是 true
!condition.matches(this.context, metadata)) {
// 返回 true 不进行创建
return true;
}
}
return false;
}
解析Scope元数据-resolveScopeMetadata()
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
//创建一个 @Scope 注解的元数据
ScopeMetadata metadata = new ScopeMetadata();
//判断是不是 这个类型,在初始化的时候 已经将我们的对象转成了 AnnotatedBeanDefinition 类型
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
//这里是去解析注解去了
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
// 属性不为 null
if (attributes != null) {
//获取其 @Scope.value 属性
metadata.setScopeName(attributes.getString("value"));
//获取其 @Scope.proxyMode 属性
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
// 如果 @Scope.proxyMode == 默认值的话
if (proxyMode == ScopedProxyMode.DEFAULT) {
//将其设置为 ScopedProxyMode.NO 这个值是在构造函数创建的~~
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
调用registerBeanDefinition()
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//获取BeanName
String beanName = definitionHolder.getBeanName();
//注册到spring容器中,这个方法我们在注册 后置处理器的时候已经分析过了
//1. name 和 BeanDefinition 放到 beanDefinitionMap中
//2. name 存到 beanDefinitionNames 中
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//获取Bean的别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
springboot
springboot 最终也是调用大致的流程,只贴前置流程的源码
调用流程
项目启动
@SpringBootApplication
public class SpringIocApplication {
public static void main(String[] args) {
SpringApplication.run(SpringIocApplication.class, args);
}
}
调用run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
- 内部调用 run 方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
- 创建对象
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(
ResourceLoader resourceLoader,
Class<?>... primarySources) {
// 将 我们的 启动类,放到集合中 然后设置给 primarySources 这个属性
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
}
- 然后调用run 方法
public ConfigurableApplicationContext run(String... args) {
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
}
剩余流程
剩余流程就不贴代码了,自己可以跟一下,为啥上面贴呢,主要是将 将启动类放到 primarySources
集合中
-
调用 prepareContext 方法
- 调用 getAllSources 方法 获取 启动类集合~~
-
调用 load()
-
调用 load()
-
调用 load()
-
调用 load()
-
调用 annotatedReader.register(source);
-
循环调用 registerBean()
-
调用 doRegisterBean()
扩展阅读
通过源码分析,我们传递的扫描类,最终将我们的Bean,处理完成后放进了beanDefinitionMap
和beanDefinitionNames
,
不依托AnnotationConfigApplicationContext
单独调用这个方法看看,
public class RegisterContext {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader definitionReader = new AnnotatedBeanDefinitionReader(beanFactory);
definitionReader.register(User.class);
User bean = beanFactory.getBean(User.class);
System.out.println(bean);
}
}
@Conditional(Person.class)
class User {
}
//用于控制 User 是否注册
class Person implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 返回 true 就会注入,返回 false 就不会注册 User 这个Bean,如果没注册在获取的时候会出现问题...
return false;
}
}
流程图
- 从流程图上看, 最终 register 的调用由 AnnotatedBeanDefinitionReader 调用
后续文章
- 源码-1:ApplicationContext-1
- 源码-2:ApplicationContext-2
- 源码-3:ApplicationContext-3
- 源码-4:ApplicationContext-4