spring AutowiredFieldValueResolver 源码

  • 2022-08-08
  • 浏览 (384)

spring AutowiredFieldValueResolver 代码

文件路径:/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredFieldValueResolver.java

/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.aot;

import java.lang.reflect.Field;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.aot.hint.ExecutableMode;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.function.ThrowingConsumer;

/**
 * Resolver used to support the autowiring of fields. Typically used in
 * AOT-processed applications as a targeted alternative to the
 * {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
 * AutowiredAnnotationBeanPostProcessor}.
 * <p>
 * When resolving arguments in a native image, the {@link Field} being used must
 * be marked with an {@link ExecutableMode#INTROSPECT introspection} hint so
 * that field annotations can be read. Full {@link ExecutableMode#INVOKE
 * invocation} hints are only required if the
 * {@link #resolveAndSet(RegisteredBean, Object)} method of this class is being
 * used (typically to support private fields).
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @since 6.0
 */
public final class AutowiredFieldValueResolver extends AutowiredElementResolver {

	private final String fieldName;

	private final boolean required;

	@Nullable
	private final String shortcut;


	private AutowiredFieldValueResolver(String fieldName, boolean required,
			@Nullable String shortcut) {

		Assert.hasText(fieldName, "'fieldName' must not be empty");
		this.fieldName = fieldName;
		this.required = required;
		this.shortcut = shortcut;
	}


	/**
	 * Create a new {@link AutowiredFieldValueResolver} for the specified field
	 * where injection is optional.
	 * @param fieldName the field name
	 * @return a new {@link AutowiredFieldValueResolver} instance
	 */
	public static AutowiredFieldValueResolver forField(String fieldName) {
		return new AutowiredFieldValueResolver(fieldName, false, null);
	}

	/**
	 * Create a new {@link AutowiredFieldValueResolver} for the specified field
	 * where injection is required.
	 * @param fieldName the field name
	 * @return a new {@link AutowiredFieldValueResolver} instance
	 */
	public static AutowiredFieldValueResolver forRequiredField(String fieldName) {
		return new AutowiredFieldValueResolver(fieldName, true, null);
	}


	/**
	 * Return a new {@link AutowiredFieldValueResolver} instance that uses a
	 * direct bean name injection shortcut.
	 * @param beanName the bean name to use as a shortcut
	 * @return a new {@link AutowiredFieldValueResolver} instance that uses the
	 * shortcuts
	 */
	public AutowiredFieldValueResolver withShortcut(String beanName) {
		return new AutowiredFieldValueResolver(this.fieldName, this.required, beanName);
	}

	/**
	 * Resolve the field for the specified registered bean and provide it to the
	 * given action.
	 * @param registeredBean the registered bean
	 * @param action the action to execute with the resolved field value
	 */
	public <T> void resolve(RegisteredBean registeredBean, ThrowingConsumer<T> action) {
		Assert.notNull(registeredBean, "'registeredBean' must not be null");
		Assert.notNull(action, "'action' must not be null");
		T resolved = resolve(registeredBean);
		if (resolved != null) {
			action.accept(resolved);
		}
	}

	/**
	 * Resolve the field value for the specified registered bean.
	 * @param registeredBean the registered bean
	 * @param requiredType the required type
	 * @return the resolved field value
	 */
	@Nullable
	@SuppressWarnings("unchecked")
	public <T> T resolve(RegisteredBean registeredBean, Class<T> requiredType) {
		Object value = resolveObject(registeredBean);
		Assert.isInstanceOf(requiredType, value);
		return (T) value;
	}

	/**
	 * Resolve the field value for the specified registered bean.
	 * @param registeredBean the registered bean
	 * @return the resolved field value
	 */
	@Nullable
	@SuppressWarnings("unchecked")
	public <T> T resolve(RegisteredBean registeredBean) {
		return (T) resolveObject(registeredBean);
	}

	/**
	 * Resolve the field value for the specified registered bean.
	 * @param registeredBean the registered bean
	 * @return the resolved field value
	 */
	@Nullable
	public Object resolveObject(RegisteredBean registeredBean) {
		Assert.notNull(registeredBean, "'registeredBean' must not be null");
		return resolveValue(registeredBean, getField(registeredBean));
	}

	/**
	 * Resolve the field value for the specified registered bean and set it
	 * using reflection.
	 * @param registeredBean the registered bean
	 * @param instance the bean instance
	 */
	public void resolveAndSet(RegisteredBean registeredBean, Object instance) {
		Assert.notNull(registeredBean, "'registeredBean' must not be null");
		Assert.notNull(instance, "'instance' must not be null");
		Field field = getField(registeredBean);
		Object resolved = resolveValue(registeredBean, field);
		if (resolved != null) {
			ReflectionUtils.makeAccessible(field);
			ReflectionUtils.setField(field, instance, resolved);
		}
	}

	@Nullable
	private Object resolveValue(RegisteredBean registeredBean, Field field) {
		String beanName = registeredBean.getBeanName();
		Class<?> beanClass = registeredBean.getBeanClass();
		ConfigurableBeanFactory beanFactory = registeredBean.getBeanFactory();
		DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
		descriptor.setContainingClass(beanClass);
		if (this.shortcut != null) {
			descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut,
					field.getType());
		}
		Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		try {
			Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);
			Object value = ((AutowireCapableBeanFactory) beanFactory).resolveDependency(
					descriptor, beanName, autowiredBeanNames, typeConverter);
			registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
			return value;
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName,
					new InjectionPoint(field), ex);
		}
	}

	private Field getField(RegisteredBean registeredBean) {
		Field field = ReflectionUtils.findField(registeredBean.getBeanClass(),
				this.fieldName);
		Assert.notNull(field, () -> "No field '" + this.fieldName + "' found on "
				+ registeredBean.getBeanClass().getName());
		return field;
	}

}

相关信息

spring 源码目录

相关文章

spring AotServices 源码

spring AutowiredArguments 源码

spring AutowiredArgumentsCodeGenerator 源码

spring AutowiredElementResolver 源码

spring AutowiredMethodArgumentsResolver 源码

spring BeanDefinitionMethodGenerator 源码

spring BeanDefinitionMethodGeneratorFactory 源码

spring BeanDefinitionPropertiesCodeGenerator 源码

spring BeanDefinitionPropertyValueCodeGenerator 源码

spring BeanFactoryInitializationAotContribution 源码

0  赞