preface
In the previous doCreateBean method, we learned that populateBean is responsible for populating the Bean instance properties. At this time in Bean members need to dependency injection have in applyMergedBeanDefinitionPostProcessors corresponding post processor for the storage, Final members are encapsulated by AutowiredAnnotationBeanPostProcessor# injectionMetadataCache this collection.
1. Dependencies and Dependency Injection
Many people may not be clear about what dependency and dependency injection are. This is a core concept in understanding Spring IoC. The following is a brief look at dependencies and dependency injection from a code perspective.
- A simple MVC login entry
@RestController
@RequestMapping("/web")
public class UserController {
@Autowired
@Qualifier("normalUserService")
private UserService userService;
/**
* 用户登陆入口
*/
@PostMapping("/login")
public void login(User user) { userService.login(user); }}Copy the code
The design principle of software architecture requires interface programming, so the STRUCTURE shown in the above code is often adopted in MVC architecture. UserController relies on the implementation class of UserService interface. At this point, the UserController is directly dependent on the UserService. At this point, without Spring, there are three ways to inject UserService:
- Every time I call login,
new UserService()
;- Injection is done by means of setters. That’s provided in UserController
setUserService(UserService userService)
.- By constructively injecting,
public UserController(UserService userService)
.Among them, the way of new is the way of higher coupling degree. Therefore, in Spring, constructs and setter injection methods are provided to implement IoC ideas. In the Spring framework, the dependencies are declared and the framework automatically generates Java objects that the user needs, which are called beans. The Injection of UserService into UserController is called Dependency Injection (DI).
2. Automatic assembly
@autoWired annotations and @Resource annotations are both examples of autowiring. Think about autowiring. As we learned from the previous article, Spring abstracts the information from Java objects into BeanDefinitions, and finally loads non-lazy-loaded singleton beans through the getBean method, which adds them to the singleton cache each time the getBean assembles a Bean. The process of auto-assembly, then, is the process of getting the dependent Bean from the container according to the rule (if specified), and then assigning the value through reflection to complete the assembly.
3. General process of populateBean
- Activation rear InstantiationAwareBeanPostProcessor processor InstantiationAwareBeanPostProcessor method: after the instantiation bean, Spring properties filling before execution of hook methods,
This is a callback to perform custom field injection on the bean instance before Spring’s autowiring begins, and is the last chance to modify the bean’s property values before autowiring.
- Resolve how dependency injection works by assembling properties into PropertyValues: resolvedAutowireMode.
- Activate InstantiationAwareBeanPostProcessor# postProcessProperties: the @autowired tag attributes of dependency injection.
- Dependency check: checkDependencies.
- Wrap the parsed value in a BeanWrapper: applyPropertyValues.
3.1 InstantiationAwareBeanPostProcessor# postProcessAfterInstantiation
- AbstractAutowireCapableBeanFactory#populateBean
/ / InstantiationAwareBeanPostProcessors one last time to modify the property of the bean
/ / InstantiationAwareBeanPostProcessor was realized using the cor way for all the post processor calls.
/ / until a InstantiationAwareBeanPostProcessor in postProcessAfterInstantiation return false
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// If false is returned, interrupt
if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return; }}}}Copy the code
In populateBean, nullation verification will be performed first, and after verification is passed. Check whether the user has registered InstantiationAwareBeanPostProcessor, if any, Of these rear device using the chain of responsibility pattern activation postProcessAfterInstantiation method, if a post processor is returned to the false, then Spring will not perform automatic assembly logic framework. Official advice is not to expand then place the processor, but recommended extending from InstantiationAwareBeanPostProcessorAdapter BeanPostProcessor or derived.
3.2 Parse properties to PropertyValues according to injection mode
// PVS is an instance of MutablePropertyValues
// Provides read and write operations on attributes, and can be deep copy via constructors
// Get the BeanDefinition property value for the Bean
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// The injection is done according to the dependency injection mode configured by the Bean. The default value is 0, that is, the following logic is not followed
// If the dependency assembly mode is set, the properties of the Bean will be iterated, and the corresponding injection will be done according to type or name
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// AutoWired auto-assembly logic according to beanName
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// Perform autowired auto-assembly logic according to Type
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
Copy the code
- So let’s first pull it out of the BeanDefinition
propertyValues
, the specific call method inAbstractBeanDefinition#getPropertyValues
, the return type isMutablePropertyValues
.- Parse dependencies in the way they are assembled. in
AutowireCapableBeanFactory
Five methods of dependency injection are declared in the interface:
resolvedAutowireMode | Dependency injection | describe |
---|---|---|
0 | AUTOWIRE_NO | There is no explicit configuration on the way to assemble |
1 | AUTOWIRE_BY_NAME | Assemble as beanName |
2 | AUTOWIRE_BY_TYPE | Assemble according to type |
3 | AUTOWIRE_CONSTRUCTOR | Do the assembly in the constructor |
4 | AUTOWIRE_AUTODETECT | By introspecting the bean class to determine the appropriate autowiring strategy,Spring has labeled it as@Deprecated |
Generally in the form of annotations, the default is resolved to 0, that is, there is no explicit configuration of the autoload policy. When a block of code goes into an if condition, it is usually either explicitly specifying autowired in an XML configuration file or declaring autowired on an @bean in a Java configuration class. Here’s a quick example:
@Bean(autowire = Autowire.BY_NAME)
Copy the code
3.3 InstantiationAwareBeanPostProcessor# postProcessProperties
If there is no explicit statement of automatic assembly way (the @autowired annotation), then this post processor is used to InstantiationAwareBeanPostProcessor postProcessProperties method.
Whether registered InstantiationAwareBeanPostProcessors / / container
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// Whether to perform dependency check. The default value is false
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;
// Perform dependency injection on the attributes of the @autoWired tag
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// Handle unset attributes after parsing
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return; } } pvs = pvsToUse; }}}Copy the code
- AutowiredAnnotationBeanPostProcessor#postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// Get the metadata marked by the @autowired annotation in the specified class.
/ / metadata in applyMergedBeanDefinitionPostProcessors instantiated for storage
// findAutowiringMetadata reads metadata from the injectionMetadataCache cache
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// Automatically inject the Bean's properties
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;
}
Copy the code
In the front doCreateBean we analyses applyMergedBeanDefinitionPostProcessors, In its postProcessMergedBeanDefinition already call the method on the Bean findAutowiringMetadata be members of the @ Autowired mark for the storage, already into the attributes filling stage, Metadata of type injectionMetadataCache is retrieved from the injectionMetadataCache cache. InjectionMetadata provides an Inject method that performs automatic injection dependent logic.
3.3.1 org. Springframework. Beans. Factory. The annotation. InjectionMetadata# inject
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) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "'." + element);
}
InjectedElement#inject, here is the implementation of polymorphism
/ / the @autowired attention AutowiredAnnotationBeanPostProcessor. AutowiredFieldElement. Injectelement.inject(target, beanName, pvs); }}}Copy the code
Check whether the current checkedElements is empty, and if so, parse injectedElements. Then iterate over the Element to perform inject.
- AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// Currently stored members that need to be injected
Field field = (Field) this.member;
Object value;
// If the value of this member is cached, fetch it from the cache
if (this.cached) {
/ / call DefaultListableBeanFactory resolveDependency finally
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
Create a DependencyDescriptor for the member.
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
// Set the Class of the current bean
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory ! =null."No BeanFactory available");
// Get the type converter
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
/ / call DefaultListableBeanFactory resolveDependency finally
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
// If the value of a member variable is not cached
if (!this.cached) {
// The value of the member variable is not null and required==true
if(value ! =null || this.required) {
this.cachedFieldValue = desc;
// Register dependencies
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
// The dependent object type matches the field type and is injected by type by default
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = newShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); }}}else {
this.cachedFieldValue = null;
}
this.cached = true; }}}if(value ! =null) {
ReflectionUtils.makeAccessible(field);
// Call reflection for assignmentfield.set(bean, value); }}}Copy the code
OK, here we go to the crucial step of resolving dependencies.
- First try to fetch the Bean corresponding to the dependency from the cache.
- If there is no corresponding Bean for the dependency in the BeanFactory. Create one for the member
DependencyDescriptor
And then callbeanFactory.resolveDependency
To load the beans.- Register the dependencies between beans.
- Call reflection to populate the obtained Bean.
field.set(bean, value)
, notice that before this step, Spring pairsfield
Permissions are set for thefield.setAccessible(true)
Among them, the logic is encapsulated in the beanFactory. Automatic assembly resolveDependency. Keep going to find out.
3.3.2 rainfall distribution on 10-12 DefaultListableBeanFactory# resolveDependency
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) {
// Resolve dependencies
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
returnresult; }}Copy the code
Here Spring does some adaptation of dependencies, focusing on doResolveDependency, which resolves dependencies.
- DefaultListableBeanFactory#doResolveDependency
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Beanfactory.getbean (); // Get the dependency from the container
Object shortcut = descriptor.resolveShortcut(this);
// If the bean can be retrieved from the container, return it directly
if(shortcut ! =null) {
returnshortcut; } Class<? > type = descriptor.getDependencyType();// Handle @value annotations
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if(value ! =null) {
if (value instanceofString) { 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())); }}// If the member variable that identifies the @autoWired annotation is a compound type, such as array, List, Map, etc.
// Get the value in @autowired from here
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if(multipleBeans ! =null) {
return multipleBeans;
}
// If the member tagged by @autoWired is not a composite object
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// If it cannot be found, verify that the current mark of required is true.
if (isRequired(descriptor)) {
/ / if the @autowired annotation (required = true), but you can't match to the corresponding bean, throw NoSuchBeanDefinitionException anomalies
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// If more than one Bean is matched, see if @primary and @priority are marked
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if(isRequired(descriptor) || ! indicatesMultipleBeans(type)) {/ / if not declared, the direct selling NoUniqueBeanDefinitionException
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 be an 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();
// Key is the name of the dependent candidate, for example, UserController depends on UserService.
/ / autowiredBeanName = userService at this time
autowiredBeanName = entry.getKey();
// Class, then instantiate after the election
instanceCandidate = entry.getValue();
}
if(autowiredBeanNames ! =null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// Apply the obtained candidate Class to getBean
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
The code logic here is closely related to our usual programming.
- call
descriptor.resolveShortcut
Check to see if the current factory has already loaded the same Bean, and return if so.- To deal with
@Value
Analytic logic.- Call if currently injected is a composite object
resolveMultipleBeans
.- If you’re just injecting plain Bean objects, look for candidates that match the criteria. Return a Map.
The reason for returning a Map is that an interface can have more than one implementation class, and lookup by type will return the implementation class that implements the interface. When dealing with multiple candidate beans, Spring determines whether the @primary or @Order annotation is declared to determine which Bean to inject. If there is no statement, then determine whether a statement required = false), if required for the default, it throws NoUniqueBeanDefinitionException anomalies. Beanfactory.getbean (beanName) is called by resolveCandidate (resolveCandidate).
What is a composite object? Spring can inject not only a single Bean object, but also arrays, collections, streams, maps, and so on.
3.3.3 How to degrade if Autowired cannot select the most suitable Bean according to byType
Answer in determineAutowireCandidate in through byType unable to select the most appropriate Bean, Spring will use byName way of comparison of current property name and candidate Bean list whether candidateName matching to do the final processing.
- DefaultListableBeanFactory#determineAutowireCandidate
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<? > requiredType = descriptor.getDependencyType();// Select the best solution according to the @primary annotation tag
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if(primaryCandidate ! =null) {
return primaryCandidate;
}
// Inject according to @order, @priority, and the most appropriate Bean that implements the Order interface (the smaller the number, the more appropriate)
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 the Bean with the best solution cannot be found through the above two methods:
// If the type is already in resolvableDependencies, return the registered object directly.
// If byType cannot be found, use byName to find dependencies
// If the attribute name matches a candidate's Bean name or alias, the Bean is returned
if((beanInstance ! =null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
returncandidateName; }}return null;
}
Copy the code
If UserService has two implementation classes,VipUserService beanName is actively declared as VIP and NormalUserService normal, then you can inject VipUserService in Controller by writing:
@Autowired
UserService vip;
Copy the code
4. Dependency check
Spring is not recommended in the latest version, so we won’t focus on it here.
5. Wrap parsed values in BeanWrapper -applyPropertyValues.
Beans configured in the form of annotations do not fill values into PVS. I have seen in some books that focus on parsing this method. The current version of Spring5.1 does not find this method in the debug, so I do not explain in detail. I prefer this to be left for xmL-compatible practices.
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 {
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());
}
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;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
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();
}
// 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); }}/** * Convert the given value for the specified target property. */
@Nullable
private Object convertForProperty(
@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
if (converter instanceof BeanWrapperImpl) {
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
}
else {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
returnconverter.convertIfNecessary(value, pd.getPropertyType(), methodParam); }}Copy the code
All attributes configured from XML are declared as strings, so some type of parsing and strong-casting is required here. Core approach:
- parsing
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
- injection
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
conclusion
- Annotation-driven beans that perform property population are not
autowireByName
andautowireByType
In, but inAutowiredAnnotationBeanPostProcessor
This is for the rear processorpostProcessProperties
In the. - During property population, if the current Bean instance depends on a member (another Bean) that has not been loaded, it will enter the logic of the election candidate list, and after various judgments, the most suitable Bean instance will be selected
getBean
Operation. @Autowired
During autowiring, beans are loaded in a “byType” fashion by default, and if a suitable Bean cannot be selected, attribute names are added to the list of candidate beansbeanName
Compare.- Declare correctly
@Primary
andOrder
Such annotations make beans preferable in polymorphic elections. required=false
You can tell your program not to throw an exception if the Bean is not found, but an error will still be reported during the call (stalling) and this is not recommended.- The autoloassembly pattern of XML is a different bifurcation in code from the annotation-driven pattern.