问题抛出:
我们开发过程中、经常通过@Autowired注解引入一个类、经常使用@Value注解引入一个字符串的值、但是Spring是如何做到的呢?
继承结构:
如上图 AutowiredAnnotionBeanPostProcessor这个类就是处理@Autowired注解和@Value注解的。我们分析一下、我们知道Spring Bean的生命周期、其中包括实例化、填充属性、初始化阶段。
1、实例化:前面讲过 Spring的实例化有、构造方法、Supplier、FactoryMethod、InstantiationAwareBeanPostProcessor等方式
2、填充属性:无非就是给属性赋值 populateBean
3、初始化:执行自定义init方法和执行Bean的增强器
思考:如果你是Spring的开发者、如何设计合理呢?
是否应该在实例和初始化之间做一些操作、把@Autowired修饰的属性或方法元数据准备好、在给Bean属性赋值阶段直接拿到元数据进行调用呢? 下面我们看源码
源码跟踪:
1、进入doCreateBean方法 里面有一个applyMergedBeanDefinitionPostProcessors
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 对所有实现了MergedBeanDefinitionPostProcessor接口的bean进行调用
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
这里获取所有BeanPostProcessor遍历是否是MergedBeanDefinitionPostProcessor 、根据类的继承结构图、AutowiredAnnotationBeanPostProcessor是属于MergedBeanDefinitionPostProcessor类型
2、AutowiredAnnotationBeanPostProcessor里面有一个方法findAutowiredMetadata();
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
/**将beanName作为注入元数据(Map)的key,如果beanName为空的话,那就把类名作为key*/
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 查看下这个key是不是在缓存map中了(当bean还没有初始化前,会调用一次该方法,在初始化装填属性的时候会再调用一次,你品!)
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
/**
* 构建一个需要注入的元数据对象,一个类对应一个注入元数据,而一个注入元数据包含多个注入元素,元素可以是字段或方法
* InjectMetadata类有两个重要的成员变量:
* (1)Class<?> targetClass
* (2)Collection<InjectedElement> injectedElements
*/
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
逻辑也很简单、先从缓存中获取是否存在、如果没有、根据Bean的Class对象解析构建出来Autowired修饰的metadata对象 然后放到缓存中
3、根据Bean的生命周期我们知道给Bean填充数据这个方法叫做populateBean方法、相关代码如下:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/**
* 如果InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation() stProcessAfterInstantiation执行完且
* 返回了true,则会继续调用这个processor的postProcessProperties方法进行一个属性的装填操作
* 这里如果bp是AutowiredAnnotationBeanPostProcessor类型的,则这个地方会调用其postProcessProperties方法,
* 即会处理类中@Autowired的成员变量
*/
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
/**postProcessPropertyValues这个方法已经标注为废弃了*/
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
这里判断下是否是InstantiationAwareBeanPostProcessor 根据类的继承结构图、很明显AutowiredAnnotationBeanPostProcessor是属于InstantiationAwareBeanPostProcessor的。调用postProcessProperties方法。
4、postProcessProperties方法如下
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 找到这个 Bean 的注入元信息对象
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 进行注入,这个地方就有意思了(层层进去,它会根据元数据中的注入类型是字段注入还是方法注入去装配属性信息)
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
这里又看到findAutowiringMetedata、实际上这里会从第二步已经准备放入缓存的Metedata取出、执行inject方法
5、Inject方法如下
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
这里的element 有两个子类
①AutowiredFieldElement 注解放在属性上 进入跟踪进去最终会通过反射机制给属性赋值
②AutowiredMethodElement 注解放在方法上进入跟踪进去最终反射机制调用方法的invoke方法
以上就完成对@Autowired注解的处理