• Spring Reading Directory

The createBean method can be divided into four small methods:

  • ResolveBeanClass: loads the Class object
  • PrepareMethodOverrides: works on a bean defined through XMLlookup-methodandreplace-methodAttribute preprocessing
  • After the application processor before resolveBeforeInstantiation: instantiation
  • DoCreateBean: Creates the Bean

Let’s take a look at them one by one.

resolveBeanClass

First debug into AbstractAutowireCapableBeanFactory createBean class

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Use the class loader to load classes by class or by classNameClass<? > resolvedClass = resolveBeanClass(mbd, beanName);if(resolvedClass ! =null&&! mbd.hasBeanClass() && mbd.getBeanClassName() ! =null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}
      // omit code...
}
Copy the code

Enter the AbstractBeanFactory class resolveBeanClass method. Note that typesToMatch may be of type factoryBean. class, and typesToMatch is a mutable parameter. Find out where the resolveBeanClass method is called when you DeBug yourself.

@Nullable
	protectedClass<? > resolveBeanClass(final RootBeanDefinition mbd, String beanName, finalClass<? >... typesToMatch)throws CannotLoadBeanClassException {
		//BeanDefintion is created while scanning,
		AbstractBeanDefinition but AbstractBeanDefinition has a beanClass property
		try {
			// If beanClass is Class, return beanClass directly
			if (mbd.hasBeanClass()) {
				return mbd.getBeanClass();
			}
            / / ignore
			if(System.getSecurityManager() ! =null) {
				returnAccessController.doPrivileged((PrivilegedExceptionAction<Class<? >>) () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext()); }else {
				AbstractBeanDefinition < beanDefinition > < AbstractBeanDefinition > < AbstractBeanDefinition
				returndoResolveBeanClass(mbd, typesToMatch); }}catch (PrivilegedActionException pae) {
			ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
		}
		catch (ClassNotFoundException ex) {
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
		}
		catch (LinkageError err) {
			throw newCannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err); }}Copy the code

Enter the AbstractBeanFactory class doResolveBeanClass method

@Nullable
	privateClass<? > doResolveBeanClass(RootBeanDefinition mbd, Class<? >... typesToMatch)throws ClassNotFoundException {
		// Get the classloader
		ClassLoader beanClassLoader = getBeanClassLoader();
		ClassLoader dynamicLoader = beanClassLoader;
		boolean freshResolve = false;

		if(! ObjectUtils.isEmpty(typesToMatch)) { ClassLoader tempClassLoader = getTempClassLoader();if(tempClassLoader ! =null) {
				dynamicLoader = tempClassLoader;
				freshResolve = true;
				if (tempClassLoader instanceof DecoratingClassLoader) {
					DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
					for(Class<? > typeToMatch : typesToMatch) { dcl.excludeClass(typeToMatch.getName()); }}}}// Get the beanClass property specified in BeanDefinition,
		String className = mbd.getBeanClassName(); // String or #{XXX}
		if(className ! =null) {
			// className can be a Spring EL expression, so it needs to be resolved
			Object evaluated = evaluateBeanDefinitionString(className, mbd);
            // If className is Spring EL, className and Evaluated will not be equal
			if(! className.equals(evaluated)) {// The evaluated type is Class
				if (evaluated instanceof Class) {
					return(Class<? >) evaluated; }// the evaluated type is String. Set freshResolve to true
				else if (evaluated instanceof String) {
					className = (String) evaluated;
					freshResolve = true;
				}
				else {
					throw new IllegalStateException("Invalid class name expression result: "+ evaluated); }}if (freshResolve) {
				if(dynamicLoader ! =null) {
					try {
                        // Use the class loader to load classes
						return dynamicLoader.loadClass(className);
					}
					catch (ClassNotFoundException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ":"+ ex); }}}// The reflection utility Class loads the Class object
				returnClassUtils.forName(className, dynamicLoader); }}// The reflection utility Class loads the Class object
		return mbd.resolveBeanClass(beanClassLoader);
	}
Copy the code

AbstractBeanDefinition Class (); If not, get the value of the beanClass attribute and convert it to type Stirng, then parse the expression for className. Dynamicloader.loadclass (className) or classutils.forname (className, classLoader).

prepareMethodOverrides

Preprocessing the look-method and replace-method properties in the XML-defined bean

	try {
			// Preprocess the lookup-method and replace-method methods in the xmL-defined bean
			// Methods for @lookup annotations are not handled here
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}
Copy the code

Enter the prepareMethodOverrides method of the AbstractBeanDefinition class

