我们都知道只要给对应的类添加相应的注解(@Repository@Service@Controller@Component),spring就可以把类作为bean注入到ioc容器里。另外@Bean注解也可以把方法作为一个bean注入。
目录
一、@Repository@Service@Controller@Component
findCandidateComponents(basePackage);
一、@Repository@Service@Controller@Component
这些都是我们常用的注解,既然是注解,我们在AnnotationConfigUtils抽象类中找到入口。
AnnotationConfigUtils#registerAnnotationConfigProcessors 方法,这个方法是spring添加一些注解对应的处理器,spring的事件监听注解也是在这里注册的。
ConfigurationClassPostProcessor 是配置注解的处理器。
主要看ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法,这个方法是BeanDefinitionRegistryPostProcessor接口的实现。
获取已经注册的beanName进行循环,String[] candidateNames = registry.getBeanDefinitionNames(); 其中就包括项目的启动类
其中ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) 方法是检查是否有@Component@Configuration之类的注解,有的话就添加到集合里下一步处理。这里我们debug可以看到,最后这个集合里就是我项目的启动类。
然后下面进入到do.while循环,
重点看 parser.parse(candidates); 这个方法就是去找对应的注解,一些Service,Controller等注解并注册到ico容器。
this.reader.loadBeanDefinitions(configClasses); 这个方法是为@Bean注解注册到ioc容器。下面讲解
我们先看parser.parse(candidates); 方法的实现
doProcessConfigurationClass方法
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 可以理解为判断有没有@ComponentScan,ComponentScans注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 主要功能去解析指定包下的所以class文件是否有相应的注解,并返回BeanDefinitionHolder集合
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 返回的集合是否有任何进一步的配置类,并在需要时进行递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
//判断是否有@Component@Service@Controller等注解,继续递归解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理 @Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//处理 @ImportResource 注解
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 处理 @Bean 注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
//添加对象,后面从这里获取解析
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
方法Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
调用ComponentScanAnnotationParser解析器去解析
ComponentScanAnnotationParser#parse 方法最后去扫描
根据包名来扫描 ClassPathBeanDefinitionScanner#doScan
终于来到Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
这个方法就是扫描拿到了满足条件的类,然后循环进行下面的注册。并返回BeanDefinitionHolder集合。
中间链路太长了,中间的类型判断,类型转换等等。不过没关系,我们终究还是来到了。
findCandidateComponents(basePackage);
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//转成classpath // classpath*:com/example/demo/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//获取当前包下所有的class文件
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 获取class文件的注解,并递归解析父级的注解来合并成mappings数组。封装成元数据对象
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//判断注解是否在includeFilters集合里面
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
//检查是否抽象类,是否接口
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
//加入BeanDefinition集合并返回,注入ioc
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;
}
getMetadataReaderFactory().getMetadataReader(resource);
调用工厂获取一个MetadataReader
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
//构造器,创建了一个SimpleAnnotationMetadataReadingVisitor访问者
SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader);
//二进制,字节码解析class文件获取注解信息,通过visitor回调
getClassReader(resource).accept(visitor, PARSING_OPTIONS);
this.resource = resource;
this.annotationMetadata = visitor.getMetadata();
}
这里使用了访问者设计模式,我们看一下visitEnd()回调方法
SimpleAnnotationMetadataReadingVisitor#visitEnd()
@Override
public void visitEnd() {
String[] memberClassNames = StringUtils.toStringArray(this.memberClassNames);
MethodMetadata[] annotatedMethods = this.annotatedMethods.toArray(new MethodMetadata[0]);
//根据当前注解获取父级的注解信息,生成MergedAnnotationsCollection对象,存了注解的并集,后面判断需要
MergedAnnotations annotations = MergedAnnotations.of(this.annotations);
this.metadata = new SimpleAnnotationMetadata(this.className, this.access,
this.enclosingClassName, this.superClassName, this.independentInnerClass,
this.interfaceNames, memberClassNames, annotatedMethods, annotations);
}
static MergedAnnotations of(Collection<MergedAnnotation<?>> annotations) {
Assert.notNull(annotations, "Annotations must not be null");
if (annotations.isEmpty()) {
return TypeMappedAnnotations.NONE;
}
//创建MergedAnnotationsCollection对象
return new MergedAnnotationsCollection(annotations);
}
//构造器
private MergedAnnotationsCollection(Collection<MergedAnnotation<?>> annotations) {
Assert.notNull(annotations, "Annotations must not be null");
//当前类上的注解
this.annotations = annotations.toArray(new MergedAnnotation<?>[0]);
this.mappings = new AnnotationTypeMappings[this.annotations.length];
//循环每个注解,获取父级的注解,并加到mappings数组里。
for (int i = 0; i < this.annotations.length; i++) {
MergedAnnotation<?> annotation = this.annotations[i];
Assert.notNull(annotation, "Annotation must not be null");
Assert.isTrue(annotation.isDirectlyPresent(), "Annotation must be directly present");
Assert.isTrue(annotation.getAggregateIndex() == 0, "Annotation must have aggregate index of zero");
this.mappings[i] = AnnotationTypeMappings.forAnnotationType(annotation.getType());
}
}
到此MetadataReader创建完成,主要是存了class的注解信息。
isCandidateComponent(metadataReader)
判断是否有注解在includeFilters集合里,即是否有满足自动注入ioc的注解
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
//匹配,满足匹配返回
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
includeFilters集合里有两个注解 @Component @ManagedBean
为什么只有两个,按道理不应该是@Repository@Service@Controller@Component注解等等吗。那我们看下@Repository@Service@Controller的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
可以看到每个注解里都有一个@Component注解,即@Component是元注解,@Repository@Service@Controller都是@Component的派生注解。 所以在项目里要想注入到ico容器里,只要添加@Component注解就可以。
看匹配的方法是怎么匹配的,tf.match(metadataReader, getMetadataReaderFactory())
AbstractTypeHierarchyTraversingFilter#match
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//判断是否有@Component注解。因为tf的类型是AnnotationTypeFilter,所以matchSelf方法在AnnotationTypeFilter类里重写
if (matchSelf(metadataReader)) {
return true;
}
ClassMetadata metadata = metadataReader.getClassMetadata();
if (matchClassName(metadata.getClassName())) {
return true;
}
AnnotationTypeFilter#matchSelf
@Override
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
这里主要是两个判断:
metadata.hasAnnotation(this.annotationType.getName()) //判断当前类是否有@Component注解
metadata.hasMetaAnnotation(this.annotationType.getName()) //判断父级类有没有@Component注解
因为在上面创建元数据对象MetadataReader的时候分析,在访问者的visitEnd()回调方法里创建了MergedAnnotationsCollection对象,里面存了当前类的注解信息。
所以看下在MergedAnnotationsCollection里是怎么判断的。
MergedAnnotationsCollection#isDirectlyPresent
@Override
public boolean isDirectlyPresent(String annotationType) {
return isPresent(annotationType, true);
}
private boolean isPresent(Object requiredType, boolean directOnly) {
//判断this.annotations当前class上是否有@Component注解
for (MergedAnnotation<?> annotation : this.annotations) {
Class<? extends Annotation> type = annotation.getType();
if (type == requiredType || type.getName().equals(requiredType)) {
return true;
}
}
//directOnly 为 true ,不走下面
if (!directOnly) {
for (AnnotationTypeMappings mappings : this.mappings) {
for (int i = 1; i < mappings.size(); i++) {
AnnotationTypeMapping mapping = mappings.get(i);
if (isMappingForType(mapping, requiredType)) {
return true;
}
}
}
}
return false;
}
MergedAnnotationsCollection#find
private <A extends Annotation> MergedAnnotation<A> find(Object requiredType,
@Nullable Predicate<? super MergedAnnotation<A>> predicate,
@Nullable MergedAnnotationSelector<A> selector) {
if (selector == null) {
selector = MergedAnnotationSelectors.nearest();
}
MergedAnnotation<A> result = null;
for (int i = 0; i < this.annotations.length; i++) {
MergedAnnotation<?> root = this.annotations[i];
AnnotationTypeMappings mappings = this.mappings[i];
//循环mappings 数组---里面是所有父级的注解
for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
AnnotationTypeMapping mapping = mappings.get(mappingIndex);
//判断是否有@Component注解
if (!isMappingForType(mapping, requiredType)) {
continue;
}
MergedAnnotation<A> candidate = (mappingIndex == 0 ? (MergedAnnotation<A>) root :
TypeMappedAnnotation.createIfPossible(mapping, root, IntrospectionFailureLogger.INFO));
if (candidate != null && (predicate == null || predicate.test(candidate))) {
if (selector.isBestCandidate(candidate)) {
return candidate;
}
result = (result != null ? selector.select(result, candidate) : candidate);
}
}
}
return result;
}
判断完成,返回BeanDefinition集合,注入ioc
二、@Bean
在上面的分析中,我们在ConfigurationClassParser#doProcessConfigurationClass 方法中看到了bean注解的解析
// 处理 @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
//把有@Bean注解的方法创建beanMethods对象,并加到beanMethods集合里缓存。等全部类解析完后在外面注入
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
/**
* Retrieve the metadata for all <code>@Bean</code> methods.
*/
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
//在元数据里获取有Bean注解的方法
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return beanMethods;
}
回到最开始的注解配置处理器ConfigurationClassPostProcessor
ConfigurationClassPostProcessor#processConfigBeanDefinitions
do while循环里
do {
//解析class的注解
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//注入返回的类集合里的有@Bean注解的方法
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
this.reader.loadBeanDefinitions(configClasses);
/**
* Read {@code configurationModel}, registering bean definitions
* with the registry based on its contents.
*/
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
/**
* Read a particular {@link ConfigurationClass}, registering bean definitions
* for the class itself and all of its {@link Bean} methods.
*/
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//取出缓存@Bean方法的集合,循环
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
循环进去loadBeanDefinitionsForBeanMethod(beanMethod)方法
方法的最后注入ioc容器。
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
总结
主要类的调用顺序
ConfigurationClassPostProcessor ==》ConfigurationClassParser ==》ComponentScanAnnotationParser ==》ClassPathBeanDefinitionScanne ==》ClassPathScanningCandidateComponentProvider
主要方法 :
Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 返回BeanDefinition集合。
tf.match(metadataReader, getMetadataReaderFactory()) 注解匹配的方法
通过指定的包路径,扫描所有的class文件,asm字节码解析获取class的注解信息封装成MetadataReader,并通过MergedAnnotationsCollection递归合并父级的注解,最后判断class是否满足注入ico容器,即有没有@Component注解。
中间还解析了@Bean注解的方法。返回所有满足的方法并注入ioc。
this.reader.loadBeanDefinitions(configClasses); //注入@bean注解的bean