开发者

spring中自动注入注解的实现方式

目录
  • 类结构
  • 获取注解
  • 注入
    • Field 注入
    • Method 注入
  • 总结

    在前面的文章中,我们介绍过,基于注解的包扫描模式下,会默认注册一系列的后置处理器,其中,就包含一个 AutowiredAnnotationBeanPostProcessor,这个处理器默认就会处理 @Autowired@Value 注解。

    类结构

    spring中自动注入注解的实现方式

    从图中可知,这是一个 MergedBeanDefinitionPostProcessor 实现类,所以会在每一个实例对象创建时,当实例化结束,还未提前暴露时,对实例对象进行处理。

    // AutowiredAnnotationBeanPostProcessor
    @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) {
    	// 确定缓存 key
    	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    	// 从缓存获取 InjectionMetadata
    	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    	// metadata 为 null,python表示需要刷新
    	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
    				metadata = buildAutowiringMetadata(clazz);
    				// 放入缓存
    				this.injectionMetadataCache.put(cacheKey, metadata);
    			}
    		}
    	}
    	return metadata;
    }
    private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    	// autowiredAnnotationTypes 两种类型 @Autowired/@Value
    	if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
    		return InjectionMetadata.EMPTY;
    	}
    
    	List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    	Class<?> targetClass = clazz;
    
    	do {
    		final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    		
    		// 处理 Field 上注解
    		ReflectionUtils.doWithLocalFields(targetClass, field -> {
    			MergedAnnotation<?> ann = findAutowiredAnnotation(field);
    			if (ann != null) {
    				// static 不支持注入
    				if (Modifier.isStatic(field.getModifiers())) {
    					if (logger.isInfoEnabled()) {
    						logger.info("Autowired annotation is not supported on static fields: " + field);
    					}
    					return;
    				}
    				// 默认 true
    				boolean required = determineRequiredStatus(ann);
    				currElements.add(new AutowiredFieldElement(field, required));
    			}
    		});
    
    		// 处理 Method 上注解
    		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);
                    // Method 比 Field 多了 PropertyDescriptor
    				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
    				currElements.add(new AutowiredMethodElement(method, required, pd));
    			}
    		});
    
    		elements.addAll(0, currElements);
    		targetClass = targetClass.getSuperclass();
    	}
    	while (targetClass != null && targetClass != Object.class);
    
    	return InjectionMetadata.forElements(elements, clazz);
    }
    
    @Nullable
    private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
    	// TypeMappedAnnotations
    	MergedAnnotations annotations = MergedAnnotations.from(ao);
    	for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
    		// 获取指定 type 对应的 TypeMappedAnnotation,存在,将对应的 TypeMappedAnnotation 返回
    		MergedAnnotation<?> annotation = annotations.get(type);
    		if (annotation.isPresent()) {
    			return annotation;
    		}
    	}
    	return null;
    }

    可以看到,获取当前类及其父类中 Field 或 Method 上定义的注解,此时封装为 TypeMappedAnnotations,接着获取指定注入注解类型对应的 TypeMappedAnnotation,存在,返回 TypeMappedAnnotation,从中获取注解属性 "required" 对应的值,默认 true,之后将 Field 或 Method 封装成 InjectionMetadata.InjectedElement,加入 elements 集合,最后包装成 InjectionMetadata,放入 AutowiredAnnotationBeanPostProcessor 中 injectionMetadataCache 缓存。

    有一点要注意,就是 Method 注入时,虽然获取了 pd,但测试中 pd 为 null,也不影响注入,由此也说明注入的方法不一定必须是 setter 或 getter 方法。

    注入

    实例化完 bean 之后,进行属性填充,执行 AbstractAutowireCapableBeanFactory#populateBean,此时会http://www.devze.com调用 InstantiationAwareBeanPostProcessor#postProcessProperties,AutowiredAnnotationBeanPostProcessor 实现了这个方法。

    @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 前android面已经介绍过了,此时会直接从缓存获取到 InjectionMetadata。

    // InjectionMetadata
    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) {
    		OqInsfUNM	element.inject(target, beanName, pvs);
    		}
    	}
    }

    遍历,对每个 InjectedElement,调用 inject 方法。从上面介绍可知,InjectedElement 共两种,分别是针对 Field 的 AutowiredFieldElement,以及针对 Method 的 AutowiredMethodElement。下面分别介绍。

    Field 注入

    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    	Field field = (Field) this.member;
    	Object value;
    	// false
    	if (this.cached) {
    		try {
    			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    		}
    		catch (NoSuchBeanDefinitionException ex) {
    			// Unexpected removal of target bean for cached argument -> re-resolve
    			value = resolveFieldValue(field, bean, beanName);
    		}
    	}
    	else {
    		value = resolveFieldValue(field, bean, beanName);
    	}
    	if (value != null) {
            // 反射注入值
    		ReflectionUtils.makeAccessible(field);
    		field.set(bean, value);
    	}
    }
    @Nullable
    private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
    	DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
    	desc.setContainingClass(bean.getClass());
    	Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
    	Assert.state(beanFactory != null, "No BeanFactory available");
    	// 创建了一个 SimpleTypeConverter 作为 typeConverter
    	TypeConverter typeConverter = beanFactory.getTypeConverter();
    	Object value;
    	try {
    		// 解析依赖,对于基本类型,解析后经过转换返回包装类型
    		value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    	}
    	catch (BeansException ex) {
    		throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
    	}
    	synchronized (this) {
    		if (!this.cached) {
    			Object cachedFieldValue = null;
    			if (value != null || this.required) {
    				cachedFieldValue = desc;
    				registerDependentBeans(beanName, autowiredBeanNames);
    				if (autowiredBeanNames.size() == 1) {
    					String autowiredBeanName = autowiredBeanNames.iterator().next();
    					if (beanFactory.containsBean(autowiredBeanName) &&
    							beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
    						cachedFieldValue = new ShortcutDependencyDescriptor(
    								desc, autowiredBeanName, field.getType());
    					}
    				}
    			}
    			this.cachedFieldValue = cachedFieldValue;
    			this.cached = true;
    		}
    	}
    	return value;
    }

    逻辑比较简单,解析出注入的值,接着反射注入值。

    Method 注入

    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    	if (checkPropertySkipping(pvs)) {
    		return;
    	}
    	Method method = (Method) this.member;
    	Object[] arguments;
    	if (this.cached) {
    		try {
    			arguments = resolveCachedArguments(beanName);
    		}
    		catch (NoSuchBeanDefinitionException ex) {
    			// Unexpected removal of target bean for cached argument -> re-resolve
    			arguments = resolveMethodArguments(method, bean, beanName);
    		}
    	}
    	else {
    		// 解析参数
    		arguments = resolveMethodArguments(method, bean, beanName);
    	}
    	if (arguments != null) {
    		try {
    			// 反射调用方法,注入属性
    			ReflectionUtils.makeAccessible(method);
    			method.invoke(bean, arguments);
    		}
    		catch (InvocationTargetException ex) {
    			throw ex.getTargetException();
    		}
    	}
    }
    @Nullable
    private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
    	int argumentCount = method.getParameterCount();
    	Object[] arguments = new Object[argumentCount];
    	DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
    	Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
    	Assert.state(beanFactory != null, "No BeanFactory available");
    	TypeConverter typeConverter = beanFactory.getTypeConverter();
    	// 解析每一个参数
    	for (int i = 0; i < arguments.length; i++) {
    		// 封装 MethodParameter
    		MethodParameter methodParam = new MethodParameter(method, i);
    		// 封装 DependencyDescriptor
    		DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
    		currDesc.setContainingClass(bean.getClass());
    		descriptors[i] = currDesc;
    		try {
    			// 解析依赖,required 默认 true,遇见无法解析的直接抛出异常
    			Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
    			if (arg == null && !this.required) {
    				arguments = null;
    				break;
    			}
    			// 构造参数
    			arguments[i] = arg;
    		}
    		catch (BeansException ex) {
    			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
    		}
    	}
    	synchronized (this) {
    		if (!this.cached) {
    			if (arguments != null) {
    				DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
    				registerDependentBeans(beanName, autowiredBeans);
    				if (autowiredBeans.size() == argumentCount) {
    					Iterator<String> it = autowiredBeans.iterator();
    					Class<?>[] paramTypes = method.getParameterTypes();
    					for (int i = 0; i < paramTypes.length; i++) {
    						String autowiredBeanName = it.next();
    						if (beanFactory.containsBean(autowiredBeanName) &&
    								beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
    							cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
    									descriptors[i], autowiredBeanName, paramTypes[i]);
    						}
    					}
    				}
    				this.cachedMethodArguments = cachedMethodArguments;
    			}
    			else {
    				this.cachedMethodArgumentOqInsfUNMs = null;
    			}
    			this.cached = true;
    		}
    	}
    	return arguments;
    }

    可以看到,不管是 Field 注入还是 Method 注入,都是先封装出一个 DependencyDescriptor,接着执行 beanFactory.resolveDependency 进行依赖的解析,不同点在于 Field 解析完就返回了,而 Method 解析完是为了构造出参数数组。

    之后,不管是 Field 注入,还是 Method 注入,都是利用反射完成注入。这也说明,Method 注入时,只要能正常的封装出参数数组,就能完成属性或字段注入。

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