ApplicationContext为什么可以通过@Autowired 进行注入

发布于:2024-03-01 ⋅ 阅读:(47) ⋅ 点赞:(0)

一、分析

在我们日常开发中,有时我们会使用这样的的一段代码

app.getBean(User.class);

那么这里的app就是ApplicationContext,如何获得这个ApplicatitionContext呢,无非就两种方式

  • 实现ApplicationContextAware接口中的 setApplicationContext 方法,接收其传入的applicationContext参数
  • 使用 @Autowired 注入

那么这里,就记录一下,ApplicationContext是如何完成注入的呢?
话说到这里,我们需要去看一下ApplicationContext 的refresh中调用的 prepareBeanFactory 方法,这个方法的内容如下

/**
	 * Configure the factory's standard context characteristics,
	 * such as the context's ClassLoader and post-processors.
	 * @param beanFactory the BeanFactory to configure
	 */
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// todo 注册 ApplicationContextAwareProcessor 到容器中,它的作用是在bean的实例化过程中当中,通过调用 postProcessBeforeInitialization 方法完成 一些Aware接口的相应方法的调用
		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		// todo 当前 ApplicationContext 在有需要的地方,可以使用@Autowired 依赖注入,是在  DefaultListableBeanFactory#doResolveDependency 方法中拿到的
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// todo 注册 ApplicationListenerDetector 到容器中,它的作用是收集监听器实例
		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// todo 注册 Environment 到容器中
		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

注意下面这一段代码,如图所示
在这里插入图片描述
通过上面这个图,可以发现,spring在启动的过程中,把当前 ApplicationContext 实例放入到DefaultListableBeanFactory中的 resolvableDependencies 容器中去了,如下图所示
在这里插入图片描述
那么疑问来了,放到这个 resolvableDependencies 容器中后,在哪里有使用到呢?
很轻易的想到,肯定是在bean实例化过程中,做依赖注入的时候用到了。
由于@Autowired是由 AutowiredAnnotationBeanPostProcessor 处理器来支持的,所以看一下这个图
在这里插入图片描述
点进去看看
在这里插入图片描述
点进去看看
在这里插入图片描述

进去看看在这里插入图片描述
doResolveDependency 方法的代码如下

@Nullable
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			Class<?> type = descriptor.getDependencyType();
			//  todo 获取@Value中的值,值类似于${enjoy.name}, 主要是看 QualifierAnnotationAutowireCandidateResolver  !!!!!!!!!!!!!!!!
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			//如果值是一个表达式时
			if (value != null) {
				// ${} 表达式解析
				if (value instanceof String) {
					// todo 具体参数解析。返回的是真正的参数
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				try {
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				}
				catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return (descriptor.getField() != null ?
							converter.convertIfNecessary(value, type, descriptor.getField()) :
							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
				}
			}

			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

			// todo 拿到需要注入的类型的所有实例
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			// todo 如果一个类型有多个实现的话,比如用到 @Primary 注解
			if (matchingBeans.size() > 1) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				// todo 从map容器中根据beanName ,获得 bean
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				// todo 如果需要注入的类型,只有一个实例的话,则直接拿出来
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}

			// todo  这里会走到getBean
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

在这里插入图片描述

进入 findAutowireCandidates 方法看看在这里插入图片描述
通过上面这个图,可以发现,拿到这个 DefaultListableBeanFactory 中的 resolvableDependencies 容器中的所有实例,其中就包括 ApplicationContext 的实例。类型匹配到以后,就把它返回了

针对上面的代码的分析,下面这里,做一下验证
准备下面的这样的代码

二、代码验证


@BeanIncluded
public class Student {

    @Autowired
    private ApplicationContext app;

    @EventListener(value = ContextRefreshedEvent.class)
    public void listenEvent(){
        Environment env = app.getEnvironment();
        System.out.println("=====容器启动成功=======");
    }
}

bug过程如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过上面这几个图,可以发现,返回就是ApplicationContext 实例

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到