Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the full process source code of GetBean in Spring?

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "what is the whole process source code of GetBean in Spring". In daily operation, I believe that many people have doubts about the source code of the whole process of GetBean in Spring. Xiaobian consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the question of "what is the whole process source code of GetBean in Spring". Next, please follow the editor to study!

I. Preface

If you ask a problem, you must give a solution!

Recently, there are feedback from fans and friends, and they always encounter obstacles in communicating with their superiors and feel that they are not understood. Most of the time, the things he puts forward may be answered by the leader: "I didn't get to your point,"the project you want to do has no business value,"if you ask a question, give a solution," and so on.

In view of the fact that the specific situation needs to be analyzed in detail, we may not be able to determine whose problem it is, leading to differences in each conversation. It may be that leader has the difficulties and perspective of leader, or it may be that employees have employees' understanding and ideas, so they do not reach an agreement in the end.

But as far as leading a team is concerned, effective communication is very important. Like: if what you say is right, then why am I arguing with you? Instead of suppressing the contradictions encountered, it is better to have an open chat, and whoever has a bigger perspective and mind will have more empathy.

If sharp criticism disappears completely, mild criticism will become harsh.

If mild criticism is not allowed, silence will be considered ulterior motives.

If silence is no longer allowed, it will be a crime to praise not working hard enough.

If only one sound is allowed, then the only voice that exists is a lie.

Second, interview questions

Thank the plane, remember!, always feel that Spring has nothing to see, how can the interviewer ask the flowers?

Interviewer: what is the role of transformedBeanName in Spring's getBean?

Xie Ji: I don't know. It seems that the word means to change the name of Bean.

Interviewer: so, if your Bean has an alias alias, what will Spring do when getting Bean?

Xie Ji: here!

Interviewer: what if you use depends-on?

Xie Ji: Ah, I haven't used depends-on. I don't know!

Interviewer: when you debug the code, have you ever seen a & in front of BeanName, and why?

Xie Ji: I don't deserve to know! Goodbye!

III. The process of obtaining Bean

For partners who have just come into contact with the Spring source code, they may wonder how to get so many processes for a Bean.

There may be Bean, there may be aliases, there may be dependencies, or they may be wrapped by BeanFactory, so there will be transformedBeanName to handle these differentiated behaviors.

There is no circular dependency, whether there is a parent factory, whether it is a singleton or a prototype, whether it is lazy loading or preloading, not in the buffer, so there are various combinations of judgments to do different processes.

Early exposure of objects, three-level cache, and clear post-marking, all of which are optimized to make the acquisition of the entire Bean more efficient.

Therefore, in order to meet all kinds of needs, it becomes more and more complex. The in-depth study of this part of knowledge is definitely not only to deal with the eight-part essay, but also to consider whether there is a roughly known process when complex problems are encountered in the daily use of Spring, which can quickly locate the problems, and whether the technical implementation scheme of such requirements can play a certain guiding role in the future application development, because it is the concrete implementation of a design scheme.

1. GetBean core flow chart

Brother Fu, getBean core flow chart

The whole diagram is the content of the classes involved in the getBean process and the methods and operations used by the core process. If you can understand the whole picture, you will basically understand the whole process of getBean.

This picture may be blurred by network compression and can be obtained by following the official account: bugstack wormhole stack, reply: artwork.

Next, we will list the key codes about obtaining Bean examples in turn for analysis, and readers can also look at them together with the flow chart, which will be easier to understand.

2. Where does getBean start to read the source code @ Test public void test_getBean () {BeanFactory beanFactory = new ClassPathXmlApplicationContext ("spring-config.xml"); UserDao userDao = beanFactory.getBean ("userDao", UserDao.class); logger.info ("get Bean: {}", userDao);}

In the daily application to the development of Spring is basically based on annotations, it is almost impossible to use beanFactory.getBean to get a Bean instance.

So when you are learning, if you can not find the entrance to view the getBean source code, and it is not convenient to debug and be familiar with the source code, you can write such a unit test class and click into getBean to read the source code.

3. Global preview of getBean source code

