spring bean通过注解注入ioc容器的源码跟踪

我们都知道只要给对应的类添加相应的注解(@Repository@Service@Controller@Component),spring就可以把类作为bean注入到ioc容器里。另外@Bean注解也可以把方法作为一个bean注入。

目录

一、@Repository@Service@Controller@Component

findCandidateComponents(basePackage);

二、@Bean

总结


一、@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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值