spring5.3 八:依赖注入源码分析下

@Resource注解底层工作流程图
在这里插入图片描述

@Resource自动注入

@Resource实现的子类是CommonAnnotationBeanPostProcessor。和@Autowired一样,CommonAnnotationBeanPostProcessor也是先执行postProcessMergedBeanDefinition方法,后续再执行postProcessProperties。而postProcessMergedBeanDefinition同样时先找注入点然后缓存起来,postProcessProperties把缓存的注入点找出来进行依赖注入处理。

@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
		//获取找到的注入点(被@resource标记的属性或者方法)
		InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}
	
private InjectionMetadata findResourceMetadata(String beanName, final 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);
					}
					//在注入点 被@resource标记的
					//核心方法
					metadata = buildResourceMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			//在do while中遍历字段 调用lambda表达式
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				//不用管
				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 (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@EJB annotation is not supported on static fields");
					}
					currElements.add(new EjbRefElement(field, field, null));
				}
				//找到被@resource标记的字段 加入到currElements这个集合中
				else if (field.isAnnotationPresent(Resource.class)) {
					//如果@resource标记的是静态资源 会抛异常
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@Resource annotation is not supported on static fields");
					}
					if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
						//构造ResourceElement 构造的时候回解析@resource的属性值 比如name  type  和 有没有懒加载
						currElements.add(new ResourceElement(field, field, null));
					}
				}
			});
			//在do while中遍历方法 调用lambda表达式
			//也是寻找被@resource标记的方法
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				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.getParameterCount() != 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 (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@EJB annotation is not supported on static methods");
						}
						if (method.getParameterCount() != 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 (!this.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 InjectionMetadata.forElements(elements, clazz);
	}

这部分和@Autowired差不多,通过反射获取到bean的属性和方法,通过判断有没有@Resource注解,有的话判断一些其他条件,然后把符合的封装一层缓存起来。
到了属性填充阶段执行postProcessProperties

@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		//获取找到的注入点(被@resource标记的属性或者方法)
		InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
		try {
			//属性注入 调用的是InjectedElement的inject
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
		}
		return pvs;
	}

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

			if (this.isField) {
				Field field = (Field) this.member;
				ReflectionUtils.makeAccessible(field);
				// getResourceToInject  核心方法  通过属性找到对应的bean
				// 调的是ResourceElement的getResourceToInject
				field.set(target, getResourceToInject(target, requestingBeanName));
			}
			else {
				if (checkPropertySkipping(pvs)) {
					return;
				}
				try {
					Method method = (Method) this.member;
					ReflectionUtils.makeAccessible(method);
					//通过方法参数找到对应的bean
					method.invoke(target, getResourceToInject(target, requestingBeanName));
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

这部分流程就是拿到之前缓存的注入点开始注入。判断是不是懒加载,如果是懒加载生成代理类。如果不是懒加载,判断容器是否存在注入点名字的bean或者@Resource有没有指定name属性,如果满足其中一个条件,会执行getBean(name)方法获取bean。如果不满足就和@Autowired现根据类型找bean,再根据name确定bean。

依赖注入总结

  1. 先根据spring的自动注入就是@Bean(autowire = Autowire,BY_TYPE) 进行判断。这个方法已经过期,一般不会触发这个判断,可以忽略。
  2. 在BeanDefinition后置处理的时候开始找注入点,对于被 @Autowired、@Value、@Inject、@Resource注解标记的方法或属性
  3. 属性填充阶段开始属性注入,找出之前缓存的注入点,处理@Value、再处理@Autowired
  4. @Autowired先根据类型在容器和父容器中找到符合类型的bean的名称,通过一个责任链模式(涉及@Qualifier的处理)去过滤不符合的bean的名称,
  5. 如果只有一个bean就直接返回,如果找到多个bean,判断@Primary 在判断@Priority 。如果还有多个在根据名称筛选唯一一个。
  6. 然后根据筛选处来的beanName实例化bean,通过反射赋值给目标对象。
  7. 如果注入点上标注的注解是@Resource,判断容器是否存在注入点名字的bean或者@Resource有没有指定name属性。如果满足其中一个条件,会执行getBean(name)方法获取bean。
  8. 如果不满足上述条件,就执行和@Autowired一样的逻辑
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值