Source code location: AbstractBeanFactory-> getBean ()-> doGetBean ()

@ Override public T getBean (String name, Class requiredType) throws BeansException {/ / getBean just like your leader didn't actually do anything, all in doGetBean return doGetBean (name, requiredType, null, false);} protected T doGetBean (final String name, final Class requiredType, final Object [] args, boolean typeCheckOnly) throws BeansException {/ / deal with aliases BeanName, factory BeanName final String beanName = transformedBeanName (name) with & symbol; Object bean / / first try to get the Bean instance from the cache. This location is the three-level cache solution Object sharedInstance = getSingleton (beanName); if (sharedInstance! = null & & args = = null) {if (logger.isDebugEnabled ()) {if (isSingletonCurrentlyInCreation (beanName)) {logger.debug ("Returning eagerly cached instance of singleton bean'" + beanName + "'that is not fully initialized yet-a consequence of a circular reference") } else {logger.debug ("Returning cached instance of singleton bean'" + beanName + "'");}} / / 1. If sharedInstance is a normal Bean instance, the following method returns / / 2. If sharedInstance is a factory Bean type, you need to obtain the getObject method. You can refer to the implementation class bean = getObjectForBeanInstance (sharedInstance, name, beanName, null) of FactoryBean.} there are three types of else {/ / cyclic dependencies: setter injection, multiple instances and constructors. Spring can only solve setter injection, so here Prototype throws an exception if (isPrototypeCurrentlyInCreation (beanName)) {throw new BeanCurrentlyInCreationException (beanName);} / / 1. Parent bean factory exists / / 2. If the current bean does not exist in the current bean factory, go to the parent factory to find the bean instance BeanFactory parentBeanFactory = getParentBeanFactory (); if (parentBeanFactory! = null & &! containsBeanDefinition (beanName)) {/ / get the beanName corresponding to name. If name starts with &, return & + beanName String nameToLookup = originalBeanName (name) / / call different parent container methods to get bean instance if (args! = null) {return (T) parentBeanFactory.getBean (nameToLookup, args);} else {return parentBeanFactory.getBean (nameToLookup, requiredType) depending on whether the args parameter is empty }} / / 1. TypeCheckOnly, which is used to determine whether only type checking / / 2 is done when calling the getBean method. If you do not just do type checking, markBeanAsCreated will be called to record if (! typeCheckOnly) {markBeanAsCreated (beanName);} try {/ / get the GenericBeanDefinition corresponding to beanName from the container getMergedLocalBeanDefinition and convert it to RootBeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition (beanName); / / check whether the currently created bean definition defines checkMergedBeanDefinition (mbd, beanName, args) for abstract bean / / handle dependencies that use depends-on annotations to create bean instances String [] dependsOn = mbd.getDependsOn () If (dependsOn! = null) {for (String dep: dependsOn) {/ / monitors the existence of depends-on circular dependencies, and if so, throws an exception if (isDependent (beanName, dep)) {throw new BeanCreationException (mbd.getResourceDescription (), beanName, "Circular depends-on relationship between'" + beanName + "'and'" + dep + ")) } / / Registration dependency record registerDependentBean (dep, beanName); try {/ / load depends-on dependency (dep is depends-on abbreviation) getBean (dep) } catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException (mbd.getResourceDescription (), beanName, "'" + beanName + "'depends on missing bean'" + dep + "", ex) } / / create a singleton bean instance if (mbd.isSingleton ()) {/ / pass beanName and new ObjectFactory anonymous inner classes into the callback sharedInstance = getSingleton (beanName, new ObjectFactory () {@ Override public Object getObject () throws BeansException {try {/ / create bean return createBean (beanName, mbd, args) } catch (BeansException ex) {/ / destroy destroySingleton (beanName); throw ex;}); bean = getObjectForBeanInstance (sharedInstance, name, beanName, mbd);} / / create other types of bean instances 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, new ObjectFactory () {@ Override public Object getObject () throws BeansException {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;}} / / if type conversion is needed, the operation if (requiredType! = null & & bean! = null & & requiredType.isInstance (bean)) {try {return getTypeConverter (). ConvertIfNecessary (bean, requiredType) } catch (TypeMismatchException ex) {if (logger.isDebugEnabled ()) {logger.debug ("Failed to convert bean'" + name + "'to required type'" + ClassUtils.getQualifiedName (requiredType) + "'", ex);} throw new BeanNotOfRequiredTypeException (name, requiredType, bean.getClass ());}} / / return Bean return (T) bean;}

To sum up, it is basically the core processing methods involved in the getBean process, including

TransformedBeanName, which handles aliases BeanName and factory BeanName with & characters.

GetSingleton, first try to get the Bean instance from the cache, this location is the three-level cache to solve the circular dependency.

GetObjectForBeanInstance, if sharedInstance is a normal Bean instance, the following method returns directly. In addition, sharedInstance is a factory Bean type, so you need to get the getObject method. You can refer to the implementation class about FactoryBean.

IsPrototypeCurrentlyInCreation, there are three kinds of circular dependencies: setter injection, multi-instance and constructor. Spring can only solve setter injection, so here Prototype will throw an exception.

GetParentBeanFactory, the parent bean factory exists, and the current bean does not exist in the current bean factory, then go to the parent factory to find the bean instance.

OriginalBeanName, get the beanName corresponding to name. If name starts with &, it returns & + beanName

Args! = null. Call different parent container methods to get the bean instance depending on whether the args parameter is empty.

! typeCheckOnly,typeCheckOnly, which is used to determine whether only type checking is done when the getBean method is called. If not, markBeanAsCreated is called to record.

Mbd.getDependsOn, dealing with dependencies that use depends-on annotations to create bean instances

IsDependent, which monitors the existence of depends-on circular dependencies. If so, an exception will be thrown.

RegisterDependentBean, registration dependency record

GetBean (dep), loading depends-on dependencies (dep is depends-on abbreviation)

Mbd.isSingleton () to create a singleton bean instance

Mbd.isPrototype () to create other types of bean instances

Return (T) bean, which returns the Bean instance

4. BeanName conversion operation

Handle the & symbol: transformedBeanName ()-> BeanFactoryUtils.transformedBeanName (name)

Public static String transformedBeanName (String name) {Assert.notNull (name, "'name' must not be null"); String beanName = name; while (beanName.startsWith (BeanFactory.FACTORY_BEAN_PREFIX)) {beanName = beanName.substring (BeanFactory.FACTORY_BEAN_PREFIX.length ());} return beanName;}

Objects created using FactoryBean will use getBean (FACTORY_BEAN_PREFIX + beanName) to add & (String FACTORY_BEAN_PREFIX = "&") to beanName when DefaultListableBeanFactory is initialized.

Here, the & is removed step by step using the while loop, and the loop interception continues as long as the first character is the & character. & userService-> & & userService-> & & userService-> userService

Alias translation: transformedBeanName ()-> canonicalName

Public String canonicalName (String name) {String canonicalName = name; / / Handle aliasing... String resolvedName; do {resolvedName = this.aliasMap.get (canonicalName); if (resolvedName! = null) {canonicalName = resolvedName;}} while (resolvedName! = null); return canonicalName;}

First of all, Spring does not use aliases as key in Map when storing Bean, so if you encounter all aliases to get Bean, you need to find the corresponding original name. If you know this, if you don't have such problems, you'll know where to start.

The do...while loop will, like a chain, keep looking for the name corresponding to the alias until the current name has no alias, it will return the corresponding BeanName.

5. Depends-on depends on Beanprotected boolean isDependent (String beanName, String dependentBeanName) {synchronized (this.dependentBeanMap) {return isDependent (beanName, dependentBeanName, null);}

IsDependent deals with Bean definitions that use depends-on configuration.

Private boolean isDependent (String beanName, String dependentBeanName, Set alread if (alreadySeen! = null & & alreadySeen.contains (beanName)) {return false;} String canonicalName = canonicalName (beanName); Set dependentBeans = this.dependentBeanMap.get (canonicalName); if (dependentBeans = = null) {return false;} if (dependentBeans.contains (dependentBeanName)) {return true;} for (String transitiveDependency: dependentBeans) {if (alreadySeen = null) {alreadySeen = new HashSet ();} alreadySeen.add (beanName) If (isDependent (transitiveDependency, dependentBeanName, alreadySeen)) {return true;}} return false;}

AlreadySeen! = null to monitor the Bean that you already depend on

CanonicalName, handle alias configuration, find the original BeanName

SetdependentBeans, which gets the dependent Bean collection

The for loop recursively detects dependent Bean and adds it to alreadySeen

AbstractBeanFactory-> registerDependentBean (dep, beanName)-> DefaultSingletonBeanRegistry

Public void registerDependentBean (String beanName, String dependentBeanName) {String canonicalName = canonicalName (beanName); synchronized (this.dependentBeanMap) {Set dependentBeans = this.dependentBeanMap.get (canonicalName); if (dependentBeans = = null) {dependentBeans = new LinkedHashSet (8); this.dependentBeanMap.put (canonicalName, dependentBeans);} dependentBeans.add (dependentBeanName);} synchronized (this.dependenciesForBeanMap) {Set dependenciesForBean = this.dependenciesForBeanMap.get (dependentBeanName if (dependenciesForBean = null) {dependenciesForBean = new LinkedHashSet (8) This.dependenciesForBeanMap.put (dependentBeanName, dependenciesForBean);} dependenciesForBean.add (canonicalName);}}

CanonicalName (beanName) to get the original beanName

Synchronized (this.dependentBeanMap), add

Synchronized (this.dependenciesForBeanMap), add

Finally: getBean (dep), you can get the Bean that depends-on depends on.

6. Dealing with single instance Bean

AbstractBeanFactory-> mbd.isSingleton ()

If (mbd.isSingleton ()) {sharedInstance = getSingleton (beanName, new ObjectFactory () {@ Override public Object getObject () throws BeansException {try {return createBean (beanName, mbd, args);} catch (BeansException ex) {destroySingleton (beanName); throw ex;}); bean = getObjectForBeanInstance (sharedInstance, name, beanName, mbd);}

This part is to create a single instance Bean instance by passing in beanName and singletonFactory anonymous inner classes waiting for callback.

Public Object getSingleton (String beanName, ObjectFactory singletonFactory) {Assert.notNull (beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get (beanName); if (singletonObject = = null) {if (this.singletonsCurrentlyInDestruction) {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!)") } if (logger.isDebugEnabled ()) {logger.debug ("Creating shared instance of singleton bean'" + beanName + "');} 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) {singletonObject = this.singletonObjects.get (beanName); if (singletonObject = = null) {throw ex;}} catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException: this.suppressedExceptions) {ex.addRelatedCause (suppressedException);}} throw ex;} finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null } afterSingletonCreation (beanName);} if (newSingleton) {addSingleton (beanName, singletonObject);}} return (singletonObject! = NULL_OBJECT? SingletonObject: null);}}

