Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Preface: This article is mainly about the Spring container startup process is mainly done in the way of the problem may not involve too much detail, I hope you can read this article to have a simple understanding of Spring source code.
Environment introduction:
- Spring 5.3.10
- Jdk 11
In the previous article we looked at the object creation process in getBean Spring, Today we continue to analyze AbstractAutowireCapableBeanFactory# populateBean method Spring to fill Bean object (actually we said the process of automatic injection)
Get field information
Gets the field information for the Bean
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
Copy the code
Find the Bean’s schema
There are two common modes for looking up beans: AUTOWIRE_BY_NAME or AUTOWIRE_BY_NAME
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; }Copy the code
1. Search by Bean name
Query beans through BeanName and add them to PVS.
protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues PVS) {/ / get the basic attribute of type String [] the putobject = unsatisfiedNonSimpleProperties (MBD, bw); for (String propertyName : BeanName if (containsBean(propertyName)) {// getBean Object bean = getBean(propertyName); pvs.add(propertyName, bean); registerDependentBean(propertyName, beanName); if (logger.isTraceEnabled()) { logger.trace("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'"); } } else { if (logger.isTraceEnabled()) { logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found"); }}}}Copy the code
2. Search by Bean type
protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } Set<String> autowiredBeanNames = new LinkedHashSet<>(4); String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : PropertyNames) {try {// getPropertyDescriptor pd = bw. Getpropertynames (propertyName); // getPropertyDescriptor pd = bw. // Don't try autowiring by type for type Object: Never makes sense, // even if it is technically an unsatisfied, non-simple property. // Exclude Object type if (object.class! = pd. GetPropertyType ()) {/ / get geng method MethodParameter methodParam = BeanUtils. GetWriteMethodParameter (pd); // Do not allow eager init for type matching in case of a prioritized post-processor. boolean eager = ! (bw.getWrappedInstance() instanceof PriorityOrdered); DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); // Parse the value matched by the beanName attribute, Store the resolved property names in autowiredBeanNames // All matching beans will be found when the property exists in an encapsulated bean and injected into Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); if (autowiredArgument ! = null) { pvs.add(propertyName, autowiredArgument); } // loop autowiredBeanNames for (String autowiredBeanName: autowiredBeanNames) { registerDependentBean(autowiredBeanName, beanName); if (logger.isTraceEnabled()) { logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + autowiredBeanName + "'"); } } autowiredBeanNames.clear(); } } catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); }}}Copy the code
3. Several important methods
- unsatisfiedNonSimpleProperties
This is an attribute whose type is object type, but not all object types will be found. For example, the eight primitive types, String, Number, Date, URL, URI, etc., will be ignored
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) { Set<String> result = new TreeSet<>(); PropertyValues pvs = mbd.getPropertyValues(); PropertyDescriptor[] pds = bw.getPropertyDescriptors(); for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() ! = null && ! isExcludedFromDependencyCheck(pd) && ! pvs.contains(pd.getName()) && ! BeanUtils.isSimpleProperty(pd.getPropertyType())) { result.add(pd.getName()); } } return StringUtils.toStringArray(result); }Copy the code
- registerDependentBean
Save the mapping for property injection
public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (! dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); }}Copy the code
- resolveDependency
Look up dependencies by type
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); } else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); } else { Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } } // public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); Try {// Given a shortcut implementation for a given factory, such as considering some pre-parsed information // The parsing algorithm will first try to resolve the shortcut through this method before going into the normal type-matching algorithm for all beans. / / Object subclasses can override this method shortcut = descriptor. ResolveShortcut (this); if (shortcut ! = null) { return shortcut; } // Find the dependent type Class<? > type = descriptor.getDependencyType(); / / @ the Value for Value Object Value = getAutowireCandidateResolver () getSuggestedValue (descriptor); if (value ! = null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName ! = null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter ! = null ? typeConverter : getTypeConverter()); try { return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { // A custom TypeConverter which does not support TypeDescriptor resolution... return (descriptor.getField() ! = null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); }} // Parse the compound type bean // include: Array, Collection, Map Object multipleBeans = resolveMultipleBeans(Descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans ! = null) { return multipleBeans; } // Return the key beanName value bean instance Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); If (MatchingBeans.isEmpty ()) {// find a matching value if (isRequired(Descriptor)) {// Throw an exception if @AutoWired is not found and the required attribute is true raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; If (matchingBeans.size() > 1) {// Confirm candidates for the given bean autowire // autowiredBeanName = in order of @primary and @priority determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || ! indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // Possibly it was meant to bean empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). return null; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // We have exactly one match. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames ! = null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } result = null; } if (! ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass()); } return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); }}Copy the code
Set the value of the Bean property
The operation of assigning a property, which is encapsulated in the instance object PVS of PropertyValues, is not applied to the bean
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs.isEmpty()) { return; } if (System.getSecurityManager() ! = null && bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } MutablePropertyValues mpvs = null; // List<PropertyValue> original; If (PVS instanceof MutablePropertyValues) {MPVS = (MutablePropertyValues) PVS; If (mpvs.isconverted ()) {// Shortcut: use the pre-converted values as-is.try {// in line with bw. SetPropertyValues (MPVS); return; } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } original = mpvs.getPropertyValueList(); } else { original = Arrays.asList(pvs.getPropertyValues()); } // Custom converter TypeConverter converter = getCustomTypeConverter(); If (Converter == null) {// There is no use of the default type conversion converter = bw; } / / get the parser BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver (this, beanName, MBD, the converter); List<PropertyValue> deepCopy = new ArrayList<>(original.size()); boolean resolveNecessary = false; for (PropertyValue pv : original) { if (pv.isConverted()) { deepCopy.add(pv); } else { String propertyName = pv.getName(); OriginalValue = pv.getValue(); if (originalValue == AutowiredPropertyMarker.INSTANCE) { Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod(); if (writeMethod == null) { throw new IllegalArgumentException("Autowire marker for property without write method: " + pv); } originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true); } Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); // Object convertedValue = resolvedValue; boolean convertible = bw.isWritableProperty(propertyName) && ! PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); If (convertible) {convertedValue = convertForProperty(resolvedValue, propertyName, bw, Converter); if (convertedValue = convertForProperty(resolvedValue, propertyName, BW, Converter); } // Possibly store converted value in merged bean definition, // in order to avoid re-conversion for every created bean instance. if (resolvedValue == originalValue) { if (convertible) {// Save pv.setconvertedValue (convertedValue); } // save pv deepCopy. Add (pv); } else if (convertible && originalValue instanceof TypedStringValue && ! ((TypedStringValue) originalValue).isDynamic() && ! (convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); // Rewrap the value of the attribute deepCopy. Add (pv); } else { resolveNecessary = true; deepCopy.add(new PropertyValue(pv, convertedValue)); } } } if (mpvs ! = null && ! ResolveNecessary) {// the tag has converted mpvs. set.php (); } // Set our (possibly Massaged) deep copy. Try {// Bw. setPropertyValues(new MutablePropertyValues(deepCopy)); } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); }}Copy the code
Reference documentation
- spring.io
- Blog.csdn.net/qq330983778…