Spring — The difference between BeanFactory and FactoryBean

An overview of the

These two are completely different in Spring. Factorybeans are used in some frameworks that integrate with Spring. The BeanFactory is not used much in everyday use, but instead is the ApplicationContext object.

The difference between

BeanFactory

BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory: BeanFactory If you are interested, check out this book. The first edition is complete with Spring’s core features.

It is recommended to read the official document BeanFactory directly.

It is the top-level interface to the Spring Bean Container from which beans can be retrieved. As a bean, as long as it is managed by Spring, Spring will put the bean in its container.

FactoryBean

First, a FactoryBean is a bean. But it is not a normal bean; it is a bean that can create objects. The last thing exposed is the object it returns from getObject(), and the object it creates is not managed by Spring. (injection can be injected, in this case, it does not follow a standard Springbean lifecycle.)

In addition, this interface provides whether the object is created singleton or multiinstance. Its subinterface, SmartFactoryBean, also provides more detailed control. The official documentation FactoryBean

These are his implementation classes.

FactoryBean analysis

The interface itself has nothing to say. Here’s how factoryBeans are parsed and used in Spring.

Usage analysis in Spring

Let’s start with a small example

  1. FactoryBean
public class MyFirstTestFactoryBean implements SmartFactoryBean<Test> {
	@Override
	public Test getObject(a) throws Exception {
		Test test = new Test();
		test.setAge(12);
		test.setName("name");
		return test;
	}

	@Override
	publicClass<? > getObjectType() {return Test.class;
	}

	@Override
	public String toString(a) {
		return "toString-lc"; }}Copy the code
  1. Bean

    public class Test {
    	private String name;
    	private Integer age;
    
    	public String getName(a) {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public Integer getAge(a) {
    		return age;
    	}
    
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    
    	@Override
    	public String toString(a) {
    		return "Test{" +
    				"name='" + name + '\' ' +
    				", age=" + age +
    				'} '; }}Copy the code
  2. The configuration class

    public class MyFirstTestFactoryConfig {
    	@Bean(name = "testFactoryBean")
    	public MyFirstTestFactoryBean testFactoryBean(a){
    		return newMyFirstTestFactoryBean(); }}Copy the code
  3. Start the class

    public class BeanFactoryApplicationText {
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context = null;
    		try {
    			 context = new AnnotationConfigApplicationContext(MyFirstTestFactoryConfig.class);
    			Test bean = context.getBean(Test.class);
    			System.out.println(bean);
    			MyFirstTestFactoryBean myFirstTestFactoryBean = context.getBean(MyFirstTestFactoryBean.class);
    			MyFirstTestFactoryBean myFirstTestFactoryBean1 = (MyFirstTestFactoryBean) context.getBean("&testFactoryBean");
    			MyFirstTestFactoryBean myFirstTestFactoryBean2 = (MyFirstTestFactoryBean) context.getBean("&&testFactoryBean");
    			System.out.println(myFirstTestFactoryBean==myFirstTestFactoryBean1 );
    			System.out.println(myFirstTestFactoryBean==myFirstTestFactoryBean2 );
    		}catch (Throwable e){
    			e.printStackTrace();
    		}finally {
    			assertcontext ! =null; context.close(); }}}Copy the code
  4. The results of

Factorybeans are parsed in Spring

Start with the preInstantiateSingletons method

First of all, FactoryBean is also a Bean and follows the Spring standard creation process. Because the Spring standard process for creating beans is too long, I won’t go into details here. The specific method is ConfigurableListableBeanFactory interface preInstantiateSingletons, specific implementation class is DefaultListableBeanFactory.

Just pick some key methods to analyze.

 // Determine if this bean is a FactoryBean