public void prepareMethodOverrides(a) throws BeanDefinitionValidationException {
		// Check that lookup methods exist and determine their overloaded status.
		// Check if there are lookup methods and determine their overloaded status.
		if (hasMethodOverrides()) {
			getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride); }}Copy the code

Enter the prepareMethodOverride method of the AbstractBeanDefinition class

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
		// Get the number of corresponding methods in this class, parent class, and parent interface
		int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
		if (count == 0) {
			throw new BeanDefinitionValidationException(
					"Invalid method override: no method with name '" + mo.getMethodName() +
					"' on class [" + getBeanClassName() + "]");
		}
		else if (count == 1) {
			// The flag overloaded avoids the overhead of an argument type check
			mo.setOverloaded(false); }}Copy the code

This method mainly preprocesses the lookup-method and replace-method properties, which are less used now. If you are interested in these two properties, you can check them out on the Spring website by clicking “I go” or by moving to the Spring source code (ii – 2)-lookup-method and appet-method elements

resolveBeforeInstantiation

	try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 1
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);  / / object
			if(bean ! =null) {
				returnbean; }}catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}
Copy the code

Note that there is an if block in the method above. If the result is not empty after the pre-processing, it will skip the subsequent bean creation and return the result directly. The current Bean creation process is complete and the doCreateBean function is not executed further down.

Enter AbstractAutowireCapableBeanFactory resolveBeforeInstantiation method of a class

@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		/ / beforeInstantiationResolved value will only be null or true
		if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// Return the Class objectClass<? > targetType = determineTargetType(beanName, mbd);if(targetType ! =null) {
					// before instantiation
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if(bean ! =null) {
						// after initializationbean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! =null);
		}
		return bean;
	}
Copy the code

Then enter AbstractAutowireCapableBeanFactory Class determineTargetType method, this method is to load Class object.

	@Nullable
	protectedClass<? > determineTargetType(String beanName, RootBeanDefinition mbd, Class<? >... typesToMatch) {// Get the resolvedTargetType attribute, also equivalent to the cache,Class<? > targetType = mbd.getTargetType();if (targetType == null) {
			// If BeanDefinition sets factoryMethodName, then factoryMethodName is used to determine the type,
			< AbstractBeanDefinition > < AbstractBeanDefinitiontargetType = (mbd.getFactoryMethodName() ! =null ?
					getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
					resolveBeanClass(mbd, beanName, typesToMatch));
			if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
				// Log the parsed type into resolvedTargetTypembd.resolvedTargetType = targetType; }}return targetType;
	}
Copy the code

Methods before AbstractAutowireCapableBeanFactory applyBeanPostProcessorsBeforeInstantiation instantiation of a class

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class
        beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				/ / execution postProcessBeforeInstantiation method, also is instantiated before
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if(result ! =null) {
					returnresult; }}}return null;
	}
Copy the code

Note: the method name of the above method applyBeanPostProcessors BeforeInstantiation, BeforeInstantiation BeforeInstantiation. Get all the BeanPostProcessor first, and then iterate over the judge whether realized InstantiationAwareBeanPostProcessor, then execute postProcessBeforeInstantiation instantiation method before. If postProcessBeforeInstantiation method returns the object, that is, don’t return null, is executed applyBeanPostProcessorsAfterInitialization after initialization method.

Methods after applyBeanPostProcessorsAfterInitialization AbstractAutowireCapableBeanFactory class initialization

@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			/ / execution postProcessAfterInitialization method, namely after initialization
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
Copy the code

Also should pay attention to the method of the method name applyBeanPostProcessorsAfterInitialization, AfterInitialization after initialization. Access to all the BeanPostProcessor, then cycle after each BeanPostProcessor postProcessAfterInitialization initialization method. If postProcessAfterInitialization initialization method of the return value is null directly after end of cycle, to return. I have three BeanPostProcessor, for example, A, B, C, when performing A BeanPostProcessor postProcessAfterInitialization method returns A null, BeanPostProcessor B and C will not be executed. AOP is also executed here.

If you are not familiar with BeanPostProcessor, go to: Spring source code -BeanPostProcessor

doCreateBean

After program execution resolveBeforeInstantiation function, if the returned result is null, it needs to perform doCreateBean function to create a Bean.

try {
			Spring has a built-in method for creating beans
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
Copy the code

The doCreateBean function is too long, so I’ll break up several articles to read.

  • If you have any questions or errors in this article, please feel free to comment. If you find this article helpful, please like it and follow it.