“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第4篇文章,点击查看活动详情” 这里会将关键的源码直接贴出来,注意这里讲述的源码顺序并不是spring的一个启动流程顺序,而是针对spring源码中的扫描部分做分析解读。
1.spring源码入口: AnnotationConfigApplicationContext
创建一个spring容器,加载配置类。所以就从AnnotationConfigApplicationContext的有参构造方法来看。
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(context.getBean("user"));
}
}
2.进入到 AnnotationConfigApplicationContext类的构造方法
这个有参的构造方法中: this();无参构造方法 register(componentClasses);注册 refresh();刷新
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
1.进入到this()方法:
位置:AnnotationConfigApplicationContext类
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
这个方法里面的createAnnotatedBeanDefReader这个对象可以不用去看,从代码来看一个start方法,一个end方法,我猜测它的主要作用:记录一下程序的执行信息。
这里最主要的是reader和scanner,它们一个是读取,一个是扫描。
2.进入到 refresh();
这个方法很重要,比较核心的方法。扫描bean,创建bean 都是在这里面。
invokeBeanFactoryPostProcessors(beanFactory); 这个方法会调用this()方法中创建的scanner对象的scan()方法 扫描bean。
finishBeanFactoryInitialization(beanFactory); 这个方法中会实例化所有剩余的(非懒加载)单例bean。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 准备此上下文以进行刷新
// Prepare this context for refreshing.
prepareRefresh();
//告诉子类刷新内部bean工厂
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备bean工厂以便在此上下文中使用
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
//允许在上下文子类中对bean工厂进行后处理。
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//调用上下文中注册为bean的工厂处理器
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截bean创建的bean处理器。
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//初始化此上下文的消息源。
// Initialize message source for this context.
initMessageSource();
//为此上下文初始化事件多播
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
//初始化特定上下文子类中的其他特殊bean。
// Initialize other special beans in specific context subclasses.
onRefresh();
//检查侦听器bean并注册它们
// Check for listener beans and register them.
registerListeners();
// 实例化所有剩余的(非惰性初始化)单例。
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//最后一步:发布相应的事件。
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例以避免悬空资源
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// 重置“活动”标志。
// Reset 'active' flag.
cancelRefresh(ex);
// 将异常传播到调用方。
// Propagate exception to caller.
throw ex;
}
finally {
//重置Spring核心中的常见自省缓存,因为我们
//可能不再需要单例bean的元数据。。。
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
3.扫描
扫描主要的作用:1.将扫描得到的bean封装成beanDefinition,2将扫描得到的beanDefinition注册到容器中。
扫描用的AnnotationConfigApplicationContext类下的AnnotationConfigApplicationContext()方法中创建的scanner对象。
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
1.进入到scanner对象
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
private final BeanDefinitionRegistry registry;
private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
@Nullable
private String[] autowireCandidatePatterns;
private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private boolean includeAnnotationConfig = true;
......
}
上面这段代码只是ClassPathBeanDefinitionScanner 中一部分。
1. BeanDefinitionRegistry registry;
private final BeanDefinitionRegistry registry;
spring中的单一原则可以从这行代码中看到,或者是增强可读性。
BeanDefinitionRegistry 是一个接口,这个接口有很多实现类,其中有一个 DefaultListableBeanFactory 实现类。
DefaultListableBeanFactory 不仅实现 BeanDefinitionRegistry 接口,还实现了其他接口,所以它的功能很强大。
有意思的是,ClassPathBeanDefinitionScanner 中的 registry 属性,在实际执行中的值就是DefaultListableBeanFactory 。
那么为什么这里的registry 不直接定义为DefaultListableBeanFactory类?我猜测有以下原因
1.这个只需要注册的功能,并不需要其他功能,所以没必要定义为DefaultListableBeanFactory
2.增强可读性。从命名角度看BeanDefinitionRegistry 与DefaultListableBeanFactory 显然BeanDefinitionRegistry 可读性更强。
3.符合spring中单一原则,BeanDefinitionRegistry 主要功能就是注册,DefaultListableBeanFactory还有其他功能。
2.scan()方法中的doScan(String... basePackages)
可以在ClassPathBeanDefinitionScanner中直接搜doScan,就能找到
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
1.获取BeanDefinition集合
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
这行代码就是获取BeanDefinition,进入到findCandidateComponents()方法
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
直接进到scanCandidateComponents(basePackage)方法中
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
......
1.重新生成包路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
这行代码主要作用:根据传入的包路径获取一个适用于spring内部的包路径以方便后续使用。就是重新生成一个路径。
2.获取所有的.class文件的file对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
根据上面生成的路径获取该路径下面的所有.class文件的file对象。
3.获取metadataReader元数据信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
根据resources来获取元数据信息,这个元数据信息包含了这个类的所有信息,这个地方spring用的是ASM技术来获取metadataReader。
4.根据元数据信息进行判断
if (isCandidateComponent(metadataReader)) {
1.metadataReader与(excludeFilters和includeFilters)比较匹配
根据这个类的元数据信息,进行判断,进入到这个判断逻辑里面
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//metadataReader 和某一个排除过滤器匹配了就return false,说明它就不是一个bean
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// metadataReader 必须有一个includeFilters 所包含的注解 才有可能是一个bean
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
可以看到excludeFilters和includeFilters,一个排除,一个包含。
excludeFilters(排除):metadataReader与某一个排除过滤器匹配了就return false,说明它就不是一个bean
includeFilters(包含):includeFilters在spring中会默认添加@Component注解,还有另外一个很少用(ManagedBean),也就是说,metadataReader中带有@Component注解才有可能成为bean\
2.判断是否有条件注解
可以看到下面这个下面这个判断返回的是isConditionMatch(metadataReader),进入到这个判断逻辑:
/**
* Determine whether the given class is a candidate component based on any
* {@code @Conditional} annotations.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
*/
private boolean isConditionMatch(MetadataReader metadataReader) {
if (this.conditionEvaluator == null) {
this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}
这个方法中直接进shouldSkip()方法。
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
继续往下走
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
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);
}
......
}
最主要看这个
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; }
元数据信息中不包含Conditional这个注解返回false,那么就不用继续往下走逻辑判断,它才可能是一个bean。
如果包含了这个注解,那么就继续向下走逻辑:找到条件注解中的类,执行这个类的matches方法,获取方法中的结果,看是否符合条件。
5.创建beanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
进入到这有参构造方法,
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
可以看到有setBeanClassName,这个地方赋值的只是名字,
/**
* 指定此bean定义的bean类名
* Specify the bean class name of this bean definition.
*/
@Override
public void setBeanClassName(@Nullable String beanClassName) {
this.beanClass = beanClassName;
}
进去之后可以看到注释:指定此bean定义的bean类名。然而这个this.beanClass 的类型是Object,不是String类型。基于现在的流程来看,现在只是获取一些元数据信息,并没有加载类,所以是拿不到clazz对象的。当需要用到与此类名相同的类的时候就会去加载,获取clazz对象,并赋值给beanClass属性。
6.再判断beanDefinition是否符合候选条件
if (isCandidateComponent(sbd)) {
进入到该方法
/**
*确定给定的bean定义是否符合候选条件。
* 默认实现检查类是否为接口
*且不依赖于外围类。
* 可以在子类中重写。要检查的bean定义
* @返回bean定义是否有资格作为候选组件
* /
/**
* Determine whether the given bean definition qualifies as candidate.
* <p>The default implementation checks whether the class is not an interface
* and not dependent on an enclosing class.
* <p>Can be overridden in subclasses.
* @param beanDefinition the bean definition to check
* @return whether the bean definition qualifies as a candidate component
*/
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
这个方法就是判断给定的bean定义是否符合候选条件,满足这些条件才会将beanDefinition添加到集合中。 metadata.isIndependent():必须是顶级类,不依赖外部类 metadata.isConcrete():不能是接口和抽象类 metadata.isAbstract():如果抽象类的情况下,且该抽象类的方法上包含Lookup注解(metadata.hasAnnotatedMethods(Lookup.class.getName()))也符合条件
2.获取scope注解的信息
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
主要是获取scope值并赋值candidate.setScope;
3.获取beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
进入到generateBeanName()方法中,位置:AnnotationBeanNameGenerator
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
上面这个段代码: if判断中获取的是@Component中的值,如果@Component没有指定值,那么就会返回这个方法:
buildDefaultBeanName(definition, registry)。
生成的默认值.
4.给beanDefinition赋默认值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
5.解析类上面的注解
这个方法中会解析这些注解:@Lazy @Primary @DependsOn等
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
6.判断beanDefinition是否存在
if (checkCandidate(beanName, candidate)) {
进入到这个方法中checkCandidate()
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
这段代码:
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
这个registry就是ClassPathBeanDefinitionScanner的registry属性,就是这个
private final BeanDefinitionRegistry registry;
前面有说的这个属性在执行的时候真正的值是:DefaultListableBeanFactory类型的值,那么进入到DefaultListableBeanFactory中这个方法containsBeanDefinition(String beanName)
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
可以看到这个地方就是一个beanDefinitionMap。
所以可以得出,如果这个beanDefinitionMap中已经存在是不会在存进去的。要么抛异常,要么不会注册。
7.创建BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
8.注册BeanDefinition
1
registerBeanDefinition(definitionHolder, this.registry);
2
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
3
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
这个三块代码,registerBeanDefinition(definitionHolder, this.registry)中传入的是ClassPathBeanDefinitionScanner中的registry属性,那么在第3块代码中registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());使用的就是 DefaultListableBeanFactory类下的registerBeanDefinition方法。 进入到这个方法(DefaultListableBeanFactory的registerBeanDefinition方法)中可以看到
this.beanDefinitionMap.put(beanName, beanDefinition);
是将 beanName和beanDefinition 放到了beanDefinitionMap中。
到此spring的扫描逻辑基本是完成了。