The introduction
AbstractBeanFactory getBean process, ordering, a bit like a foreigner to look down. Don’t believe us.
The entrance
AbstractBeanFactory has general logic for getBean
AbstractBeanFactory @override public Object getBean(String name, Object... args) throws BeansException {return doGetBean(name, null, args, false);
}
Copy the code
The core logic is in: doGetBean.
Logic description:
- Get BeanName, remove & from BeanFactory, and find the corresponding BeanName based on the alias. (That’s what the boss said.)
- Try to get the singleton from the cache and return it if it exists.
- Check if the prototypeBean is being created, if so, assume there is a circular reference, and throw an exception (that is, the boss is checking to see if it is being created, if it is).
- Find the BeanFactory that defines the bean.
- Merge multiple GernericBeanDefinitions into RootBeanDefinitions, and if the Bean has a parent, merge the related attributes of the parent class. (The boss records the dietary restrictions of the guests)
- Ensure that bean dependencies are initialized first, support for DependOn annotations (to do the necessary work to make the dish, such as washing dishes)
- Create beans with different scopes
- If you need to type cast
After the jokes, let’s get down to brass tacks.
Source code notes:
/**
* Return an instance, whichMay be shared or independent, of the specified bean. * Obtain an instance, which may be shared or independent, of the specified bean. Specified * @param name the name of the bean to retrieve * @param requiredType the requiredtypeof the bean to retrieve * @param args arguments to use when creating a bean instance * using explicit arguments * (only Applied when creating a new instance as opposed to retrieving an existing one) * Instead of getting an existing beantypeCheckOnly whether the instance is obtained
for a type check,not forActual use * is just type checking * @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //1. BeanName final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cacheformanually registered singletons. //2. Trying to fetch a singleton from the cache Spring creates an ObjectFactory object for the Bean before it is created, exposing it early to help resolve loop dependencies. 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 + "'"); } // Get the object from the bean instance, if it is a FactoryBean, get the object bean it creates = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else {
// Fail if we're already creating this bean instance: // We're assumably within a circular reference. //3. Check for stereotype dependencies and, if it is a stereotype, throw an exception, assuming a circular referenceif (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists inBeanFactory = getParentBeanFactory(); BeanFactory = getParentBeanFactory(); If the parent BeanFactory is not empty && there is no beanDefinitionMap that does not contain, // delegate to the parent BeanFactoryif(parentBeanFactory ! = null && ! containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if(args ! {// Delegation to parent with explicit args. // Delegate to the getBean method that requires argumentsreturn (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if(requiredType ! = null) {// No args -> delegate to standard getBean methodreturn parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return(T) parentBeanFactory.getBean(nameToLookup); }}if (!typeCheckOnly) {// not only type check, markBeanAsCreated // allow bean to be re-merged (beanName); } try {//5. Convert GernericBeanDefinition to RootBeanDefinition, // If the Bean has a parent, the parent will be merged. final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that // the current bean depends on. // 6. String[] dependsOn = mbd.getSon ();if(dependsOn ! = null) {for(String dep: dependsOn) {// @dependson annotation, /** * check whether there is a depends-on cycle dependency, if there is an exception. For example, A depends on B, and B depends on A: @bean (name="a")
@DependsOn("b")public A a () {
returnnew A(); } @Bean(name ="b")
@DependsOn("a")
public B b () {
returnnew B(); } * A requires that B be created before it, but B requires that A be created before it *. So this is a cycle, and for the Depends -on cycle, An exception Spring will directly * * * @ see org. Springframework. Context. The annotation. ClassPathBeanDefinitionScanner#doScan* /if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); RegisterDependentBean (dep, beanName); // DependentBean(deP, beanName); // Create the Dependent getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // Create bean instance. //7. Create an instance of the Beanif (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow forcircular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }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); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final 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); }}); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. // 8. // requiredType.isInstance (bean) : bean instanceof requiredType: true //clazz.isAssignableFrom(obj.getClass()) == clazz.isinstance (obj) // only if obj is not null if (requiredType! = null && ! requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }Copy the code
A picture is worth a thousand words (Time series)
After reading the main process, I have the following questions:
- What does getObjectForBeanInstance do?
- The role of markBeanAsCreated and getMergedLocalBeanDefinition
- A: What is bean’s DependsOn?
- The logic of createBean
GetObjectForBeanInstance and createBean logic will be uploaded before 20190921. So let’s say 2,4.
Supplementary notes:
The role of markBeanAsCreated and getMergedLocalBeanDefinition
Simply put, it is to clear the original RootBeanDefinition and merge the current multiple GenericBeanDefinitions into a new RootBeanDefinition for use by the BeanFactory.
What is a BeanDefinition
- BeanDefinition is a minimalist interface, main purpose is to allow the spring BeanFactoryPostProcessor (such as: accomplished) to reflect the bean and modify the attribute values and other metadata.
- GenericBeanDefinition is used to one-stop define standard beans. Like other BeanDefinitions, it allows you to specify a class, attribute value, optional constructor parameter value, and parentName can be configured to support derivation relationships.
- RootBeanDefinition represents the merged beanDefinition, Spring’s BeanFactory uses RootBeanDefinition to create the specified bean which may inherit multiple original BeanDefinitions, These source BeanDefinitions are typically GenericBeanDefinitions, and rootBeanDefinitions are essentially run-time “unified” bean definition views.
If you are interested, you can search
org.springframework.beans.factory.config.BeanDefinition org.springframework.beans.factory.support.GenericBeanDefinition org.springframework.beans.factory.support.RootBeanDefinition
What is the DependOn for a bean?
I initially thought it was the bean that needed to rely on and handle Autowired annotations, but it wasn’t. Find the place where BeanDefinition’s setDependsOn is called using IDEA.
Found AnnotationConfigUtils. ProcessCommonDefinitionAnnotations methods such as the following code:
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if(dependsOn ! = null) { abd.setDependsOn(dependsOn.getStringArray("value"));
}
Copy the code
That is, in doGetBean
String[] dependsOn = mbd.getDependsOn();
if(dependsOn ! = null) { ..... }Copy the code
It’s an endorsement of the @dependon annotation, which I don’t know about and haven’t used in my work. I looked it up on the Internet. The URL of the information I checked at that time: blog.csdn.net/qq_30257149…
The @dependon annotation is used to indicate that the instantiation of one bean A depends on the instantiation of another bean B, but that A does not need to hold an object of B
A few words of long-winded
Read the source code is not easy, at the beginning I always seize a method not to put, a few hours down, have no idea where they read, then always muddy destruction swallow dates, blindly for fast, as if to see a lot, in fact, what also don’t know. In early September this year, don’t know what is the weather in Beijing is getting cooler, or any other reason, I also not clear, can calm down and not fast, a layer of a layer of reading, translation, bit by bit every day read only 40 minutes, finally feeling is to understand a little, can not help but sigh with emotion as follows: only grasp details too confused Muddy lun tun net blind dates Meditation is not read fast slow Anyway I am a primer