The realization principle of @Autowire and @Value annotations in Spring

This article is mainly based on the explanations of SpringBoot-2.3.3.RELEASE and Spring-5.2.8.RELEASE. In
Spring @Autowire, the @Valuerealization principle of annotations, the liberation of these two annotations into one explanation is mainly because their implementation is basically the same.
This article relates @AutowireNotes: @Value, @Qualifier, @Lazy, @Primary, ,@javax.annotation.Priority

Related class introduction

The following are several important related classes:
org.springframework.beans.factory.config.BeanPostProcessor
org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.s.beans.factory.annotation.InjectionMetadata.InjectedElement
org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement
org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement

BeanPostProcessor

BeanPostProcessor is an interface class, all beans will pass through this post processor in the initial period, mainly providing the following two interface methods,

public interface BeanPostProcessor {
    
    
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
		return bean;
	}
}
  1. postProcessBeforeInitializationThe method is executed before the bean initialization method. For example, if the bean implements the InitializingBean interface, it will be InitializingBean#afterPropertiesSetexecuted before the method. (Not really, because look created bean, an BeanPostProcessorimplementation class is already registered)
    to BeanPostProcessor#postProcessBeforeInitializationwhether @PostConstructto perform initialization before the annotated method, which is uncertain , because the execution @PostConstruct initialization method is through the InitDestroyAnnotationBeanPostProcessorimplementation and InitDestroyAnnotationBeanPostProcessor By rewriting the BeanPostProcessor#postProcessBeforeInitialization@PostConstruct function, CommonAnnotationBeanPostProcessorit InitDestroyAnnotationBeanPostProcessorhas the same capabilities through inheritance . Therefore, it depends on the order in which the BeanPostProcessor implementation class is registered to determine whether it @PostConstructis executed in preference to annotations.

  2. postProcessAfterInitialization The method is executed after the bean's initialization method.

  3. The subclass interface of BeanPostProcessor is as follows UML diagram
    Insert picture description here

  4. AbstractAutowireCapableBeanFactory#initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd)The source code is as follows:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    
    
	if (System.getSecurityManager() != null) {
    
    
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    
    
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}else {
    
    
	    //判断是否实现了Aware接口,执行子类接口方法,
	    //此时只有:BeanNameAware,BeanClassLoaderAware,BeanFactoryAware
		invokeAwareMethods(beanName, bean); 
	}
	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
    
    
	    //调用BeanPostProcessor#postProcessBeforeInitialization
	    //ApplicationContextAwareProcessor#postProcessBeforeInitialization
	    //实现EnvironmentAware,..ApplicationContextAware等Aware的回调.
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}
	try {
    
    
	    //如果bean实现了InitializingBean接口则执行接口的afterPropertiesSet方法
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
    
    
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}
	if (mbd == null || !mbd.isSynthetic()) {
    
    
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}

MergedBeanDefinitionPostProcessor

@Autowire, @Value The search is AutowiredAnnotationBeanPostProcessorachieved by rewriting the method

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
    
    

	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
	
	default void resetBeanDefinition(String beanName) {
    
    
	}
}

BeanDefinitionMainly encapsulates the bean class information, such as whether it is a singleton, the name of the initialization method, the name of the dependent bean, and so on.

Before bean object is created, if a bean BeanDefinition is a subclass will first merge parent BeanDefinition, eventually return to a post-merger RootBeanDefinition, MergedBeanDefinitionPostProcessorit is Spring provided to interface development, and facilitate RootBeanDefinition combined to make custom modifications . Call AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)back the MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinitionmethod when it is called .

InstantiationAwareBeanPostProcessor

(See note)
@Autowire, @Value the assignment is AutowiredAnnotationBeanPostProcessorachieved by rewriting the postProcessPropertiesmethod

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    
    
    //创建bean对象实例之前执行
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    
    
		return null;
	}
    //创建bean对象实例之后执行
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    
    
		return true;
	}
    //用于给bean对象中的成员属性赋值
    //@Autowire,@Value的赋值就是AutowiredAnnotationBeanPostProcessor通过重写该方法实现
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {
    
    
		return null;
	}

	@Deprecated   //标记为过时
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    
    
		return pvs;
	}
}

AutowiredAnnotationBeanPostProcessor

@Autowire, @Value, @LookupAnd other annotations are made AutowiredAnnotationBeanPostProcessorto realize, in this paper to explain @Autowire, @Valuecomment function realization principle.
AutowiredAnnotationBeanPostProcessorInheritance are as follows:
Insert picture description here
AutowiredAnnotationBeanPostProcessora structure as follows: the main definition @Autowire, @Valuetwo annotations are filtered target bean conditions,
if the bean Field, Methodis marked two annotation is required attribute values corresponding to infuse or bean.

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.
		}
	}

