Spring注解源码解析:@Autowired

Spring注解源码解析:@Autowired

流程:

经过我们的分析和推断,解析注解@Autowired的时机,其实就是在为bean实例填充属性的时候,会调用AutowiredAnnotationBeanPostProcessor中的方法postProcessProperties,为bean实例解析注解并填充属性信息。

我们以方法postProcessProperties为入口,看了下注解@Autowired是如何解析的,其实就是获取类中所有字段以及方法上的注解,注解包括@Autowired以及@Value;但是,添加了注解的字段或方法是不允许static关键字修饰的,而且,添加注解的方法也不允许是无参方法,否则字段的值无法注入。

最后,我们可以看到解析到的所有注解信息,最后都会被设置到相应的字段和方法中。

/ * @see AutowiredAnnotationBeanPostProcessor
 * @see Qualifier
 * @see Value
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

AutowiredAnnotationBeanPostProcessor是一个Bean的后处理器,前面我们在讲解后处理器时,已经了解过了,后处理器接口BeanPostProcessor中提供了两个方法,分别是方法postProcessBeforeInitialization以和方法postProcessAfterInitializatio

可惜的是,我们在AutowiredAnnotationBeanPostProcessor类中并没有找到这两个方法的具体实现,但是,却在它的父类InstantiationAwareBeanPostProcessorAdapter中,发现了这两个方法的实现。

可以看到,在InstantiationAwareBeanPostProcessorAdapter中这两个方法默认并没有什么逻辑,都是空实现,这就证明后处理器AutowiredAnnotationBeanPostProcessor的核心逻辑,并不是围绕着接口BeanPostProcessor中的两个方法展开的。

那我们就要到其他地方寻找线索了,可以看到,AutowiredAnnotationBeanPostProcessor类的继承体系中,继承接口BeanPostProcessor的还有接口InstantiationAwareBeanPostProcessor

image-20220612225905939

postProcessProperties()

方法postProcessProperties是在为bean实例填充属性时被调用的

方法postProcessProperties的返回值类型为PropertyValues,也就是说当前是在解析属性的信息。

而前面我们在分析bean加载的逻辑时,有一个环节就是为刚实例化出来的bean填充属性,在属性信息填充之前,会将各种各样的属性信息封装到PropertyValues中,

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   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;
}

方法findAutowiringMetadata中的逻辑并不算太复杂,首先获取cacheKey,如果beanName不为空,就以beanName为cacheKey,否则以类的全限定名为cacheKey。

尝试从缓存injectionMetadataCache中,根据cacheKey获取InjectionMetadata类型的metadata,InjectionMetadata根据名称,我们大致可以理解为是可以注入到bean实例中的注解元数据,里面封装了@Autowired对应属性或方法参数的值

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// 首先获取cacheKey,如果beanName不为空,就以beanName为cacheKey,否则以类的全限定名为cacheKey。
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// 尝试从缓存injectionMetadataCache中,根据cacheKey获取InjectionMetadata类型的metadata,InjectionMetadata根据名称,我们大致可以理解为是可以注入到bean实例中的注解元数据,里面封装了@Autowired对应属性或方法参数的值
	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);
				}
				metadata = buildAutowiringMetadata(clazz);
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}
判断当前bean的类型是否符合条件

方法buildAutowiringMetadata中的第一段代码:

首先会通过AnnotationUtils中的方法isCandidateClass,判断当前bean实例的类clazz是否符合条件。

对类中的每个字段进行解析,可以看到会调用方法findAutowiredAnnotation,寻找字段上的注解,我们到方法findAutowiredAnnotation中看下

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
  //首先会通过AnnotationUtils中的方法isCandidateClass,判断当前bean实例的类clazz是否符合条件。
  //如果不存在指定类型的autowiredAnnotationTypes注解,则返回空的
   if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
      return InjectionMetadata.EMPTY;
   }
//首先对类中的每个字段进行解析,可以看到会调用方法findAutowiredAnnotation,寻找字段上的注解,我们到方法findAutowiredAnnotation中看下
ReflectionUtils.doWithLocalFields(targetClass, field -> {
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
          //判断字段是否被static关键字修饰了,如果是的话添加的注解将会失效,这也警示我们不能在静态属性中添加@Autowired或@Value。
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
          //会调用方法determineRequiredStatus获取Required的值
					boolean required = determineRequiredStatus(ann
          //将类中所有字段解析到的注解信息,添加到集合currElements中。                                           
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

AutowiredAnnotationBeanPostProcessor初始化时,就会为成员变量this.autowiredAnnotationTypes添加一些初始化元素,而且,我们可以发现竟然就是我们的目标注解@Autowired,同时还包含了注解@Value。

this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);

这里会遍历this.autowiredAnnotationTypes中的每个注解,其实也就是注解@Autowired和注解@Value,如果发现字段中存在这这两个注解就返回它们,这些都是反射底层的API,

@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
   MergedAnnotations annotations = MergedAnnotations.from(ao);
   for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
      MergedAnnotation<?> annotation = annotations.get(type);
      if (annotation.isPresent()) {
         return annotation;
      }
   }
   return null;

接下来就是要解析类中每个方法上的注解信息,其实解析的流程和步骤和前面解析字段上的流程是差不多的。

首先,从方法上获取注解信息,然后判断下方法是否是静态方法,这里也是不允许在静态方法上添加@Autowired和@Value的,然后获取属性required的值,最终设置到集合currElements中。

当然,和字段注解的解析不同的是,这里还额外判断了下方法的参数个数,如果参数个数为0也是不允许的,因为这样Spring就不知道你需要注入的值要设置到哪个属性上了。


ReflectionUtils.doWithLocalMethods(targetClass, method -> {
   Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
   if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
      return;
   }
   MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
   if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
      if (Modifier.isStatic(method.getModifiers())) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation is not supported on static methods: " + method);
         }
         return;
      }
      if (method.getParameterCount() == 0) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation should only be used on methods with parameters: " +
                  method);
         }
      }
      boolean required = determineRequiredStatus(ann);
      PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
      currElements.add(new AutowiredMethodElement(method, required, pd));
   }
});
给字段或方法注入属性的值

可以看到,接下来就是要把解析到的注解信息注入到相应属性pvs上,我们再到metadata的方法inject中看下:

在方法inject中,会遍历我们前面解析到的注解信息,然后调用element的方法inject。

InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
   metadata.inject(bean, beanName, pvs);
}
//在方法inject中,会遍历我们前面解析到的注解信息,然后调用element的方法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);
			}
		}
	}

如果注解是字段上的,那就给具体字段注入值;如果注解是方法上的,那就执行方法来注入参数的值,注解@Autowired和注解@Value底层自动注入的逻辑,也就是这样通过反射API来完成属性值的注入

 */
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
      throws Throwable {

   if (this.isField) {
      Field field = (Field) this.member;
      ReflectionUtils.makeAccessible(field);
      field.set(target, getResourceToInject(target, requestingBeanName));
   }
   else {
      if (checkPropertySkipping(pvs)) {
         return;
      }
      try {
         Method method = (Method) this.member;
         ReflectionUtils.makeAccessible(method);
         method.invoke(target, getResourceToInject(target, requestingBeanName));
      }
      catch (InvocationTargetException ex) {
         throw ex.getTargetException();
      }
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值