首先看创建一个Spring容器的代码:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
源码:
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
StartupStep是什么?
StartupStep是Spring5.3版本新增的,有两个实现类:DefaultStartupStep和FlightRecorderStartupStep
默认使用的是DefaultStartupStep,其实里面什么事情都没有做
FlightRecorderStartupStep使用了jdk9还是11以后的一个新特性,叫JFR
JFR简述:在jdk层面,提供的java程序,在生产运行过程中可以监控的一种机制,就像飞机的黑盒子,记录运行速度、性能
注意:这里不是Spring内部提供的牛逼功能,而是Spring利用jdk新特性的一个点,例如记录执行步骤的时间
了解JFR,可参考文章:深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置 - 知乎
创建一个Spring容器主要做了什么事情呢?
扫描、创建非懒加载的单例Bean
接下来再看ClassPathBeanDefinitionScanner的扫描方法:(重点关注doScan方法)
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
private final BeanDefinitionRegistry registry;
... ...
/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* This method does not register an annotation config processor
* but rather leaves this up to the caller.
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 核心扫描逻辑,得到BeanDefinition
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析Scope注解,单例还是原型设置进来
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// @Component注解有没有指定名字,指定直接返回,没有指定构造默认的
// 默认根据类的短名生成。大部分情况首字母小写,但是类名前两个字母都是大写就直接返回类名
// 举例默认情况:UserService - userService; ABTest - ABTest
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
// 遍历出来的BeanDefinition设置默认值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description,设置给BeanDefinition对应的属性
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器中是否已经存在该beanName
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;
}
/**
* Scan the class path for candidate components.
* @param basePackage the package to check for annotated classes
* @return a corresponding Set of autodetected bean definitions
*/
public Set findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
private Set scanCandidateComponents(String basePackage) {
Set candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源,匹配所有的class文件
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 资源,class文件的File对象
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 {
// 类的元数据读取器,类的注解信息、名字、是不是抽象、实现的接口名字、父类等
// 底层使用的ASM技术,metadataReader相当于类的一个代表
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// excludeFilters、includeFilters判断
// includeFilters判断:默认添加一个@Component注解(创建扫描器时添加的)
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);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
/**
* Determine whether the given class does not match any exclude filter
* and does match at least one include filter.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
*/
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 如果传入的类和任何一个排除过滤器匹配了,就返回false,表示不是一个Bean
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
for (TypeFilter tf : this.includeFilters) {
// 有@Component注解匹配
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
/**
* 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());
}
/**
* Determine if an item should be skipped based on {@code @Conditional} annotations.
* The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a
* {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION})
* @param metadata the meta data
* @return if the item should be skipped
*/
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
/**
* Determine if an item should be skipped based on {@code @Conditional} annotations.
* @param metadata the meta data
* @param phase the phase of the call
* @return if the item should be skipped
*/
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 没有@Conditional注解,就不要跳过,当前类是一个Bean(有@Component,没有@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);
}
List conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
/**
* Create a new ScannedGenericBeanDefinition for the class that the
* given MetadataReader describes.
* @param metadataReader the MetadataReader for the scanned target class
*/
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
// 这里只是把className设置到BeanDefinition中
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
/**
* Specify the bean class name of this bean definition.
*/
@Override
public void setBeanClassName(@Nullable String beanClassName) {
// 把className设置到BeanDefinition的beanClass属性,beanClass是Object类型
this.beanClass = beanClassName;
}
/**
* Determine whether the given bean definition qualifies as candidate.
* The default implementation checks whether the class is not an interface
* and not dependent on an enclosing class.
*
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();
// 不是独立的,不能成为Bean(如果是一个顶级类或者静态内部类,那么就是独立的)
// isConcrete:!(是接口||是抽象类),说白了就不是接口,也不是抽象类
// 是抽象类,但是类里面有@Lookup注解修饰的方法,可以成为Bean
// 总结:独立的;不是接口也不是抽象类;是抽象类,并且类内方法有@Lookup注解。三种情况是Bean
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
/**
* Check the given candidate's bean name, determining whether the corresponding
* bean definition needs to be registered or conflicts with an existing definition.
* @param beanName the suggested name for the bean
* @param beanDefinition the corresponding bean definition
* @return {@code true} if the bean can be registered as-is;
* {@code false} if it should be skipped because there is an
* existing, compatible bean definition for the specified name
* @throws ConflictingBeanDefinitionException if an existing, incompatible
* bean definition has been found for the specified name
*/
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;
}
// 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。
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() + "]");
}
... ...
}
思考:BeanDefinitionRegistry能不能用DefaultListableBeanFactory替换?
DefaultListableBeanFactory是BeanDefinitionRegistry的重要实现类,功能上可以替换但是没有必要。
这里扫描器主要的功能是:把扫描得到的BeanDefinition注册到Spring容器里面去,注册功能是BeanDefinitionRegistry这个接口提供的。DefaultListableBeanFactory确实有注册的功能,但是DefaultListableBeanFactory还有很多其他的功能,这里并不需要。单一职责
实际运行的时候registry属性的值就是DefaultListableBeanFactory对象
注意:有@Component注解不一定是一个Bean。如果还有@Conditional注解,就要看条件是否匹配,条件匹配了才是一个Bean,条件不匹配就不是一个Bean(@Conditional注解指定的类需要实现Condition接口,并且重写matches方法,matches方法返回true表示匹配,返回false不匹配)
BeanDefinition的beanClass属性为什么是Object类型?而不是Class?
扫描到setBeanClassName
方法这里时,是通过ASM技术去解析这个类,并没有去加载这个类,只是把Bean的名字设置给BeanDefinition的beanClass属性。等真正的去加载这个Bean时,才会得到Class对象,再把这个对象赋值给beanClass属性。这里使用Object就是考虑到两种情况:最开始赋值的是Bean的名字,加载后赋值Class对象