In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-10 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "how to understand the circular dependence of Spring Bean IOC and AOP". In daily operation, I believe many people have doubts about how to understand the circular dependence of Spring Bean IOC and AOP. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods, hoping to help you answer the doubts of "how to understand the circular dependence of Spring Bean IOC and AOP"! Next, please follow the editor to study!
Catalogue
I. Preface
Second, interview questions
Third, what is circular dependence?
1. Problem description
two。 Problem embodiment
3. Problem handling
IV. Source code analysis
1. Tell me the details.
two。 Treatment process
3. Dependency parsing
V. Summary
VI. Series recommendation
I. Preface
What can delayed gratification bring you?
I have been in college for four years, but almost everyone finds it hard to find a good job until they are close to graduation, especially in the software development industry that I am very familiar with. Even if I graduate, I still need to spend extra money on training institutions to learn programming skills before I can go out and look for a job. It seems that I haven't learned anything in the past few years at school!
Personally, I may be because I liked programming when I was in school. I also heard from my elder brother and sister that it was not easy to find a job after graduation. I also learned about the level of social requirements for programmers' development skills. That is, with the news and my willingness to toss around, I set myself a small goal that I can achieve every day:
Several kings of the world of mortals, I do not accept head-on.
Knock 200 lines of code every day, and break into the top 500 in the world.
Ha, ha,
At this time, it is easy to find a job, it comes from your continuous study and precipitation, but if you do not go through these efforts, you may become very flustered after graduation. in the end, you have no choice but to go to some institutions to study again.
Second, interview questions
Thank you for flying! I used to feel like Spring was fine. I read an article about getBean. Oh, my God!
Xie Ji: interviewer, I recently read Spring's getBean and found that there are a lot of things here, and another one is to solve the circular dependency. Do you have any questions for this interview?
Interviewer: yes, how does Spring solve circular dependency?
Xie Jing: well, it is solved by exposing objects in advance through three-level cache.
Interviewer: yes, what kind of object information is stored in these three caches?
Xie Ji: the first-level cache stores complete objects, also known as finished objects. The second-level cache holds semi-finished objects, those whose properties have not yet been assigned. The third-level cache holds lambda expressions of type ObjectFactory, which is used to deal with AOP circular dependencies.
Interviewer: yes, thank you for your preparation. Can circular dependency be solved if there is no level 3 cache, only level 2 or level 1?
Xie Jing: actually, I have read the data, and it can be solved, but Spring has to guarantee several things. Only the first-level cache processing flow cannot be split, and the complexity will increase. At the same time, semi-finished objects may have null pointer exceptions. By separating the semi-finished product from the finished product, it is more elegant, simple and easy to expand. In addition, among the two major features of Spring, there are not only IOC but also AOP, that is, where to store the enhanced bytecode method, and the three-level cache is the most important, and the circular dependency to be solved is the processing of AOP, but if the creation of the AOP proxy object is advanced, then the second-level cache can also be solved. However, this violates Spring's principle of creating objects. Spring prefers to initialize all ordinary Bean and deal with the initialization of proxy objects.
Interviewer: plane, not bad. I've learned a lot this time. So let me ask you a simple one, have you ever played with a circular dependency solution?
Xie Ji: Oh, no, I haven't practiced it! We really should do it and try it.
Third, what is circular dependence?
1. Problem description
Understanding the nature of the problem and then analyzing the problem is often more conducive to a more in-depth understanding and study of the problem. So before we analyze the Spring source code for circular dependencies, we need to understand what circular dependencies are.
There are three kinds of circular dependence: self-dependence, mutual circular dependence and multi-group circular dependence.
But no matter how many circular dependencies there are, the nature of circular dependence is the same. Even your complete creation depends on me, and my complete creation also depends on you, but we can't decouple each other, resulting in dependency creation failure.
So Spring provides a setter circular dependency injection solution in addition to constructor injection and prototype injection. Then we can also try this kind of dependence first, and how to solve it if we deal with it ourselves.
two。 Problem embodiment
Public class ABTest {public static void main (String [] args) {new ClazzA ();}} class ClazzA {private ClazzB b = new ClazzB ();} class ClazzB {private ClazzA a = new ClazzA ();}
This code is cyclically dependent on the original appearance, you have me, I have you, run on the wrong java.lang.StackOverflowError
This kind of circular dependency code can not be solved, when you see the get/set or annotations provided in Spring, the reason why this can be solved, first of all, there is a certain decoupling. Separate the creation of the class from the filling of attributes, first create a semi-finished Bean, and then deal with the filling of attributes to complete the provision of the finished Bean.
3. Problem handling
For a core purpose in this part of the code, let's solve the circular dependency ourselves, as follows:
Public class CircleTest {private final static Map singletonObjects = new ConcurrentHashMap; public static void main (String [] args) throws Exception {System.out.println (getBean (B.class). GetA ()); System.out.println (getBean (A.class). GetB ());} private static T getBean (Class beanClass) throws Exception {String beanName = beanClass.getSimpleName (). ToLowerCase () If (singletonObjects.containsKey (beanName)) {return (T) singletonObjects.get (beanName);} / / instantiated object is cached Object obj = beanClass.newInstance (); singletonObjects.put (beanName, obj); / / attribute fill completion object Field [] fields = obj.getClass (). GetDeclaredFields () For (Field field: fields) {field.setAccessible (true); Class fieldClass = field.getType (); String fieldBeanName = fieldClass.getSimpleName (). ToLowerCase (); field.set (obj, singletonObjects.containsKey (fieldBeanName)? SingletonObjects.get (fieldBeanName): getBean (fieldClass)); field.setAccessible (false);} return (T) obj;}} class A {private B b; /... get/set} class B {private An a; / /... get/set}
This code provides two classes An and B, which depend on each other. However, the dependencies in the two classes are populated using the setter approach. This is the only way to prevent two classes from having to rely heavily on another object at the beginning of their creation.
GetBean is the core content of the whole solution of circular dependency. If A relies on B when filling attributes after creation, then create B. when creating B starts filling, it is found that it depends on A, but at this time, A, a semi-finished object, is already cached in singletonObjects, so B can create it normally and complete A through recursion.
IV. Source code analysis
1. Tell me the details.
From the above example, we roughly know that when An and B depend on each other, A populates attribute B after creation, continues to create B, and then populates attribute A, which can be obtained from the cache, as follows:
So what does this problem of solving circular dependencies look like in Spring? Expand the details!
Although the core principle of solving circular dependency is the same, it becomes more complicated when it comes to supporting the IOC and AOP features of the entire Spring. The whole process of dealing with Spring circular dependency is as follows
These are the details about the acquisition process of an object with circular dependency in Spring, that is, what you want.
At first glance, there are a lot of processes, but these are basically code snippets that you have to go through when debugging your code. It is very convenient to get this execution flow and then debug it.
two。 Treatment process
The source code analysis of the case covered in this section has been updated to github: https://github.com/fuzhengwei/interview-interview-31
The following is the acquisition Bean operation of AB dependency in the unit test, focusing on the source code follow-up of entering getBean
@ Test public void test_alias () {BeanFactory beanFactory = new ClassPathXmlApplicationContext ("spring-config.xml"); Bean_A bean_a = beanFactory.getBean ("bean_a", Bean_A.class); logger.info ("get Bean via alias: {}", bean_a.getBean_b ());}
Org.springframework.beans.factory.support.AbstractBeanFactory.java
@ Override public T getBean (String name, Class requiredType) throws BeansException {return doGetBean (name, requiredType, null, false);}
After entering from getBean, the operation of getting bean will go to doGetBean.
The reason for this packaging is that doGetBean has many overloaded methods for different input parameters to facilitate external operation.
DoGetBean method
Protected T doGetBean (final String name, final Class requiredType, final Object [] args, boolean typeCheckOnly) throws BeansException {/ / get bean instance Object sharedInstance = getSingleton (beanName) from cache / / mbd.isSingleton () is used to determine whether bean is a singleton mode if (mbd.isSingleton ()) {/ / get bean instance sharedInstance = getSingleton (beanName, new ObjectFactory () {@ Override public Object getObject () throws BeansException {try {/ / create bean instance, bean instantiated return createBean (beanName, mbd, args) returned by createBean } catch (BeansException ex) {destroySingleton (beanName); throw ex;}); / / subsequent processing operation bean = getObjectForBeanInstance (sharedInstance, name, beanName, mbd);} /. / / return bean instance return (T) bean;}
As you can see in the flow chart of the source code analysis, this part is to judge whether there is an instance object from getSingleton, and there is definitely no object for the first entry, so continue to go down.
After judging the mbd.isSingleton () singleton, we start to create the createBean based on the ObjectFactory wrapper, and the core logic is to start performing the doCreateBean operation.
DoCreateBean method
Protected Object doCreateBean (final String beanName, final RootBeanDefinition mbd, final Object [] args) throws BeanCreationException {/ / create a bean instance and wrap the bean instance into a BeanWrapper object to return instanceWrapper = createBeanInstance (beanName, mbd, args) / / add the bean factory object to the singletonFactories cache addSingletonFactory (beanName, new ObjectFactory () {@ Override public Object getObject () throws BeansException {/ / get the early reference of the original object. In the getEarlyBeanReference method, the AOP-related logic is executed. If bean is not intercepted by AOP, getEarlyBeanReference returns bean as is. Return getEarlyBeanReference (beanName, mbd, bean);}}); try {/ / populate attributes, resolve dependencies populateBean (beanName, mbd, instanceWrapper); if (exposedObject! = null) {exposedObject = initializeBean (beanName, exposedObject, mbd);}} / return bean instance return exposedObject;}
There are many contents in the doCreateBean method, but the core is to create instances, add caches and finally populate attributes, which is to populate the classes involved in each property field of a bean.
CreateBeanInstance, create a bean instance, and wrap the bean instance into a BeanWrapper object to return
AddSingletonFactory, adding bean factory objects to the singletonFactories cache
GetEarlyBeanReference, which gets an early reference to the original object, and in the getEarlyBeanReference method, the AOP-related logic is executed. If bean is not intercepted by AOP, getEarlyBeanReference returns bean as is.
PopulateBean, populate attributes, resolve dependencies. This is where you start to find property B in An instance, then create B instance, and finally return.
GetSingleton three-level cache
Protected Object getSingleton (String beanName, boolean allowEarlyReference) {/ / obtain an instance from singletonObjects. SingletonObjects is the finished product bean Object singletonObject = this.singletonObjects.get (beanName); / / determine whether the bean corresponding to beanName and isSingletonCurrentlyInCreation is in the process of creating if (singletonObject = = null & & isSingletonCurrentlyInCreation (beanName)) {synchronized (this.singletonObjects) {/ / obtain bean singletonObject = this.earlySingletonObjects.get (beanName) from earlySingletonObjects If (singletonObject = = null & & allowEarlyReference) {/ / get the corresponding bean factory ObjectFactory singletonFactory = this.singletonFactories.get (beanName); if (singletonFactory! = null) {/ / pre-expose the bean instance, which is mainly used to solve the AOP circular dependency singletonObject = singletonFactory.getObject (); / / put singletonObject into the cache and remove this.earlySingletonObjects.put (beanName, singletonObject) from the singletonFactory cache This.singletonFactories.remove (beanName);} return (singletonObject! = NULL_OBJECT? SingletonObject: null);}
SingletonObjects.get (beanName). Get an instance from singletonObjects. SingletonObjects is the finished bean.
IsSingletonCurrentlyInCreation, to determine whether the bean corresponding to beanName and isSingletonCurrentlyInCreation is being created
AllowEarlyReference, obtain the bean that exposes the unfinished product in advance from earlySingletonObjects.
SingletonFactory.getObject (), which exposes bean instances in advance, which is mainly used to solve AOP circular dependencies.
To sum up, it is a code process to deal with circular dependency. the content extracted from this part is mainly the core content, and it is not all taken out at length, and there will be more involved in debugging. Try to debug several times according to the flow chart.
3. Dependency parsing
To sum up, we try to solve circular dependence by ourselves, and learn the core solution principle of circular dependence. It also analyzes the processing process of circular dependency solved by Spring and the analysis of the core source code. Then we summarize the different processing processes of the lower three levels of cache, which can be regarded as a summary and convenient for everyone to understand.
1. Can first-level caching be solved?
In fact, only one level of caching is not unable to solve circular dependencies, just like our own example.
But in Spring, if you deal with it as we did in our example, it becomes very troublesome, and there may also be NPE problems.
Therefore, as shown in the figure, according to the process handled by the code in Spring, we can not solve the problem of circular dependency in the process of storing finished Bean like first-level cache. Because the creation of the finished product of A depends on the creation of the finished product of Bline B and the creation of the finished product of B depends on A. when the attributes of B need to be completed, An is not finished, so there will be an endless loop.
two。 Can second-tier caching be solved?
This is actually easy to deal with with a second-level cache, one cache for finished objects and the other for semi-finished objects.
An is stored in the cache after the semi-finished object is created, and then the properties that depend on B in the An object are added.
B continues to create, and the created semi-finished product is also put in the cache, which can be obtained from the semi-finished product cache when supplementing the An attribute of the object. Now B is a complete object, and then An is also a complete object like a recursive operation.
3. What does the third-level cache solve?
With a second-level cache can solve the Spring dependency, how to have a three-level cache. In fact, we also mentioned in the previous analysis of the source code, three-tier cache is mainly to solve the characteristics of Spring AOP. AOP itself is an enhancement to the method, which is an lambda expression of type ObjectFactory, and the principle of Spring does not want this type of Bean to be pre-created, so it is stored in a three-level cache.
In fact, the overall processing process is similar, except that when B populates attribute A, it first queries the finished product cache, then checks the semi-finished product cache, and finally checks to see if there are any singleton project classes in the third-level cache. Finally, call the getObject method to return the proxy reference or the original reference later.
At this point, the three-level cache problem caused by Spring AOP is solved.
At this point, the study on "how to understand the circular dependency of Spring Bean IOC and AOP" 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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.