if (isFactoryBean(beanName)) {
                  // Add & to the prefix of the normal bean name. This method is familiar and follows the standard bean creation process.
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                  
					if (bean instanceof FactoryBean) {
                        // FactoryBean<? > factory = (FactoryBean<? >) bean;boolean isEagerInit;
                         // Check whether the current bean is a SmartFactoryBean and whether isEagerInit is true.
                        // If true, the Bean created by the FactoryBean needs to be comfortable
						if(System.getSecurityManager() ! =null && factory instanceofSmartFactoryBean) { isEagerInit = AccessController.doPrivileged( (PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else {
							isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if (isEagerInit) {
                             // If the BeanFactory needs to be initialized immediately, the BeanFactory needs to be createdgetBean(beanName); }}}Copy the code

There are several problems with the above code

  1. How to determine if an isFactoryBean is a FactoryBean? ?

    The essence is determined by the Class of the Bean, mainly by the isAssignableFrom method, and will set the BeanDefinition to the due BeanDefinition. The isFactoryBean property is true. But there are some small details.

    TransformedBeanName method.

    This method gets the bean’s real name. It removes the & prefix from the name of the FactoryBean.

    The following method intercepts the ampersand before the name and then aliases the cached map, retrieving the alias from the bean’s name, or returning the bean’s name if it does not.

    protected String transformedBeanName(String name) {
       return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }
    Copy the code
  2. A FactoryBean is applied to the Aware interface, init and destroy, and BeanPostProcess. Should beans be injected?

    Yes, as mentioned earlier, a FactoryBean is special, but it is also a Bean. As a Bean, it is fully qualified by the standard SpringBean creation process. So, he’ll get.

  3. If you need to understand how initialization works, it is also the normal way to get a bean. From this argument, you can see that the input parameter is still the name of the FactoryBean, and how to get it by this name. Call getObjects () to the FactoryBean.

    The main method is the getBean(beanName) method.

    The third question, involving more things, here will not say, and then the following chapter analysis.

SmartFactoryBean

In addition to FactoryBean, we add two methods,

  1. IsPrototype indicates whether the current bean is a multiinstance
  2. IsEagerInit indicates whether the current bean is an immediate initialization bean, and if immediate initialization is required, inpreInstantiateSingletonsThe FactoryBean method creates the Bean from which the FactoryBean is created.
public interface SmartFactoryBean<T> extends FactoryBean<T> {

	default boolean isPrototype(a) {
		return false;
	}

	default boolean isEagerInit(a) {
		return false; }}Copy the code

The getBean(String Name) method creates the Bean that needs to be created in the FactoryBean.

The full code will not be posted, analyze the key code

The purpose of this step is to deal with the difference between a FactoryBean and a regular bean. However, a FactoryBean has a bean name. It does not automatically prefix the bean with &. Instead, they are distinguished by prefixes when they are retrieved.

Fetch the bean from the level 1 cache. If not, create the bean and go through the standard bean-creation process.

If it already exists, it goes to the getObjectForBeanInstance method, which is pretty detailed.

		TestFactoryBean = testFactoryBean = testFactoryBean = testFactoryBean = testFactoryBean
       String beanName = transformedBeanName(name);
		Object bean;

		// Check whether the bean exists in the level 1 cache. If it does not exist, go through the standard process of creating bean.
		Object sharedInstance = getSingleton(beanName);
		if(sharedInstance ! =null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); }}// Notice this method. Very detail.
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
   // The following is the process of creating a standard create bean. ignored
Copy the code

GetObjectForBeanInstance (key)

Notice that there are a couple of parameters here.

BeanInstance: the instance of the bean

Name: The name of the bean to get, that is, the name of the call, for example &testFactoryBean.

BeanName: The name of the bean processed by transformedBeanName. Based on the example above, such as testFactoryBean.

RootBeanDefinition: The BeanDefinition of this bean

Main functions:

Do different things with different bean names, and notice that there are two names. The first name is purely to determine whether you currently want a factory bean or a plain bean. Nothing else is interesting.

Spring has this notation because of FactoryBean, and the two name arguments are meaningless without it.

A bean can be retrieved from a bean factory or from a FactoryBean, and the name passed differentiates whether a FactoryBean is returned from a plain bean.

As you can see from the code, if it is a beanName that begins with &, it is considered to be getting a factoryBean. If the current bean is a factoryBean, the next step is to get the desired bean from the factoryBean. Because beans come from only two sources, BeanFactory and FactoryBean.

In this case, there must bea mapping between the name of a FactoryBean and the beans it can create. If there is no mapping between the name of a FactoryBean and the beans it can create, it must be checked from the cache. If there is no mapping between the name of a FactoryBean and the beans it can create, it goes to the getObjectFromFactoryBean method.

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	    // Just look at the prefix and see if it starts with &.
       // If it starts with &, it is a FactoryBean that you want to fetch, so you just make a judgment, set its isFactoryBean property, and return the original bean instance
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if(! (beanInstanceinstanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if(mbd ! =null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// If it is a factoryBean, the instance of the bean will be created by FactoryBena.
		if(! (beanInstanceinstanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if(mbd ! =null) {
			mbd.isFactoryBean = true;
		}
		else {
            // get bena from the cache where key is the name of the factoryBean and value is the object created by the factoryBean
			object = getCachedObjectForFactoryBean(beanName);
		}
        // Return if found, continue if not,
		if (object == null) {
			// Return bean instance from factory.FactoryBean<? > factory = (FactoryBean<? >) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			booleansynthetic = (mbd ! =null && mbd.isSynthetic()); // This indicates whether the bean is a composite, which is not created by the application, but by a proxy, or indirectly
             // The bean is created by Factorybean.object = getObjectFromFactoryBean(factory, beanName, ! synthetic); }return object;
	}

Copy the code

GetObjectFromFactoryBean (Create bean from Factorybean)

First look at the input parameter:

Factory: The FactoryBean to create the object.

BeanName: This name has the same meaning as the previous one.

ShouldPostProcess: Whether to apply postProcess

Main functions:

The main function is to create Bean instances from factoryBeans. The specific code logic is as follows:

If it’s a singleton it needs to be cached, if it’s not a singleton it needs to be created every time. In addition, shouldPostProcess is true, indicating that the beanPostProcess method needs to be applied. There are some checks in between.

protected Object getObjectFromFactoryBean(FactoryBean<? > factory, String beanName,boolean shouldPostProcess) {
    // If it is a singleton and beanName is contained in the bean factory.
   if (factory.isSingleton() && containsSingleton(beanName)) {
        / / acquiring a lock
      synchronized (getSingletonMutex()) {
          Key is the name of the beanFactory, v is the name of the bean created by the beanFactory,
         Object object = this.factoryBeanObjectCache.get(beanName);
         if (object == null) {
              // There is nothing in the cache. This method is called factoryBean.getobject (). Get the instance of the bean
            object = doGetObjectFromFactoryBean(factory, beanName);
            // Retrieve the value from the cache again. If not, postPorcess and cache will be followed
            Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
            if(alreadyThere ! =null) {
               object = alreadyThere;
            }
            else {
               if (shouldPostProcess) {
                  if (isSingletonCurrentlyInCreation(beanName)) { // If the current bean is being created, it is better to return it directly instead of going through the process, which is also the standard process
                     // Temporarily return non-post-processed object, not storing it yet..
                     return object;
                  }
                  beforeSingletonCreation(beanName);
                  try {
                     object = postProcessObjectFromFactoryBean(object, beanName); // Only postProcessAfter methods are applied when referring to postPorcess
                  }
                  catch (Throwable ex) {
                     throw new BeanCreationException(beanName,
                           "Post-processing of FactoryBean's singleton object failed", ex);
                  }
                  finally {
                     afterSingletonCreation(beanName); // echo back and forth}}if (containsSingleton(beanName)) {
                   // Slow down storage, here is the actual creation of the bean in the cache,
                  this.factoryBeanObjectCache.put(beanName, object); }}}returnobject; }}else {
      Object object = doGetObjectFromFactoryBean(factory, beanName);
      if (shouldPostProcess) {
         try {
            object = postProcessObjectFromFactoryBean(object, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); }}returnobject; }}Copy the code

DoGetObjectFromFactoryBean (get to create the beans from the BeanFactory)

	private Object doGetObjectFromFactoryBean(FactoryBean
        factory, String beanName) throws BeanCreationException {
		Object object;
		try {
			if(System.getSecurityManager() ! =null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
				}
				catch (PrivilegedActionException pae) {
					throwpae.getException(); }}else {
                 // Call the BeanFactory method to create the object directlyobject = factory.getObject(); }}catch (FactoryBeanNotInitializedException ex) {
			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
		}

		
		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}
Copy the code

So far, we’ve looked at the key ways that FactoryBean creates objects. The entry to the above method assumes that a SmartFactoryBean needs to be initialized immediately and created while iterating through preInstantiateSingletons. Let’s start with the normal ApplicationContext and get the bean to see how it is created.

From the normalBeanFactory#<T> T getBean(Class<T> requiredType) method begins

You can get the factoryBean object creation process by using getBean(factoryBean(this name has no &)). In this method, you need to think about how to associate the type of the factoryBean with the type of the bean to be created. Once the association is in place, you can retrieve the Bean to be created using the logic above.

It all starts with getBean (Class Type).

resolveNamedBean

This method mainly obtains the bean instance by type, parameter, and wraps the bean instance as NamedBeanHolder.

The main method called is getBeanNamesForType (requiredType), which basically gets the appropriate Bean by Bean type and returns the name of the qualified Bean.

However, it is possible to return multiple beans, such as multiple implementation classes of an interface that satisfies the getBeanNamesForType condition, but this interface returns a single bean, so the following deals with this case.

If you have more than one Bean, you need to deal with it,

To see if the bean has BeanDefintion or if the bean is a candidate for Autowire (isAutowireCandidate is a BeanDefinition attribute), The values are all the implementation classes that annotate the type of the @autowire bean. Form a new Candida Games.

If you have only one, you go straight back, otherwise you have to continue judging. @primary and @priority: if there are multiple implementations of one of these annotations, an error will be returned. If there are any, return true or false for nonUniqueAsNull.

	private <T> NamedBeanHolder<T> resolveNamedBean(
			ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {

		Assert.notNull(requiredType, "Required type must not be null");
         // Get a collection of matching Bean names
		String[] candidateNames = getBeanNamesForType(requiredType);
       // If there are more than one
		if (candidateNames.length > 1) {
			List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
			for (String beanName : candidateNames) {
				if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
					autowireCandidates.add(beanName);
				}
			}
			if (!autowireCandidates.isEmpty()) {
				candidateNames = StringUtils.toStringArray(autowireCandidates);
			}
		}
       // If there is only one, then simply return it
		if (candidateNames.length == 1) {
			String beanName = candidateNames[0];
			return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
		}
         // If there are more than one of them, I will do it again.
		else if (candidateNames.length > 1) {
            // First assemble a map. The key of the map is beanName and the value of the map is the instance of the bean.
			Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
			for (String beanName : candidateNames) {
				if (containsSingleton(beanName) && args == null) {
					Object beanInstance = getBean(beanName);
					candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
				}
				else{ candidates.put(beanName, getType(beanName)); }}// Check if there is a Primary annotation in the bean
			String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
			if (candidateName == null) {
                 // This is the same logic as the Priority annotation,
				candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
			}
			if(candidateName ! =null) {
                // If it is found, it is returned directly. There's nothing else to do. Direct return
				Object beanInstance = candidates.get(candidateName);
				if (beanInstance == null || beanInstance instanceof Class) {
					beanInstance = getBean(candidateName, requiredType.toClass(), args);
				}
				return new NamedBeanHolder<>(candidateName, (T) beanInstance);
			}
            // There are no more beans available, or there are more beans available
            // nonUniqueAsNull means whether beans that are not unique and can also be NULL are allowed.
			if(! nonUniqueAsNull) {throw newNoUniqueBeanDefinitionException(requiredType, candidates.keySet()); }}// Return null
		return null;
	}
Copy the code

DoGetBeanNamesForType (ResolvableType) (get the instance of the bean by ResolvableType)

From the getBeanNamesForType method, all the way to this method, anyone familiar with Spring knows that the do method is the way to do the work. Let’s examine this method to actually get the Bean’s operations.

Let’s look at a few parameters of the method

  1. ResolvableType Type: indicates the type to be matched.
  2. Boolean includeNonSingletons: Include beans that are not singletons.
  3. Boolean allowEagerInit: Whether premature initialization is allowed.

Main functions

  1. Traversal, all beanDefintion, as mentioned earlier, there are two ways to create beans in Spring. One is the standard Spring Bean creation process, and the other is through a Factorybean. But a Factorybean is a Bean, so, In addition, Spring also has the concept of a parent container. The child can access the parent container, but the parent cannot access the child container. In addition, there is a special case where the bean is an unknown bean. For example, if the bean is a FactoryBean, but its type is indeed a NullBean, you need to make a determination in this case, so Spring provides itSmartInstantiationAwareBeanPostProcessor#predictBeanTypeMethod to determine the type of bean
  2. The general functionality is the same as described above, but some extra functionality is added along the way, and in Spring code is often reused, so a method looks complicated because it is compatible with calls from several places.
  3. Also note that when looping over a bean, check for the type of bean created by the Factorybean if it is a Factorybean, and also check for the Factorybean if the type does not match (which is also a bean).
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
		List<String> result = new ArrayList<>();

		// Check all bean definitions.
		for (String beanName : this.beanDefinitionNames) {
			// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
			if(! isAlias(beanName)) {try { 
                    // Get BeanDefintion,
					RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				 
					if(! mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || ! mbd.isLazyInit() || isAllowEagerClassLoading()) && ! requiresEagerInitForType(mbd.getFactoryBeanName()))) {// The name of the bean is the name registered in the BeanFactory.
                         // Determine if this bean is a factory bean,
						boolean isFactoryBean = isFactoryBean(beanName, mbd);  
						BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
						boolean matchFound = false;
                         // Whether to allow factory bean instantiation,
                        // containsSingleton's decision is that a factoryBean creates a bean if it exists and instantiates it
 						boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName)); 
                        // Is not lazily initialized
						booleanisNonLazyDecorated = (dbd ! =null && !mbd.isLazyInit());
						if(! isFactoryBean) {// If the current bean is not a FactoryBean, the bean does not have the ability to create objects, so this is simple
                            // Determine the type of the current bean
							if(includeNonSingletons || isSingleton(beanName, mbd, dbd)) { matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); }}else { 
							if (includeNonSingletons || isNonLazyDecorated ||
									(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
                                // The factoryBean.getType method is called to determine,
								matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
							}
                            /// if it is a factoryBean but the type does not match, check the factoryBean
							if(! matchFound) {// In case of FactoryBean, try to match FactoryBean instance itself next.beanName = FACTORY_BEAN_PREFIX + beanName; matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); }}if(matchFound) { result.add(beanName); }}}catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
					if (allowEagerInit) {
						throw ex;
					}
					// Probably a placeholder: let's ignore it for type matching purposes.
					LogMessage message = (ex instanceof CannotLoadBeanClassException ?
							LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
							LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName));
					logger.trace(message, ex);
					// Register exception, in case the bean was accidentally unresolvable.
					onSuppressedException(ex);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Bean definition got removed while we were iterating -> ignore.}}}// Check manually registered singletons too.
		for (String beanName : this.manualSingletonNames) {
			try {
				// In case of FactoryBean, match object created by FactoryBean.
				if (isFactoryBean(beanName)) {
					if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
						result.add(beanName);
						// Match found for this bean: do not match FactoryBean itself anymore.
						continue;
					}
					// In case of FactoryBean, try to match FactoryBean itself next.
					beanName = FACTORY_BEAN_PREFIX + beanName;
				}
				// Match raw bean instance (might be raw FactoryBean).
				if(isTypeMatch(beanName, type)) { result.add(beanName); }}catch (NoSuchBeanDefinitionException ex) {
				// Shouldn't happen - probably a result of circular reference resolution...
				logger.trace(LogMessage.format(
						"Failed to check manually registered singleton with name '%s'", beanName), ex); }}return StringUtils.toStringArray(result);
	}
Copy the code

So the general analysis looks like this, with several caches along the way.

  1. A map of the type of bean to be retrieved and the appropriate bean name.
  2. For factoryBeans, there is a mapping cache of factoryBeans and the beans that need to be created. But in this case, you just create singleton objects for the FactoryBean. If multiple instances are created each time, no PostProcess is applied. This object has nothing to do with the container at all. In the case of singletons, there is a little bit of interest, such as if the Bean implements a Listener, which can be detected.

A problem

What if there are two FactoryBeans that both produce beans of the same type?

An error will be reported directly.

Think of the code logic above. If two suitable beans are found, and the two suitable beans have no Primary or Priority annotation, they will go to this judgment and passnonUniqueAsNullTo determine whether to report an error.

Through the ingenuity of FactoryBeans, a bean that has not gone through the standard Spring lifecycle can be obtained through Spring factoryBeans, as shown in the code in the getBean method. So what are the benefits of this? Why do you do that?

For the sake of length, the specific use of FactoryBeans in Spring will be covered later.

As for the blog, I take it as my notes, and there are a lot of contents in it that reflect my thinking process. As my thinking is limited, there are inevitably some discrepancies. If there are any questions, please point them out. Discuss together. thank you