spring依赖注入注解@Autowired和@Resource原理解析

注解@Autowired和@Resource都可以实现Bean的自动注入。
其中@Autowired是通过Bean后处理器 BeanPostProcessor实现类AutowiredAnnotationBeanPostProcessor来完成。
而@Resource是通过另外一个CommonAnnotationBeanPostProcessor来实现的。

那么Spring是怎么做到区分的呢?
先看AbstractAutowireCapableBeanFactory,实例化bean会调用这个类的doCreateBean方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
     

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
     
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
     
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
     
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
     
			if (!mbd.postProcessed) {
     
				try {
     
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
     
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}

进入applyMergedBeanDefinitionPostProcessors方法

	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
     
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
     
			if (bp instanceof MergedBeanDefinitionPostProcessor) {
     
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
			}
		}
	}

getBeanPostProcessors()包含很多个BeanPostProcessor,就包含上面提到的两个,并且实现了MergedBeanDefinitionPostProcessor接口

进入org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
     
		super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
		if (beanType != null) {
     
			InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
			metadata.checkConfigMembers(beanDefinition);
		}
	}
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, PropertyValues pvs) {
     
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		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);
					}
					try {
     
						metadata = buildResourceMetadata(clazz);
						this.injectionMetadataCache.put(cacheKey, metadata);
					}
					catch (NoClassDefFoundError err) {
     
						throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
								"] for resource metadata: could not find class that it depends on", err);
					}
				}
			}
		}
		return metadata;
	}

再进入buildResourceMetadata方法

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
     
		LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
		Class<?> targetClass = clazz;

		do {
     
			final LinkedList<InjectionMetadata.InjectedElement> currElements =
					new LinkedList<InjectionMetadata.InjectedElement>();

			ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
     
				@Override
				public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
     
					if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
     
						if (Modifier.isStatic(field.getModifiers())) {
     
							throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
						}
						currElements.add(new WebServiceRefElement(field, field, null));
					}
					else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
     
						if (Modifier.isStatic(field.getModifiers())) {
     
							throw new IllegalStateException("@EJB annotation is not supported on static fields");
						}
						currElements.add(new EjbRefElement(field, field, null));
					}
					else if (field.isAnnotationPresent(Resource.class)) {
     
						if (Modifier.isStatic(field.getModifiers())) {
     
							throw new IllegalStateException("@Resource annotation is not supported on static fields");
						}
						if (!ignoredResourceTypes.contains(field.getType().getName())) {
     
							currElements.add(new ResourceElement(field, field, null));
						}
					}
				}
			});

			ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
     
				@Override
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
     
					Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
					if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
     
						return;
					}
					if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
     
						if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
     
							if (Modifier.isStatic(method.getModifiers())) {
     
								throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
							}
							if (method.getParameterTypes().length != 1) {
     
								throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
							}
							PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
							currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
						}
						else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
     
							if (Modifier.isStatic(method.getModifiers())) {
     
								throw new IllegalStateException("@EJB annotation is not supported on static methods");
							}
							if (method.getParameterTypes().length != 1) {
     
								throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
							}
							PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
							currElements.add(new EjbRefElement(method, bridgedMethod, pd));
						}
						else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
     
							if (Modifier.isStatic(method.getModifiers())) {
     
								throw new IllegalStateException("@Resource annotation is not supported on static methods");
							}
							Class<?>[] paramTypes = method.getParameterTypes();
							if (paramTypes.length != 1) {
     
								throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
							}
							if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
     
								PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
								currElements.add(new ResourceElement(method, bridgedMethod, pd));
							}
						}
					}
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return new InjectionMetadata(clazz, elements);
	}

这个方法有点长,只要看这句:field.isAnnotationPresent(Resource.class),属性field是被Resource注解的就添加到currElements中,最终生成InjectionMetadata对象,这个对象包含的就是bean待注入的所有属性。最后统一放到injectionMetadataCache这个Map中,为后面填充属性使用。

我们再看类org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
     
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}
	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
     
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		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;
	}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
     
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
     
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			ReflectionUtils.doWithLocalFields(targetClass, field -> {
     
				AnnotationAttributes ann = findAutowiredAnnotation(field);
				if (ann != null) {
     
					if (Modifier.isStatic(field.getModifiers())) {
     
						if (logger.isInfoEnabled()) {
     
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

findAutowiredAnnotation方法是关键

	@Nullable
	private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
     
		if (ao.getAnnotations().length > 0) {
       // autowiring annotations have to be local
			for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
     
				AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
				if (attributes != null) {
     
					return attributes;
				}
			}
		}
		return null;
	}

其中autowiredAnnotationTypes是一个Set集合,类初始化的时候就add进去了:
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);

	public AutowiredAnnotationBeanPostProcessor() {
     
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
     
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
     
			// JSR-330 API not available - simply skip.
		}
	}

所以Bean的属性包含@Autowired或者@Value的都会满足条件,最终也是生成InjectionMetadata对象,也是存在一个map里面injectionMetadataCache

回到AbstractAutowireCapableBeanFactory类的doCreateBean方法,接着上面往下走,populateBean方法,填充属性,也就是注入属性。
其中有一段:依然是遍历getBeanPostProcessors这个集合

			for (BeanPostProcessor bp : getBeanPostProcessors()) {
     
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
     
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
     
						if (filteredPds == null) {
     
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
     
							return;
						}
					}
					pvs = pvsToUse;
				}
			}

进入postProcessProperties方法

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
     
		InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
		try {
     
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
     
			throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
		}
		return pvs;
	}

是不是看到了熟悉的InjectionMetadata ,就是上面事先存好放在Map中的,这里重新拿出来,遍历BeanPostProcessors,其中CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor都会分别进入postProcessProperties方法中,从map拿出来InjectionMetadata对象,拿到InjectionMetadata对象中的injectedElements集合,这里存的就是待注入的field,跟着遍历metadata.inject(bean, beanName, pvs),最终通过反射方式实现注入。

如果使用@Autowired注解,AutowiredAnnotationBeanPostProcessor拿到的injectedElements集合就不为空,AutowiredAnnotationBeanPostProcessor来完成注入的工作。
相反使用@Resource注解,CommonAnnotationBeanPostProcessor拿到集合injectedElements就不为空,由CommonAnnotationBeanPostProcessor来完成注入工作。

以上就是@Autowired 和 @Resource实现原理。

你可能感兴趣的:(spring,spring,java,后端)