一、分析
在我们日常开发中,有时我们会使用这样的的一段代码
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 实例