栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 elements = new linkedList();
		Class targetClass = clazz;

		do {
			final linkedList currElements =
					new linkedList();

			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 elements = new ArrayList<>();
		Class targetClass = clazz;

		do {
			final List 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 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)
					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实现原理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/396843.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号