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 process of obtaining Bean?

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

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

This article mainly explains "what is the process of obtaining Bean". Friends who are interested may wish to take a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "what is the process of obtaining Bean?"

Catalogue

I. Preface

Second, interview questions

III. The process of obtaining Bean

1. GetBean core flow chart

2. Where does getBean start to read the source code

3. Global preview of getBean source code

4. BeanName conversion operation

5. Depends-on depends on Bean

6. Dealing with single instance Bean

7. Get bean instance from cache

8. Obtain bean instance in FactoryBean

Fourth, test cases

1. Alias

two。 Dependence

3. BeanFactory

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 you for the plane. I always feel that there is nothing to see about Spring. How can the interviewer find out the flowers as soon as he asks?

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 FactoryBean, 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 Little Fu, getBean Core flow Chart the whole chart is the class involved in the getBean process and the methods and operations used in 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 do anything, it's 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 {

/ / handle alias BeanName, handle factory BeanName with & character

Final String beanName = transformedBeanName (name)

Object bean

/ / first try to get the Bean instance from the cache. This location is the solution to the circular dependency of the three-level cache.

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 directly

/ / 2. If sharedInstance is a factory Bean type, you need to get the getObject method. You can refer to the implementation class about FactoryBean

Bean = getObjectForBeanInstance (sharedInstance, name, beanName, null)

}

Else {

/ / 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.

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 &, it returns & + beanName.

String nameToLookup = originalBeanName (name)

/ / call different parent container methods to get the bean instance depending on whether the args parameter is empty

If (args! = null) {

Return (T) parentBeanFactory.getBean (nameToLookup, args)

}

Else {

Return parentBeanFactory.getBean (nameToLookup, requiredType)

}

}

/ / 1. TypeCheckOnly, which is used to determine whether only type checking is done when calling the getBean method

/ / 2. If you don't just do type checking, markBeanAsCreated is called to record.

If (! typeCheckOnly) {

MarkBeanAsCreated (beanName)

}

Try {

/ / obtain 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 is an abstract bean definition

CheckMergedBeanDefinition (mbd, beanName, args)

/ / handle the dependency creation of depends-on instances using bean annotations

String [] dependsOn = mbd.getDependsOn ()

If (dependsOn! = null) {

For (String dep: dependsOn) {

/ / Monitor whether there is a depends-on circular dependency. If so, an exception will be thrown.

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 dependencies (dep is the abbreviation of depends-on)

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 a bean

Return createBean (beanName, mbd, args)

}

Catch (BeansException ex) {

/ / destroy if creation fails

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 required, the operation will be done here

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 &, return & + beanNameargs! = null. Call different parent container methods to obtain bean instance! typeCheckOnly,typeCheckOnly according to whether the args parameter is empty, which is used to determine whether only type checking is done when the getBean method is called. If it is not just type checking, markBeanAsCreated is called to record the mbd.getDependsOn to deal with the dependency using depends-on annotations to create bean instance isDependent. Monitor the existence of depends-on circular dependencies, if so, throw an exception registerDependentBean, register dependency record getBean (dep), load depends-on dependencies (dep is depends-on abbreviation) mbd.isSingleton (), create singleton bean instance mbd.isPrototype (), create other types of bean instance return (T) bean, and return 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 with FactoryBean will use getBean (FACTORY_BEAN_PREFIX + beanName) to add & (String FACTORY_BEAN_PREFIX = "&") to beanName during DefaultListableBeanFactory initialization. Here, the while loop is used to remove the & step by step, as long as the first character is the & character, the loop will continue to intercept. & 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, when you don't encounter this kind of problem, you will know where to check the do...while loop and keep looking for the alias corresponding name in turn like a chain, until the current name has no alias, it returns the corresponding BeanName5. Depends-on depends on Bean

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

Protected 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, monitor the dependent BeancanonicalName, process the alias configuration, find the original BeanNameSetdependentBeans, get the dependent Bean collection for loop to detect the dependent Bean recursively, and add it to the 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), get the original beanNamesynchronized (this.dependentBeanMap), add synchronized (this.dependenciesForBeanMap) to dependentBeanMap, add to dependenciesForBeanMap

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 public Object getSingleton (String beanName, ObjectFactory singletonFactory) {using beanName and singletonFactory anonymous inner classes to wait for callback.

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, then continue to execute beforeSingletonCreation (beanName), mark that the current bean is created, if there is a circular dependency injected by the constructor, it will report an error singletonObject = singletonFactory.getObject (), the process of creating bean is to call the createBean () method afterSingletonCreation (beanName), and finally remove the tag from the collection (beanName, singletonObject), and the newly created one will join the cache collection 7. Get bean instance from cache

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

Protected Object getSingleton (String beanName, boolean allowEarlyReference) {

/ / obtain instances from singletonObjects. The cached instances in singletonObjects are all fully instantiated bean, which can be used directly.

Object singletonObject = this.singletonObjects.get (beanName)

/ / if singletonObject is empty, it is not being created or is in the process of being created

If (singletonObject = = null & & isSingletonCurrentlyInCreation (beanName)) {

/ / add lock

Synchronized (this.singletonObjects) {

/ / there is no current beanName in the singleton cache pool

SingletonObject = this.earlySingletonObjects.get (beanName)

If (singletonObject = = null & & allowEarlyReference) {

ObjectFactory singletonFactory = this.singletonFactories.get (beanName)

If (singletonFactory! = null) {

/ / add to the third-level cache, expose the early objects 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 set injection cyclic dependencies. Later, a separate chapter will be listed to do relevant experiments on circular dependencies to verify singletonObjects, which is 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 starts with &, but beanInstance is not FactoryBean, an exception will be thrown

If (BeanFactoryUtils.isFactoryDereference (name) & &! (beanInstance instanceof FactoryBean)) {

Throw new BeanIsNotAFactoryException (transformedBeanName (name), beanInstance.getClass ())

}

/ / to determine whether the bean is FactoryBean or not, it will not be returned directly.

If (! (beanInstance instanceof FactoryBean) | | BeanFactoryUtils.isFactoryDereference (name)) {

Return beanInstance

}

Object object = null

If (mbd = = null) {

/ / if mbd is empty, bean is loaded 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 of FactoryBean type, so it is forced to change.

FactoryBean factory = (FactoryBean) beanInstance

/ / mbd is empty and determine whether 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), this is to determine whether the bean is FactoryBean or not. If mbd is empty, load bean from the cache (singleton bean instances generated by FactoryBean will be cached in the factoryBeanObjectCache collection, which is convenient to use). This will include some processing of singletons and non-singletons, as well as the final return of factory.getObject (); corresponding Bean instance 4, 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 BeanName2. Dependence

@ 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 all such Bean will eventually get getObject. I believe you have a deeper understanding of "what is the process of obtaining Bean". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

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