How to initialize Spring Bean

I’ve been doing Java for many years, and there’s always a puzzle: How Spring initializes beans, how to call reflection instantiation objects, do it yourself. In the past, I thought that spring Bean object instantiation was always done by the BeanPostProcessor interface implementation class. I just don’t know which implementation class, so let’s verify this hypothesis.

Three levels of cache

The main reason why the interviewer likes to ask is that bean creation is usually done with transitions between the three caches, with different object states stored in different caches. In the following code, I will support how objects move through the caches. Take a look at spring level 3 caching.

/** Level 1 cache is used to store fully usable singleton beans. */ Private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Level 2 cache exposes singleton object prematurely, when bean has just finished initialization, */ Private Final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); /** private final Map<String, ObjectFactory<? >> singletonFactories = new HashMap<>(16)Copy the code

Main functions of three-level cache: When getObject is called to create an instance, the created object is added to the level-2 cache and the level-2 cache is removed. After the object has completed its initialization method and property injection, the cache is added to the Level-2 cache and the level-2 cache is removed.

doGetBean

To find it from the source, all spring bean initialization is by AbstractBeanFactory doGetBean method implementation. Below I will reduce the source bloated part, posted out.

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
        // The name prefix handles beanFactory beanName with an & beginning
		String beanName = transformedBeanName(name);
		Object beanInstance;
        // Fetch bean from level 3 cache, return null, indicating that the object has not been created
		Object sharedInstance = getSingleton(beanName);
		if(sharedInstance ! =null && args == null) { // If the bean in the cache is a FactoryBean instance, the actual bean is retrieved through the interface
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else { 
             // Determine if the bean object token is being created, and if it is being created it should not proceed. This error occurs when a dependency loop occurs
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			BeanFactory parentBeanFactory = getParentBeanFactory();
            // Check if the parent exists and try to fetch it from the parent
			if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if(args ! =null) {
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if(requiredType ! =null) {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return(T) parentBeanFactory.getBean(nameToLookup); }}if(! typeCheckOnly) {// The tag beanName is being created in the cache
				markBeanAsCreated(beanName);
			}
			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if(requiredType ! =null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				if(dependsOn ! =null) {  @dependson information is used to specify the initialization order between beans
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}// Create a singleton
				if (mbd.isSingleton()) { This is where getSingleton adds the created object to the level 1 cache
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) 
							destroySingleton(beanName);
							throwex; }});// If the generated bean is a FactoryBean, get the real object
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
                // scope = prototype, because it will not be cached and will be recreated each time it is fetched
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else { // Session request these scopes. The scope container manages these objects
					String scopeName = mbd.getScope();
					if(! StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally{ afterPrototypeCreation(beanName); }}); beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); }catch (IllegalStateException ex) {
						throw newScopeNotActiveException(beanName, scopeName, ex); }}}catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally{ beanCreation.end(); }}// Return the successfully initialized object, an object initialization is completed
		return adaptBeanInstance(name, beanInstance, requiredType);  
	}
Copy the code

To summarize the above code flow:

  • Get it from level 3 cache first, if none is in cache. To determine whether there is a parent container, from the parent container. Before formally entering the bean initialization process, obtain the RootBeanDefinition based on beanName, process the bean in dependsOn first, and ensure the creation order of bean dependencies, as explained beloworg.springframework.context.annotation.@DependsOnThis note. The next step is to initialize the bean object by scope. That’s the initialization process. Let’s focus on how to instantiate the singleton beanAbstractAutowireCapableBeanFactory.createBeanGets to register a singleton object

An @dependson annotation means that instantiating an object DependsOn an instantiation, but does not require holding the instance object. For example, bean A needs to rely on Bean B to be instantiated, but bean B does not need to be its property and is often used to mark the order in which different instances are instantiated.

Take a look at the getSingleton method

public Object getSingleton(String beanName, ObjectFactory<? > singletonFactory) { synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); If (singletonObject = = null) {if (this. SingletonsCurrentlyInDestruction) {/ / tag whether bean in the destruction of throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!) "); } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { } catch (BeanCreationException ex) { throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); }} return singletonObject; } } protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); }}Copy the code

Adding to the level 1 cache indicates that the bean has been instantiated and is ready for normal use. Let’s look at how instantiation and property injection work.

createBean

Enter below AbstractAutowireCapableBeanFactory createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; MBD => mbdToUse Class<? > resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass ! = null && ! mbd.hasBeanClass() && mbd.getBeanClassName() ! = null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. // Enhanced BeanPostProcessors returns a proxy object that generates AOP, Using multiple BeanPostProcessors to handle Object bean = resolveBeforeInstantiation (beanName mbdToUse); if (bean ! = null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); Object beanInstance = doCreateBean(beanName, mbdToUse, args); return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); }}Copy the code

This logic is relatively simple, cloning a RootBeanDefinition used to initialize the object, resolveBeforeInstantiation is mainly used to initialize a proxy object, Main use BeanPostProcessor subclass InstantiationAwareBeanPostProcessor implementation method to achieve object initialization, and after the instantiation successful rear in the calling method object dependency injection, here you can see the method returns objects directly out of the way the stack, Here you can see the difference between singletons and proxy objects. The singleton initialization is implemented in doCreateBean

doCreateBean

Below is AbstractAutowireCapableBeanFactory. DoCreateBean how very close to the object instantiated

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) { 
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);  // This is the instantiation method} Object bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; }/ / use BeanDefinitionPostProcessors bean to instantiate the merge
		synchronized (mbd.postProcessingLock) {
			if(! mbd.postProcessed) {try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true; }}// We need to use the above level cache knowledge
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName)); // Whether to put it in level 3 cache
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); // Add the instantiated object to the third-level cache singletonFactories
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper); // Enter an injection for attributes, which will be discussed below
			exposedObject = initializeBean(beanName, exposedObject, mbd); // Perform the initialization method, or inject the Aware interface bean
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); }}// The following code is omitted
               // Mainly handle the hook destruction method which is set to DisposableBean interface
	}
Copy the code

The code here is divided into three main parts

  1. The instance is initialized, the object is created, and added to the level 3 cache. Level 3 caches are often used to store proxy objects, because some classes that need dynamic proxy methods will delegate the generation of proxy objects to the level 3 caches method ObjectFactroy. Ordinary objects will be returned if they are not needed.
  2. Perform property injection on the instantiated bean
  3. Perform the initialization method to join the DisposableBean interface to the disposableBeans container

instantiateBean

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);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) {// Implement the Supplier interface, which is created by the instancesupplier.get () method
			return obtainFromSupplier(instanceSupplier, beanName);
		}

                //factoryName uses factory mode to create beans and calls factory methods to do so. This supports static methods and factoryBean.invoke
		if(mbd.getFactoryMethodName() ! =null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;   // marks whether the constructor needs arguments
		boolean autowireNecessary = false;  // marks whether the constructor argument uses injection
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) { 
				if(mbd.resolvedConstructorOrFactoryMethod ! =null) {
					resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; }}}if (resolved) {
			if (autowireNecessary) {
                               // instantiate using constructor injection
				return autowireConstructor(beanName, mbd, null.null);
			}
			else {
                               // instantiate the object
				returninstantiateBean(beanName, mbd); }}// Get the constructor argumentConstructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if(ctors ! =null|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if(ctors ! =null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}
Copy the code

Instantiation method will eventually call instantiateBean SimpleInstantiationStrategy. Instantiate instantiated

instantiate

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if(! bd.hasMethodOverrides()) { Constructor<? > constructorToUse;synchronized(bd.constructorArgumentLock) { constructorToUse = (Constructor<? >) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse == null) {
					finalClass<? > clazz = bd.getBeanClass();if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if(System.getSecurityManager() ! =null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<? >>) clazz::getDeclaredConstructor); }else {
							constructorToUse = clazz.getDeclaredConstructor(); // Get the constructor
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex); }}}return BeanUtils.instantiateClass(constructorToUse); // Call the constructor to instantiate
		}
		else {
			// Must generate CGLIB subclass.
			returninstantiateWithMethodInjection(bd, beanName, owner); }}Copy the code

instantiateClass

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if(! bd.hasMethodOverrides()) { Constructor<? > constructorToUse;synchronized(bd.constructorArgumentLock) { constructorToUse = (Constructor<? >) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse == null) {
					finalClass<? > clazz = bd.getBeanClass();if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if(System.getSecurityManager() ! =null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<? >>) clazz::getDeclaredConstructor); }else {
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex); }}}return BeanUtils.instantiateClass(constructorToUse);  // Call the constructor for initialization
		}
		else {
			// Must generate CGLIB subclass.
			returninstantiateWithMethodInjection(bd, beanName, owner); }}Copy the code

If the bean does not have a method overridden, use the constructor generated by reflection. If the bean does have a method overridden, use gCLIb to create proxy objects. Concrete implementation way on the org. Springframework. Beans. Factory. Support. SimpleInstantiationStrategy. Instantiate, interested students can learn under. At this point a simple bean instantiation is complete.

injection

Below into the IOC another characteristic, bean injection, first from AbstractAutowireCapableBeanFactory. Start populateBean method

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
              / / by InstantiationAwareBeanPostProcessors postProcessAfterInstantiation if returns true, the return value of the target instance itself is the populate, otherwise the populate this process will be ignored
            If true is returned, field injection can be performed
		if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if(! bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;
				}
			}
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
                // There are four ways to get an injection
		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.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
            // The schema is not type-checked. This type of schema is usually used in XML configuration
		booleanneedsDepCheck = (mbd.getDependencyCheck() ! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); / PropertyDescriptor[] filteredPds =null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);  // Get annotation annotation needs to inject method or field, and inject
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return; } } pvs = pvsToUse; }}if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if(pvs ! =null) { applyPropertyValues(beanName, mbd, bw, pvs); }}Copy the code

Tips: On current Bean AutowireCapableBeanFactory. AUTOWIRE_NO suggests that external injection of a class, Routine use of @ Autowire, @ Resource are this type The remaining three are through XML or AutowireCapableBeanFactory. The autowire (Class <? > beanClass, int autowireMode, Boolean dependencyCheck) Set autowireMode.

According to the above code can know the main bean injection is carried out by InstantiationAwareBeanPostProcessor processing, simple interface methods

methods describe
postProcessBeforeInitialization Method is the first method to be executed. It is called before the target Object is instantiated. The return type of this method is Object, and we can return any value. Since the target object is not instantiated at this time, the return value can be used instead of the instance of the target object (such as the proxy object) that should have been generated. If the return value of this method instead of the originally generated by the target object, and the follow-up only postProcessAfterInitialization method is invoked, other methods are no longer called; Otherwise, follow the normal procedure
postProcessAfterInitialization Method is called after the target object is instantiated, when the object has been instantiated but the instance’s properties have not yet been set and are null. Because it is the return value is decided to don’t call postProcessPropertyValues method is one of the factors (because there is another factor is MBD getDependencyCheck ()); If this method returns false, and do not need to check, then postProcessPropertyValues will be ignored no execution; If returns true, postProcessPropertyValues will be executed
postProcessPropertyValues Called after assigning the bean property value to modify the property value. If postProcessAfterInstantiation method returns false, this method may not be invoked. Property values can be modified within this method
postProcessProperties This method is invoked for Bean property assignment

InstantiationAwareBeanPostProcessor interface implementation class three main points

  1. ConfigurationClassPostProcessorThe @Configuration instantiation is handled by the class name. There is no property injection logic.
  2. CommonAnnotationBeanPostProcessorThis class implements bean injection, but implements jSR-250 annotations, @resource,@EJB, @WebServiceref, @WebServicecontext, @postconstrusct, and @predeStory.
  3. AutowiredAnnotationBeanPostProcessor: Implement @AutoWired, @Value injection, and support JSR-330’s @Inject, the main analysis of this class can know bean injection.

AutowiredAnnotationBeanPostProcessor analysis

	private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
	@SuppressWarnings("unchecked")
	public AutowiredAnnotationBeanPostProcessor(a) {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.}}Copy the code

Support annotations are added to the collection at initialization time, and the scanner is used to scan methods, constructors, fields, and inject them if they exist.

How do you know if you need an injection

	@Nullable
	privateMergedAnnotation<? > findAutowiredAnnotation(AccessibleObject ao) { MergedAnnotations annotations = MergedAnnotations.from(ao);for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { MergedAnnotation<? > annotation = annotations.get(type);if (annotation.isPresent()) {
				returnannotation; }}return null;
	} 
Copy the code

AccessibleObject is the parent of Method, Field, and Constructor.

How does postProcessProperties implement bean injection
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
              // Get the required fields, methods
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs); / / injection
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}
       // Get InjectionMetadata
	private InjectionMetadata findAutowiringMetadata(String beanName, Class<? > clazz,@Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quickly fetch from the cache, if not locked to parse, then put the result in the cache
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) { 
			synchronized (this.injectionMetadataCache) { // Double check
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if(metadata ! =null) {
						metadata.clear(pvs);
					}
					metadata = buildAutowiringMetadata(clazz); 
					this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
	}
Copy the code
  • InjectionMetadata is a collection of beans that need to be injected because the bean Class information has already been parsed

See how to scan methods, fields

 	private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
       // Determine from the given annotation whether the class carries the annotation
		if(! AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)) { 
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = newArrayList<>(); Class<? > targetClass = clazz;do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            // Walk through all fields to find the scanned annotations. Note that static modification fields are not supportedReflectionUtils.doWithLocalFields(targetClass, field -> { MergedAnnotation<? > ann = findAutowiredAnnotation(field);if(ann ! =null) {
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
                     // Get the required value in the annotation
					boolean required = determineRequiredStatus(ann);
					currElements.add(newAutowiredFieldElement(field, required)); }}); ReflectionUtils.doWithLocalMethods(targetClass, method -> {// Get the bridge method on the method, because of generic type erasure, to do a safety check on the bridge method, to prevent exceptions in the call
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;
				}
                // Get the annotationMergedAnnotation<? > ann = findAutowiredAnnotation(bridgedMethod);// Method security check
				if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) { Static method injection is not supported
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: "+ method); }}boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(newAutowiredMethodElement(method, required, pd)); }});// The parent attribute takes precedence over the child class
			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while(targetClass ! =null&& targetClass ! = Object.class);// The parent class is resolved up to Object

		return InjectionMetadata.forElements(elements, clazz);
	}
Copy the code

The logic is very simple, that is, according to the given annotation to class to obtain the specified annotation, to obtain the required injection type, but a few lines of simple code can see the powerful coding ability, learn 👍. Now you need to inject the object, see how to 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) { element.inject(target, beanName, pvs); }}}@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				try {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName); }}else {
				value = resolveFieldValue(field, bean, beanName);
			}
			if(value ! =null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); }}private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory ! =null."No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter(); // Type converter
			Object value;
			try {
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			synchronized (this) {
				if (!this.cached) {
					Object cachedFieldValue = null;
					if(value ! =null || this.required) {
						cachedFieldValue = desc;
                        // Add the injection relationship to the container to facilitate synchronous bean destruction
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { // These are all for caching
								cachedFieldValue = newShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); }}}this.cachedFieldValue = cachedFieldValue;
					this.cached = true; }}returnvalue; }}Copy the code

The main core is such as to need to inject type was obtained from the cache instance in the beanFactory. ResolveDependency into DefaultListableBeanFactory a look

	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 {
                        // The Lazy load scans the @lazy annotation to return a proxy object
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			returnresult; }}Copy the code

@lazy uses annotations to modify beans or classes, which are not created immediately when the container is initialized, as long as the bean is needed. Depending on the types Optional, ObjectFactory, Provider, and lazy loading scenarios, these processes essentially call the doResolveDependency method to initialize an object, grab the original object and hand it over to these interfaces to wrap and enhance.

	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
            // If the injection is done through the constructor, the injection points can be retrieved from the constructor resolution cache
		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if(shortcut ! =null) {
				returnshortcut; } Class<? > type = descriptor.getDependencyType();// Try to get the Value of the default @value from the annotation
			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())); }}// Multiple mixed types, stream, collection, Map Array, etc
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if(multipleBeans ! =null) {
				return multipleBeans;
			}

                  The map key is the bean name, and the value is the object from the container. If no object is found, an exception is raised
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {  // There is a type. Different instances can be configured according to @primary, @priority, attribute name
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if(isRequired(descriptor) || ! indicatesMultipleBeans(type)) {// No confirmation, exception thrown
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if(autowiredBeanNames ! =null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {  // Get the instance from the container. If there is no initialization, go through the above initialization process
				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

FindAutowireCandidates = findAutowireCandidates = findAutowireCandidates = findAutowireCandidates = findAutowireCandidates = findAutowireCandidates; This is handled according to the injection type, such as stream and Collection, which are mixed types added directly. If there are more than one bean of a type, the beanName object is returned with @primary, @priority annotations, or beanName attributes. This concludes a brief look at the bean initialization process.

conclusion

Now that you know that Bean instantiation is created by a policy pattern, using a reflection attack class, it doesn’t really have much to do with BeanPostProcessor. When I first started learning Spring, my teacher said that @autowired and @Resources injected into comparison, based on type and beanName, which is not entirely correct. He gets the bean by type, and if a type has more than one beanName, the bean and property name are injected. I have never used @dependson, @primary, @priority, @lookup in Spring for many years. See the complete source code, the bean lifecycle has a clearer bean instantiation -> property injection -> perform initialization methods -> join the Spring container