This.singletonObjects.get (beanName), first try to get the object from the cache pool, and then proceed without it

BeforeSingletonCreation (beanName), marking that the current bean is created. If there is a circular dependency injected by the constructor, an error will be reported.

SingletonObject = singletonFactory.getObject (), the process of creating bean is to call the createBean () method

AfterSingletonCreation (beanName), which finally removes the tag from the collection

AddSingleton (beanName, singletonObject). Newly created ones will be added to the cache collection

7. Get bean instance from cache

DoCreateBean-> if (earlySingletonExposure)-> getSingleton (beanName, false)

Protected Object getSingleton (String beanName, boolean allowEarlyReference) {/ / get instances from singletonObjects. The cached instances in singletonObjects are all fully instantiated bean. You can directly use Object singletonObject = this.singletonObjects.get (beanName). / / if singletonObject is empty, no if is being created or created (singletonObject = = null & & isSingletonCurrentlyInCreation (beanName)) {/ / locked synchronized (this.singletonObjects) {/ / singleton cache pool, there is no current beanName singletonObject = this.earlySingletonObjects.get (beanName); if (singletonObject = = null & & allowEarlyReference) {ObjectFactory singletonFactory = this.singletonFactories.get (beanName) If (singletonFactory! = null) {/ / added to the third-tier cache, exposure early objects are used to solve the third-level cache singletonObject = singletonFactory.getObject (); this.earlySingletonObjects.put (beanName, singletonObject); this.singletonFactories.remove (beanName);} return (singletonObject! = NULL_OBJECT? SingletonObject: null);}

In fact, this code mainly uses three-level cache to solve the set injection loop dependency, and a separate chapter will be listed to verify the loop dependency.

SingletonObjects, used to store initialized bean instances.

EarlySingletonObjects, which is used to store the bean in initialization to solve circular dependencies.

SingletonFactories, used to store the bean factory, the bean generated by the bean factory has not yet finished initializing the bean.

8. Obtain bean instance in FactoryBean

AbstractBeanFactory-> getObjectForBeanInstance (sharedInstance, name, beanName, null)

Protected Object getObjectForBeanInstance (Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {/ / if beanName begins with & but beanInstance is not FactoryBean, an exception if (BeanFactoryUtils.isFactoryDereference (name) & &! (beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException (transformedBeanName (name), beanInstance.getClass ()) will be thrown } / / to determine whether the bean is FactoryBean or not, instead of directly returning if (! (beanInstance instanceof FactoryBean) | | BeanFactoryUtils.isFactoryDereference (name)) {return beanInstance;} Object object = null; if (mbd = = null) {/ / if mbd is empty, load bean from the cache (singleton bean instances generated by FactoryBean are cached to the factoryBeanObjectCache collection for convenience) object = getCachedObjectForFactoryBean (beanName) } if (object = = null) {/ / here, beanInstance is a FactoryBean type, so I forcefully change FactoryBean factory = (FactoryBean) beanInstance; / / mbd to be empty and determine whether the containsBeanDefinition contains beanName if (mbd = = null & & containsBeanDefinition (beanName)) {/ / merge BeanDefinition mbd = getMergedLocalBeanDefinition (beanName);} boolean synthetic = (mbd! = null & & mbd.isSynthetic ()) / / call getObjectFromFactoryBean to get the instance object = getObjectFromFactoryBean (factory, beanName,! synthetic);} return object;}

(! (beanInstance instanceof FactoryBean), the judgment here is whether the bean is a FactoryBean or not. It is not returned directly.

If mbd is empty, bean is loaded from the cache (singleton bean instances generated by FactoryBean are cached to the factoryBeanObjectCache collection for ease of use)

Call getObjectFromFactoryBean to get the instance, which includes some processing of singletons and non-singletons, and the final return of factory.getObject (); the corresponding Bean instance

Fourth, test case 1. Alias @ Test public void test_alias () {BeanFactory beanFactory = new ClassPathXmlApplicationContext ("spring-config-alias.xml"); UserService userService = beanFactory.getBean ("userService-alias02", UserService.class); logger.info ("get Bean via alias: {}", userService);}

When you unit test getBean, you will see that it will gradually dispose of the alias and eventually get the original BeanName

two。 Rely on @ Test public void test_depends_on () {BeanFactory beanFactory = new ClassPathXmlApplicationContext ("spring-config-depends-on.xml"); UserService userService = beanFactory.getBean (UserService.class, "userService"); logger.info ("get Bean: {}", userService.getUserDao ());}

When it comes to dependencies, you will go to dependsOn! = null to get the dependent Bean instance.

3. BeanFactory @ Test public void test_factory_bean () {BeanFactory beanFactory = new ClassPathXmlApplicationContext ("spring-config-factory-bean.xml"); UserDao userDao = beanFactory.getBean ("userDao", UserDao.class); logger.info ("get Bean: {}", userDao);}

Classes that implement FactoryBean will need to implement the getObject method, and the Bean of all such classes will eventually get the getObject

At this point, the study of "what is the whole process source code of GetBean in Spring" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report