In the process of realizing @Autowire and @Value functions, AutowiredAnnotationBeanPostProcessor mainly plays two roles.

  1. Rewriting MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinitionmethod, all reflecting traversal beanClass Fieldand Methodfind marked with bean @Autowire, @Valuea Field, , Methodencapsulated org.springframework.beans.factory.annotation.InjectionMetadatain. Stored in member variables private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);.

AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition Source code:

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    
    
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
	metadata.checkConfigMembers(beanDefinition);
}

findAutowiringMetadataThe method will be called internally to AnnotationUtils#isCandidateClass(Class<?>, Class<? extends Annotation>)
determine whether a certain class may be marked with a certain annotation. The source code is as follows:

public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
    
    
	return isCandidateClass(clazz, annotationType.getName());
}

public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
    
    
    //如果注解所在包是java开头,任何类上都可能标记这个注解
	if (annotationName.startsWith("java.")) {
    
    
		return true;
	}
	//注解所在包不是java开头的情况
	//可以认为是自定义注解,例如Spring的@Service @Autowired @Value 对Spring来说就是其自定义注解
	//如果类的包是以java开头,则不可能标记自定义的注解
	if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
    
    
		return false;
	}
	return true;
}

AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)

static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
    
    
	return (type.getName().startsWith("java.") || type == Ordered.class);
}
  1. Rewrite the InstantiationAwareBeanPostProcessor#postProcessPropertiesmethod, traverse the injectionMetadataCache InjectionMetadata, call the org.springframework.beans.factory.annotation.InjectionMetadata#injectmethod, @Autowireand @valueassign values to the bean and attribute fields.

AutowiredAnnotationBeanPostProcessor#postProcessProperties Source code:

@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;
}

InjectionMetadataThere is an abstractinternal class InjectionMetadata.InjectedElement, which is mainly used to give Fieldor Methodassign values.
AutowiredAnnotationBeanPostProcessorThere are two private inner classes inherited separately InjectedElement.

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: Assign values ​​to Field
AutowiredAnnotationBeanPostProcessor.AutowiredMethodElementthrough reflection.: Assign values ​​to Setter Method through reflection.

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#injectSource code:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    
    
	Field field = (Field) this.member;
	Object value;
	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);
	}
}

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValueSource code:

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");
	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;
}

The beanFactory.resolveDependency(default DefaultListableBeanFactory) overall logic called inside the method is roughly as follows:

  1. Judge Filedor Methodon whether there are @Lazynotes, if there is created brokers for lazy loading.
  2. If it is not lazy loading, it is judged whether there is an @Valueannotation. If it exists, the value value is obtained. Finally, by PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class<T>, boolean)parsing the property value ( in fact, it is ConfigurableEnvironmentthe MutablePropertySources collection encapsulated in ), after obtaining the property value, it will be analyzed by SpringEL. After parsing, the SimpleTypeConverterobject performs a data type conversion and returns to the type required by Filed.
  3. If there is no @Valuecomment, it is based on @Autowireinjecting the bean, the DefaultListableBeanFactoryvariable beanName all, determines whether the object type and the required identical, is saved to List beanName set (a plurality of the same interface implementation class may occur, so use set),
    • Traverse beanNames to determine whether each bean meets the requirements, if it exists, it @Qualifierwill determine whether the name matches, and if it matches, the corresponding bean object will be obtained. If there is no @Qualifierannotation, all bean objects are obtained and encapsulated in Map.
    • If there are multiple instance objects in the Map, then judge @Primarythe implementation class with annotations and return the object. @PrimaryThere can only be one implementation of the same type
    • If there are multiple instance objects in the Map, but there are no @Primaryannotations, compare whether there are @javax.annotation.Priorityannotations and choose the higher priority to return. The smaller the value, the higher the priority.
    • Match by name
    • If the above rules are not met, an exception message will be thrown and multiple bean implementations will appear.

The matching logic of dependency injection Bean in Spring is as follows
DefaultListableBeanFactory#determineAutowireCandidate

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
    
    
	Class<?> requiredType = descriptor.getDependencyType();
	String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
	if (primaryCandidate != null) {
    
    
		return primaryCandidate;
	}
	String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
	if (priorityCandidate != null) {
    
    
		return priorityCandidate;
	}
	// Fallback
	for (Map.Entry<String, Object> entry : candidates.entrySet()) {
    
    
		String candidateName = entry.getKey();
		Object beanInstance = entry.getValue();
		if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
				matchesBeanName(candidateName, descriptor.getDependencyName())) {
    
    
			return candidateName;
		}
	}
	return null;
}

Guess you like

Origin blog.csdn.net/u013202238/article/details/107879726