Spring's official website reading container and its instantiation

spring Container

What is a container?

Let's start with a sentence on the official website:

The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.

Probably translated as:

  1. The Spring IOC container is oneOrg.springframework.contextInstantiated object of.ApplicationContext
  2. Containers are responsible for instantiating, configuring, and assembling a bean
    So we can say:
    At the code level, the Spring container is an object that implements the ApplicationContext interface.
    Functionally, the Spring container is the core of the Spring framework and is used to manage objects.Containers create objects, connect them together, configure them, and manage their entire life cycle from creation to destruction.
    How does the container work?
    Let's look directly at a picture on the official website, as follows:

    The Spring container produces a fully configured and usable system through our submitted pojo classes and configuration metadata
    The configuration metadata here is actually the XML configuration file that we provide, or some configuration information that we annotate

Spring Bean

How do I instantiate a Bean?
From the official website, there are three main ways

1. Construction methods
2. Through Static Factory Method
3. Through Instance Factory Method
These three examples, the official website has a specific demonstration, there is no longer a post here, we check some of the source code by ourselves to verify the conclusions we get on the official website, and then verify them by debug and so on.

Let's do another wave of analysis from a code perspective, and here we're going to go directly to

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

In this method, the specific positioning steps are no longer demonstrated. You can use this code as follows:

ClassPathXmlApplicationContext cc =
    // Here we instantiate a container through xml configuration
    new ClassPathXmlApplicationContext("classpath:application.xml");
MyServiceImpl myServiceImpl= (MyServiceImpl) cc.getBean("myServiceImpl");

The direct main method runs, then

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

The entry to this method breaks a breakpoint, as shown in the figure:

Next, we analyze this method, which is actually an important method in the life cycle of springbeans. This method completes the inferential construction method in the post-processor that invokes the second bean in the life cycle of springbeans.This method also returns a BeanWrapper object that can be wrapped outside by calling BeanWrapper's getWrappedInstance() method and then returning the wrapped Bean object. This BeanWrapper is actually an encapsulation of the bean object in Spring. The object encapsulation in Spring is most thorough, including BeanWrapper and you will see a Holder pair laterLike, are these all later or come back to this method? First, look at the parameters of this method. First, a String-type beanName is passed in. This parameter is certainly unnecessary, because how do you store so many beans in spring, it must be by name, and there is also a collection of beanNames specifically stored in spring

private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

Then a parameter of RootBeanDefinition was passed in. This parameter can be used as an article if you want to say something, so I won't say anything here, but when I come to it later, let's mention the general purpose of this parameter first. In spring, we usually use BeanDefinition to describe a bean, which is equivalent to using a Class object to describe a bean in java.Like classes, each is a model of an object. BeanDefinition has many implementations, each of which has its own indispensable functions.This RootBeanDefinition can be used as a template for beans (using the setAbstract method here) and then as a real bean, mainly as a parent bd, but not a child BD becauseOrg.springframework.beans.Factory.support.RootBeanDefinition#setParentNameMethod throws an exception directly, indicating it cannot be setThe parent BD. talks about RootBeanDefinition first and then more.

Again, back to this method, this method first determines the access permissions of the class, because spring by default is allowed for non-public classes, FactoryMethod mentioned later is also important, and so on.

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		// Detect the access rights of a class, spring is allowed by default for non-public classes
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		/**
		 * factoryMethod, If the factory method is not empty, construct the bean object from the factory method
		 * This way of building bean s can be tried by writing a demo on your own without in-depth analysis of the source code
		 *
		 * If there is a FactoryMethod, the FactoryMethod is called to create the object
		 * Require xml testing, do not know if factoryMethod can be used in annotations
		 * <bean id="xxx" class="xxx.xxx.xxx" factory-method="test()"></>
		 * Actually bd has been changed, changing the beanClass attribute in bd to the one specified by factoryMethod
		 */
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		/**
		 * You can tell from spring's original comment that this is a Shortcut. What does it mean?
		 * You can use this Shortcut when you build the same bean multiple times, which means you no longer need to infer in what way the bean should be constructed each time
		 * For example, when you build a prototype-type bean multiple times, you can go here to hortcut
		 *
		 * resolved andMbd.constructor ArgumentsResolvedThis will be set during the first instantiation of the bean s, as demonstrated later
		 *
		 *
		 * shortCut: Shortcut, when we re-create the same bean, we can use this shortcut; that is, when spring builds an object, he knows how it is built, whether by construction or by default. This value records that when a new prototype object is created, the resolved value works, and there's no need to decide
		 */
		boolean resolved = false;
		boolean autowireNecessary = false;		// Is it necessary to assemble automatically
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				// If the cached parsed constructor or factory method is not empty
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					// The constructorArgumentsResolved field is marked as parsed by the constructor parameter, that is, if the constructor's parameters have been parsed, the following must be an example of a parameterized construction method
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				// Construct bean objects by means of automatic assembly of construction methods
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// Initialize by default parameterless construction method
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		// If (args are not empty) or (args are empty and cached parsed constructors or factory methods are empty), you will come here
		/**
		 * Second Execution Post Processor
		 * SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors
		 * Inferential construction method
		 */
		// Candidate constructors for autowiring?
		// Find if there is a candidate auto-injection constructor and leave it to the post-processor to decide which construction methods to return
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			// Invoke the constructor to instantiate the bean object by means of automatic assembly of the construction method (injection)
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// No special handling: simply use no-arg constructor.
		// Initialize using default parameterless construction method (using reflection newInstance)
		return instantiateBean(beanName, mbd);
	}

Our main focus is on several ways to instantiate:

  1. Get an instantiated object directly from the instanceSupplier in BeanDefinition.This instance Supplier property is not something I particularly understand. There is no way to configure it in terms of tags or annotations in the xml.Later inOrg.springframework.context.Support.GenericApplicationContextThe following two methods were found in this class

After breakpoint testing, it is found that when you instantiate an object, you enter the supplier method above.Here is the test code:

public static void main(String[] args) {
    // AnnotationConfigApplicationContext is a subclass of GenericApplicationContext
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
		ac.registerBean("service", Service.class,Service::new);
		ac.refresh();
		System.out.println(ac.getBean("service"));
	}

You can see that you entered this method for instantiation
This method is not commonly used, nor can we use it in general, so we don't do much research. I think it should be a convenient external extension provided by Spring, which allows developers to more flexible instantiation of a bean.
2. Next, we validate the instantiation methods of the objects separately by using different methods of creating bean s.
By @Compent, @ServiceEqual Annotation Method
Test code:

public class Main {
	public static void main(String[] args) {
        // Scan by configuring classes
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
		System.out.println(ac.getBean(Service.class));
	}
}

@Component
public class Service {

}

You can see that the code executes to the last line, and we can see from the comments above that when no special handling is done, the default is to instantiate the object using a parameterless constructor
* via plain XML (with the @compent comment, not to mention here)
* via @Configuration annotations

Tags: Spring xml Java Attribute

Posted on Sat, 06 Jun 2020 23:17:43 -0400 by FrobinRobin