General documentation: Article directory Github: github.com/black-ant
A. The preface
Where the previous article took stock of SpringIOC: Bean creation main process, this article injects the second major step property
Let’s look at a very common picture, from @Topjava. Cn/article / 139…
1.1 What does attribute injection in this document contain?
PS: I stumbled upon the fact that this article cannot be limited to PopulateBeans, so I will continue to improve the following information in this section, if you are interested!
The main scope of Bean property processing is to inject beans. According to our general understanding, Bean injection mainly includes three injection modes: property/constructor/setter
- Method one: Through the constructor @Autowired main flow
- Method 2: @autowired main flow via properties
- Mode 3: @autowired the main process via setter mode
Method one: Through the constructor @Autowired main flow
@Autowired
public AutowiredService(CommonService commonService, BeanAService beanAService) {
this.commonService = commonService;
this.beanAService = beanAService;
}
Copy the code
CreateBeanInstance (beanName, MBD, args) is executed in the doCreateBean method
// As you can see, in BeanWrapper, two Autowired objects are already processed
// This is triggered by the following code in createBeanInstance:Constructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if(ctors ! =null|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);
}
// autowireConstructor core codeC- ConstructorResolver M- autowireConstructorCopy the code
Method 2: @autowired main flow via properties
As you can see in the figure above, neither of the properties starts loading after createBeanInstance, but we know that the injection of the properties is done before initializeBean to ensure that the initialization method is available.
/ /, when dealing with populateBean to InstantiationAwareBeanPostProcessor processing, which mainly include these
org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
/ /...Finally is the core of AutowiredAnnotationBeanPostProcessor, this we behind populateBean speak in detailCopy the code
Mode 3: setter
/ / way sanhe way two types, the PostProcessor processing, mainly org. Springframework. Beans. Factory. The annotation. AutowiredAnnotationBeanPostProcessor
Copy the code
2. Property injection process
Unlike AutoWired above, what else does populateBean primarily handle?
To better understand the process, make a distinction here that in addition to autowired injection properties, there is an important concept in populateBean called PropertyValues
TODO: There is a big problem with this part, the source of which has never been understood, and most of the reference materials have been skimped on// We'll look at it later in the evening. We guess it's because the old XML way of building objects has a property property
// If there are any clear ones, please mention them. Thank you very much
Copy the code
Let’s take a closer look at the property injection process
2.1 Entry for attribute injection
C - AbstractAutowireCapableBeanFactory M173_05 - doCreateBean (beanName mbdToUse, args) : create Bean object - populateBean: Property Injection Operation -> M173_30Copy the code
2.2 Main process of attribute injection
The main process of injecting properties is in doCreateBean. Recall the concept of circular dependencies. Before populateBean is called, an object has been generated that has not completed the related property injection
First take a look at the properties passed in
populateBean(beanName, mbd, instanceWrapper);
PS: Property injection is done before InitializingBean, so the related initialization method can be used with @Autowired object, more on this later
Property to inject the populateBean logic
The overall logic is divided into 7 steps:
- Step 1: Processing the empty instance of BeanWrapper. The empty instance must be judged and processed before instantiation
- Use BeanPostProcessors instead
- Step 3: Inject properties into the bean
- Step 4: determine whether registered InstantiationAwareBeanPostProcessors and whether to need to rely on tests
- Step 5: BeanPostProcessor processing, here is mainly InstantiationAwareBeanPostProcessor processing
- Step 6: Dependency check
- Step 7 : applyPropertyValues(beanName, mbd, bw, pvs)
C173- AbstractAutowireCapableBeanFactory
M173_30- populateBean(String beanName, RootBeanDefinition mbd,BeanWrapper bw)
P- String beanName
P- RootBeanDefinition mbd
P- @Nullable BeanWrapper bw
1-BeanWrapper empty instance handling: If BeanWrapper is empty and MBD has a value, the empty instance cannot be initialized. Throw a BeanCreationException. If BeanWrapper is empty and MBD has no attribute, Direct return2-Beanpostprocessors? - This is the PostProcesssors last loadopportunity. This method defaults for if-bean initialization when defining a bean. Bean InstantiationAwareBeanPostProcessor - > the FOR - all iterations BeanPostProcessors: getBeanPostProcessors - InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation ? - When the return value isfalseTo stop the entire bean property injection directlyreturnTo skip the property injection operation3- Inject properties to the bean -newMutablePropertyValues(PVS) -- get the PropertyValues of the bean -- PropertyValues PVS = (mbd.haspropertyvalues ()? mbd.getPropertyValues() :null) -- PVS sources-Determine if there are auto-injected annotations -> Auto-injected properties - encapsulate PropertyValues into a MutablePropertyValues object, Property on the object allows for simple operations - > PS: M173_30_3 - by MBD. GetResolvedAutowireMode () name is the difference between injection or type injection - > different types of injection - > PS: M173_30_4 - AUTOWIRE_BY_NAME -- autowireByName(beanName, mbd, bw, newPvs); - AUTOWIRE_BY_TYPE -- autowireByType(beanName, mbd, bw, newPvs);4- determine whether registered InstantiationAwareBeanPostProcessors and whether to need to rely on check (needsDepCheck) - registration: HasInstantiationAwareBeanPostProcessors () - rely on check: MBD getDependencyCheck ()! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE5- when the step4Indicates that processing by BeanPostProcessor is required, that is, hasInstAwareBpps + BeanPostProcessor is not empty - PVS isnullThrough MBD. GetPropertyValues (); Get a -- iterate over the BeanPostProcessor array,instanceofInstantiationAwareBeanPostProcessor, pre-processing of Bean - PropertyValues = ibp. PostProcessProperties (PVS. bw.getWrappedInstance(), beanName); -- Obtain PropertyValues. - If PropertyValues isnullBy ibp. PostProcessPropertyValues (PVS, filteredPds, bw. GetWrappedInstance (), beanName); Complete build - filteredPds = filterPropertyDescriptorsForDependencyCheck (bw, MBD allowCaching);6- rely on check - filteredPds = filterPropertyDescriptorsForDependencyCheck (bw, MBD allowCaching); - checkDependencies(beanName, mbd, filteredPds, pvs); -- Dependency checking, corresponding to the depends-on attribute7- applyPropertyValues(beanName, mbd, bw, pvs); C175- AbstractBeanDefinition: MutablePropertyValues class M175_01- getResolvedAutowireMode: Get the type of AutowiredCopy the code
PS:M173_30_3 MutablePropertyValues
Allows simple property manipulation and provides constructors to support deep copying and construction from maps
C190- MutablePropertyValues
F190_01- List<PropertyValue> propertyValueList
F190_02- Set<String> processedProperties
Copy the code
PS:M173_30_4 was injected through different types
C173- AbstractAutowireCapableBeanFactory M173_10- autowireByName : According to the attribute name, Complete automatic dependency injection - get non-simple properties of Bean objects (objects of non-basic types) FOR- loop through the array of properties, Get related bean by name recursively - add related bean to MutablePropertyValues - registerDependentBean(propertyName, beanName); - Map<String, Set<String>> dependentBeanMap : BeanName - > rely on beanName collection - Map < String, Set the < String > > dependenciesForBeanMap: rely on beanName - > beanName collection -1Get beanName -2Add <canonicalName, <dependentBeanName>> to a dependentBeanMap -3Add < <canonicalName>> to dependenciesForBeanMap M173_11- autowireByType: Do automatic dependency injection based on the attribute type - the overall approach is similar to byName, where the logic is to find the attribute that needs dependency injection and then iteratively find the bean that matches itCopy the code
M173_10 autowireByName source
protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
// Check whether the Bean is loaded
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
// Register a dependent bean for the given bean so that the given bean can be destroyed before it is destroyed
registerDependentBean(propertyName, beanName);
/ /... log
}
else {
/ /... log}}}// Pro 1: containsBean details-containsBeanDefinition: -containsBeandefinition: BeanDefinitionMap. Either containsKey (beanName), registerBeanDefinition add - parentBeanFactory. ContainsBean: from the Parent// Pro 2: registerDependentBean logic, which does several things
public void registerDependentBean(String beanName, String dependentBeanName) {
// Determine the original name and resolve the alias to the canonical name, which is essentially a loop to aliasMap
String canonicalName = canonicalName(beanName);
// Lock the dependentBeanMap to ensure that multiple threads are unique
DependentBeanMap: a collection of dependentBean names to dependentbean names
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans =this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if(! dependentBeans.add(dependentBeanName)) {return; }}DependenciesForBeanMap: a collection of bean names to which I am dependent
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); }}// PS: dependentBeanMap and dependenciesForBeanMap
https://blog.csdn.net/xieyinghao_bupt/article/details/109552054
Copy the code
M173_11 autowireByType source
Ps: There are too few cases here at the beginning, I didn’t understand, I turned over the series of notes, and finally figured it out
This section refers to IOC, only part of the logic is added
protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// Define the interface to the type conversion method
// Use a custom TypeConverter to replace the default PropertyEditor mechanism
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
// If the above interface is null, BeanWrapper will be used directly
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// Get non-simple attributes
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// Iterate over the propertyName array
for (String propertyName : propertyNames) {
try {
// Obtain the PropertyDescriptor instance
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
if(Object.class ! = pd.getPropertyType()) {// Probe the set method of the specified property
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
booleaneager = ! (bw.getWrappedInstance()instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// Parse the value of the attribute specified by beanName and store the name of the parsed attribute in autowiredBeanNames
// When an attribute exists over a encapsulated bean, all matching beans will be found and injected
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if(autowiredArgument ! =null) {
pvs.add(propertyName, autowiredArgument);
}
// Iterate over the autowiredBeanName array
for (String autowiredBeanName : autowiredBeanNames) {
// Attribute dependency injectionregisterDependentBean(autowiredBeanName, beanName); } autowiredBeanNames.clear(); }}catch (BeansException ex) {
throw newUnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); }}} PS: autowireByType can pass@Bean(initMethod = "initMethod", autowire = Autowire.BY_TYPE)Triggers:Pro 1: PropertyDescriptor objectFunction: PropertyDescriptor describes a property method exported by a Java bean using a pair of accessor methods. GetPropertyDescriptor: gets a PropertyDescriptor for a specific property of the wrapped object// Pro 2 : BeanUtils.getWriteMethodParameter(pd)-method writeMethod = pd.getwritemethod () : gets the Method applied to the value of the write property -> PS:M173_11_01 -new MethodParameter(writeMethod, 0)
// Pro 3 : DependencyDescriptorDescriptor for the specific dependency to be injected. Wraps constructor parameters, method parameters, or fields to allow uniform access to their metadata.Copy the code
PS:M173_11_01 you can see here is the setter method
A question about the default injection type
AUTOWIRE_NO: AUTOWIRE_NO: AUTOWIRE_NO: AUTOWIRE_NO: AUTOWIRE_NO: AUTOWIRE_NO
public int getResolvedAutowireMode(a) {
if (this.autowireMode == AUTOWIRE_AUTODETECT) {
// Work out whether to apply setter autowiring or constructor autowiring.
// If it has a no-arg constructor it's deemed to be setter autowiring,
// otherwise we'll try constructor autowiring.Constructor<? >[] constructors = getBeanClass().getConstructors();for(Constructor<? > constructor : constructors) {if (constructor.getParameterCount() == 0) {
returnAUTOWIRE_BY_TYPE; }}return AUTOWIRE_CONSTRUCTOR;
}
else {
return this.autowireMode; }}Copy the code
ResolveDependency details
ResolveDependency method mainly is called autowireByType, moreover also is involved in AutowiredAnnotationBeanPostProcessor
What it does: resolves the specified dependencies against the beans defined in this factory
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);
}
returnresult; }}Copy the code
PS: M173_30_5 InstantiationAwareBeanPostProcessor structure
Subinterface functions of BeanPostProcessor: Add a callback function before instantiation and a callback function after instantiation but before explicit property setting or autoliring has occurred. Create agents with special target sources (pooled targets, delayed initialization targets, etc.) to implement additional injection policy features: This interface, in addition to BeanPostProcessor default postProcessBeforeInstantiation, postProcessAfterInstantiation method, There will be an additional method postProcessProperties, postProcessPropertyValues
// public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor
/ / here by inherited hasInstantiationAwareBeanPostProcessors determine whether related objects
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Pro 1: starting point for configuration
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
/ / PS: hasInstantiationAwareBeanPostProcessors attributable to the parent class AbstractBeanFactory
private volatile boolean hasInstantiationAwareBeanPostProcessors;
/ /...
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Pro 2: Property Settings
// As you can see, the switch is configured in addBeanPostProcessor
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.remove(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
this.beanPostProcessors.add(beanPostProcessor);
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / Pro 3: look at the InstantiationAwareBeanPostProcessor calls
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
/ / Step 3: BeanPostProcessors processing, mainly postProcessAfterInstantiation pre-processing
/ / PS: there is only inherited InstantiationAwareBeanPostProcessor class postProcessAfterInstantiation can proceed
/ /...
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return; }}}}/ /...
/ / Step 5: BeanPostProcessor processing, here is mainly InstantiationAwareBeanPostProcessor processing
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/ / implementation InstantiationAwareBeanPostProcessor postProcessProperties
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
/ / implementation InstantiationAwareBeanPostProcessor postProcessPropertyValues
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return; } } pvs = pvsToUse; }}}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
4: / / Pro postProcessProperties and postProcessPropertyValues rolePostProcessProperties: - at the factory before the application of the attribute value of a given to a given bean for reprocessing, do not need any property descriptors. PostProcessPropertyValues: - Post-process the given attribute values before the factory applies them to the given bean. - allows replacement of the PropertyValues to be applied, usually by creating a new MutablePropertyValues instance based on the original PropertyValues, adding or removing specific valuesCopy the code
2.3 Functions of PropertyValue and applyPropertyValues
Throughout the process, a property called PropertyValue appears repeatedly. Let’s take a look at the past and present
// M173_11 source code
// TODO C173 - AbstractAutowireCapableBeanFactory M173_15 - applyPropertyValues: attributes into operation? - The previous operation is just to complete the acquisition of all injected properties and encapsulate the acquired properties in the instance PVS of PropertyValues? - Here attributes are applied to the bean that has been instantiated1- BeanWrapperImpl.setSecurityContext ? - Set the SecurityContext property of BeanWrapperImpl2- Prepare properties - MutablePropertyValues MPVS -list <PropertyValue> Original3- to obtain attribute set - the original = MPVS. GetPropertyValueList () : / original = Arrays.aslist (pvs.getPropertyValues())// There is an intermediate node: if the configuration is complete, then return
4- Prepare property - TypeConverter Converter = getCustomTypeConverter() -new BeanDefinitionValueResolver(this, beanName, MBD, Converter) : used to parse unparsed objects - List<PropertyValue> deepCopy =new ArrayList<>(original.size())
5- For loop List<PropertyValue> original to convert PropertyValue? - Determine whether the property value is converted. Non-mutablepropertyvalues will use the original type directly. - Otherwise, obtain propertyName and originalValue first// Note that Autowired processing is performed here- If the type is Autowired - Method writeMethod = bw.getPropertyDescriptor(propertyName).getwritemethod ()? In the case of Autowired property, get the property descriptor for the particular property of the wrapper object and then get the method applied to write the property value -new DependencyDescriptor(new MethodParameter(writeMethod, 0), true)? - Creates a new descriptor for a method or constructor parameter// Note that the property transformation starts here and is divided into two steps
5.1- convertedValue = valueResolver.resolveValueIfNecessary ? - Given PropertyValue, return a value that resolves any references to other beans in the factory if necessary5.2- convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter) ? - If writable and not given attribute path indicates index or nested attribute - setConvertedValue + added to4Step List<PropertyValue> deepCopy collection6- Inject the core: set the property values for the property -- bw.setpropertyValues (MPVS);Copy the code
M173_15 applyPropertyValues source code
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
// Step 1: Set BeanWrapperImpl's SecurityContext property
if(System.getSecurityManager() ! =null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
// Step 2: Prepare attributes
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
// Step 3: Get the property set
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// Return directly after conversion
if (mpvs.isConverted()) {
try {
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());
}
// Step 4: Prepare attributes
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// Step 5: Attribute loop transformation
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object 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;
booleanconvertible = bw.isWritableProperty(propertyName) && ! PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);if (convertible) {
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) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceofTypedStringValue && ! ((TypedStringValue) originalValue).isDynamic() && ! (convertedValueinstanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(newPropertyValue(pv, convertedValue)); }}}if(mpvs ! =null && !resolveNecessary) {
mpvs.setConverted();
}
// Step 6: Inject the core
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex); }}Copy the code
conclusion
It looks like a long time, but after looking back at the series, I feel that there are still a lot of places I haven’t understood, and I have time to fill in the pit later
It’s too late to beat the curls. Go to bed
The appendix
Appendix I: M173_30 populateBean core code
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// The empty instance of BeanWrapper must be determined and processed before instantiation
if (bw == null) {
// If BeanWrapper is empty and MBD has a value, the empty instance cannot be initialized, throw BeanCreationException
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// If BeanWrapper is empty and MBD has no attribute, return
return; }}// isSynthetic: returns whether the bean definition is "synthetic", i.e. not defined by the application itself
/ / hasInstantiationAwareBeanPostProcessors: hold InstantiationAwareBeanPostProcessor bean
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// Loop all
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/ / here will only handle InstantiationAwareBeanPostProcessor
if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return; }}}}// Get the value of the bean property
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// Check whether there is an auto-injected annotation -> Auto-injected attribute
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// Encapsulate PropertyValues into a MutablePropertyValues object that allows simple manipulation of properties -> PS:M173_30_3
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
/ / by MBD. GetResolvedAutowireMode () difference is that the name injection or type injection - > different types of injection - > PS: M173_30_4
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
/ / determine whether registered InstantiationAwareBeanPostProcessors and whether to need to rely on to check (needsDepCheck)
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
booleanneedsDepCheck = (mbd.getDependencyCheck() ! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds =null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return; } } pvs = pvsToUse; }}}if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// The dependency check corresponds to the depends-on attribute
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if(pvs ! =null) {
// Apply attributes to the beanapplyPropertyValues(beanName, mbd, bw, pvs); }}Copy the code
Appendix II: autowireConstructor Main method TODO
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@NullableConstructor<? >[] chosenCtors,@Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw); Constructor<? > constructorToUse =null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
if(explicitArgs ! =null) {
argsToUse = explicitArgs;
}
else {
Object[] argsToResolve = null;
synchronized(mbd.constructorArgumentLock) { constructorToUse = (Constructor<? >) mbd.resolvedConstructorOrFactoryMethod;if(constructorToUse ! =null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; }}}if(argsToResolve ! =null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); }}if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.Constructor<? >[] candidates = chosenCtors;if (candidates == null) { Class<? > beanClass = mbd.getBeanClass();try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(...);
}
}
if (candidates.length == 1 && explicitArgs == null&&! mbd.hasConstructorArgumentValues()) { Constructor<? > uniqueCandidate = candidates[0];
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
returnbw; }}// Need to resolve the constructor.
booleanautowiring = (chosenCtors ! =null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if(explicitArgs ! =null) {
minNrOfArgs = explicitArgs.length;
}
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
AutowireUtils.sortConstructors(candidates);
intminTypeDiffWeight = Integer.MAX_VALUE; Set<Constructor<? >> ambiguousConstructors =null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for(Constructor<? > candidate : candidates) {int parameterCount = candidate.getParameterCount();
if(constructorToUse ! =null&& argsToUse ! =null && argsToUse.length > parameterCount) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (parameterCount < minNrOfArgs) {
continue; } ArgumentsHolder argsHolder; Class<? >[] paramTypes = candidate.getParameterTypes();if(resolvedValues ! =null) {
try {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if(pnd ! =null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue; }}else {
// Explicit arguments given -> arguments length must match exactly.
if(parameterCount ! = explicitArgs.length) {continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if(constructorToUse ! =null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = newLinkedHashSet<>(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); }}if (constructorToUse == null) {
if(causes ! =null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw newBeanCreationException(...) ; }else if(ambiguousConstructors ! =null && !mbd.isLenientConstructorResolution()) {
throw newBeanCreationException(...) ; }if (explicitArgs == null&& argsHolderToUse ! =null) { argsHolderToUse.storeCache(mbd, constructorToUse); } } Assert.state(argsToUse ! =null."Unresolved constructor arguments");
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
Copy the code
Appendix III: Injection timing of @value
TODO
Copy the code