Весна имеет свое собственное решение для круговых зависимостей между бобами. Ключевым моментом является кеш третьего уровня. Конечно, это решение не может решить все проблемы, оно может лишь решить только круговую зависимость неконструкций в режиме синглтона фасоля.
Мы начнем с порядка инициализации a-> b-> ca, что означает, что в бобах необходимы экземпляры B, экземпляры C необходимы в бобах B, в бобах C необходимы экземпляры C, а экземпляры A необходимы в бобах C. Конечно, эта потребность не является зависимостью, подобной конструктору. Как только предпосылки доступны, мы можем начать. Нет сомнений, что мы инициализируем первое. Метод инициализации - org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
Защищенный <t> t Dogetbean (Имя окончательного строки, окончательный класс <T> обязательный, конечный объект [] args, boolean typecheckonly) бросает Beansexception {final String beanname = transformedbeanName (name); Объектный боб; // с нетерпением проверьте синглтонский кэш на предмет зарегистрированных вручную синглтонов. Object sharedinstance = getsingleton (Beanname); // фокусируется 1 if (sharedinstance! = Null && args == null) {if (logger.isdebugenabled ()) {if (issingletoncurlyincreation (beanname)) {logger.debug («возвращающийся нетерпеливый кэшированный экземпляр Singleton ' + Beanname +», который еще не является полностью начальным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным, который еще не является инициализированным. } else {logger.debug ("возвращающий кэшированный экземпляр синглтонского бона '" + beanname + "'"); }} bean = getObjectforbeanInstance (sharedinstance, имя, beanname, null); } else {// Не удалось, если мы уже создаем этот экземпляр Bean: // Мы предполагаем в круговой ссылке. if (isprototypurlyNincreation (beanname)) {бросить новый BeancurryIncreationException (BeanName); } // Проверьте, существует ли определение бобов на этой фабрике. Beanfactory parentbeanfactory = getParentBeanFactory (); if (parentbeanfactory! = null &&! Содержит Beandefinition (beanname)) {// не найдено -> Проверьте родитель. String nametolookup = OriginalBeanName (name); if (args! = null) {// делегирование родителям с явными Args. return (t) parentbeanfactory.getbean (nametolookup, args); } else {// no args -> делегировать в стандартный метод GetBean. return parentbeanfactory.getbean (nametolookup, readytype); }} if (! typecheckonly) {markbeanascreated (beanname); } try {final rootbeandefinition mbd = getmergedlocalbeandefinition (beanname); Checkmergedbeandefinition (MBD, Beanname, Args); // гарантировать инициализацию бобов, от которой зависит текущий боб. String [] deventson = mbd.getDependson (); if (иждинсон! = null) {for (string desentsonbean: dependson) {if (isdependious (beanname, depencesonbean)) {throw new beancreationexception (mbd.getresourcedescription (), beanname, "циркулярная зависимость между" + beanname + "и" и " + degysonbean +" '); } RegisterDependentBean (иждинсонбейн, Beanname); getbean (иждинсонбан); }} // Создать экземпляр боба. if (mbd.issingleton ()) {// confoce 2 sharedinstance = getsingleton (beanname, new objectfactory <object> () {@Override public Object getObject () бросает BeanSexception {try {return createBean (beanname, mbd, args);} catch (beanSexcept Поместить там // Процесс создания bean = getObjectforbeanInstance (sharedinstance, имя, beanname, mbd); } else if (mbd.isprototype ()) {// Это прототип -> Создать новый экземпляр. Объект PrototypeInstance = null; try {перед прототипированием (Beanname); PrototypeInstance = CreateBean (Beanname, MBD, ARGS); } наконец {AfterPrototypeCreation (Beanname); } bean = getObjectForbeanInstance (PrototypeInstance, имя, Beanname, MBD); } else {string scopename = mbd.getScope (); Окончательная область применения = this.scopes.get (scopename); if (scope == null) {бросить new allodalstateexception ("без применения, не зарегистрированной для имени сферы" " + scopename +" '"); } try {object scopedInstance = scope.get (beanname, new objectfactory <object> () {@Override public Object getObject () Throws BeanSexception {перед прототипированием (Beanname); try {return createbean (beanname, mbd, args); bean = getObjectforbeanInstance (ScopedInstance, имя, Beanname, MBD); } catch (allogalStateException ex) {Throw New BeancreationException (Beanname, «Scope '» + Scopename + "' не является активным для текущего потока; рассмотрите" + "определение прокси -сервера для этого боба, если вы собираетесь ссылаться на него из синглтона", ex); }}} catch (beansexception ex) {cleanupafterbeancreationfailure (beanname); бросить бывш; }} // Проверка, если требуется тип, соответствует типу фактического экземпляра боба. if (requireType! = null && bean! = null &&! udeyType.isassignableFrom (bean.getClass ())) {try {return getTypeConverter (). ConvertifNecessary (bean, обязательный тип); } catch (typemismatchexception ex) {if (logger.isdebugenabled ()) {logger.debug («Не удалось преобразовать компонент '" + name + "' tos teble [" + classutils.getqualifiedname (requiretype) + "]", ex); } бросить новый BeannotofRequiredTyPeexception (имя, обязательное значение, bean.getClass ()); }} return (t) bean; } Этот метод очень длинный, давайте поговорим о нем понемногу. Давайте сначала посмотрим на наш фокус. Object sharedInstance = getSingleton(beanName ) получает объект Singleton из коллекции синглтонов на основе имени. Давайте посмотрим на этот метод, и, наконец, org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
Защищенный объект getsingleton (String beanname, boolean ablearlyreference) {Object singletonObject = this.singletonObjects.get (beanname); if (singletonobject == null && issingletoncurryincreation (beanname)) {synchronized (this.singletonobjects) {singletonobject = this.earlysingletonobjects.get (beanname); if (singletonObject == null && allowEarlyReference) {objectFactory <?> singletonfactory = this.singletonfactory.get (beanname); if (singletonfactory! = null) {singletonobject = singletonfactory.getObject (); это. this.singletonfactory.remove (Beanname); }}} return (singletonobject! = null_object? singletonobject: null); } Каждый должен обратить внимание на этот метод, это очень важно. Мы упомянули кеш 3 -го уровня в начале, и одна из точек использования здесь. Какой это кеш 3 -го уровня? singletonObjects кэша первого уровня расположены с созданиями SingletonObjects. Второй уровень earlySingletonObjects Store Singleton Objects, которые выставлены заранее (не полностью собраны). SingletonFactories третьего уровня хранят объект объекта, который будет создан для создания экземпляра. После объяснения кеша уровня 3, давайте посмотрим на логику. В первый раз, когда я захожу в this.singletonObjects.get(beanName) возвращает NULL. Затем isSingletonCurrentlyInCreation определяет, можно ли получить данные во вторичном кэше.
public boolean issingletoncurryincreation (string beanname) {return this.singletonscurlyincreation.contains (beanname); } Будет ли включено Beanname в набор singletonsCurrentlyInCreation содержит входящее Beanname? Там нет места, чтобы установить его раньше, поэтому он определенно не включает его. Следовательно, этот метод возвращает false, и последующий процесс не останется. Метод getSingleton возвращает NULL.
Давайте посмотрим getSingleton фокус. Мы видим, что анонимный объект ObjectFactory передается. Метод GetObject называется CreateBean, реальный метод создания боба. Конечно, мы можем отложить это в сторону и продолжать смотреть на наш метод getSingleton
Public Object Getsingleton (String Beanname, ObjectFactory <?> SingletonFactory) {assert.notnull (beanname "'' Beanname 'не должно быть нулевым"); синхронизированный (this.singletonObjects) {Object singletonObject = this.singletonObjects.get (beanname); if (singletonobject == null) {if (this.singletonscurry indestruction) {бросить новое BeancreationnotallowedException (Beanname, «Создание бобов Singleton, не допускается, в то время как синглтоны этой фабрики находятся в разрушении» ( + »(не просите фасоли из фасоли в реализации« Разрушение »);»); »); } if (logger.isdebugenabled ()) {logger.debug («Создание общего экземпляра Singleton Bean '" + beanname + "'"); } beforesingletoncreation (beanname); Boolean Newsingleton = False; Boolean RecordsupressedExceptions = (this.suppressedExceptions == null); if (RecordsupressedExceptions) {this.suppressedExceptions = new LinkedHashset <execect> (); } try {singletonObject = singletonfactory.getObject (); Newsingtleton = True; } catch (allodalstateException ex) {// имеет объект Singleton, неявно появляющийся в то же время -> // Если да, продолжайте с ним, так как исключение указывает на это состояние. singletonobject = this.singletonobjects.get (beanname); if (singletonObject == null) {throw ex; }} catch (beancreationException ex) {if (recordsupressedExceptions) {for (исключение PulpressedException: this.suppressedExceptions) {ex.addrelitedCaue (suppressedException); }} бросить ex; } наконец {if (RecordsUpressedExceptions) {this.supressedExceptions = null; } effeksingletonCreation (Beanname); } if (newsingleton) {addsingleton (beanname, singletonobject); }} return (singletonObject! = null_object? singletonObject: null); }} Первое предложение этого метода Object singletonObject = this.singletonObjects.get(beanName) извлекает данные из кэша первого уровня, что определенно является нулевым. Затем вызывается метод beforeSingletonCreation .
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }} Среди них процесс добавления Beanname к набору singletonsCurrentlyInCreation . Этот набор очень важен и будет использоваться позже. Затем вызовите метод GetObject SingletonFactory, чтобы выполнить реальное процесс создания. Давайте посмотрим на реальный процесс создания, упомянутый выше createBean Основная логика внутри этого - doCreateBean .
Защищенный объект DocReateBean (Final String Beanname, Final Rootbeandefinition MBD, Final Object [] args) {// создание создания боба. BeanWrapper ExtanceWrapper = null; if (mbd.issingleton ()) {exancewrapper = this.factorybeaninstancecache.remove (beanname); } if (exancewrapper == null) {exancewrapper = createBeanInstance (beanname, mbd, args); } final Object bean = (encoswrapper! = null? exancewrapper.getWrappedInstance (): null); Class <?> Beantype = (EncanceWrapper! = Null? Exancewrapper.getWrappedClass (): null); // Позволяйте пост-обработкам изменять определение объединенного бобов. Synchronized (mbd.postprocessinglock) {if (! mbd.postprocasted) {ApplymergedbeandefinitionPostProcessors (MBD, Beantype, Beanname); mbd.postprocased = true; }} // с нетерпением Qache Singletons, чтобы иметь возможность разрешить круговые ссылки // даже при запусках интерфейсами жизненного цикла, такими как BeanFactoryAware. // беспокойство3 Boolean Ranarysingletonexposture = (mbd.issingleton () && this.allycircularReferences && issingletoncurryNureNcreation (beanname)); if (ransysingletonexposture) {if (logger.isdebugenabled ()) {logger.debug («с нетерпением ждем кэшированных бобов» " + beanname +" ', чтобы разрешить разрешение потенциальных циркулярных ссылок "); } addsingletonFactory (beanName, new ObjectFactory <Object> () {@Override public Object getObject () Throws Beansexception {return getearlybeanReference (beanname, mbd, bean);}}); } // Инициализируйте экземпляр боба. Object exposedObject = bean; try {opulatebean (beanname, mbd, exanterprapper); if (exposedObject! = null) {exposedObject = initiazebean (beanname, exposedObject, mbd); }} catch (throwable ex) {if (ex exanceof beancreationexception && beanname.equals (((beancreationexception) ex) .getbeanname ())) {throw (beancreationexception) ex; } else {бросить новое beancreationException (mbd.getresourcedescription (), beanname, «Инициализация ошибки бобов», Ex); }} if (RanachsingleTonexPosture) {Object ranssingletonReference = getsingleton (beanname, false); if (ransysingletonReference! = null) {if (exposedObject == bean) {exposedObject = ransysingletonReference; } else if (! this.AllowRawInectionDespiteWrapping && hasDependentBean (beanname)) {String [] getencebeans = getDependentBeans (beanname); SET <String> ActualDependentBeans = new LinkedHashSet <String> (upendentBeans.length); for (String -зависимый bean: upendentbeans) {if (! removesingletonifcreatedypechecececkonly (в зависимости от)) {factiondependentbeans.add (зависит от); }} if (! ActualDependentBeans.isempty ()) {Throw New BeancurlyIncreationException (BeanName, «Бин с именем» « + Beanname +» был введен в другие бобы [ + stringutils.collectiontocommadelimitdingriting (фактические подразделения). Тем не менее, другие бобы не используют окончательную версию « +» Bean. }}}}} // Зарегистрировать фасоль как одноразовый. try {RegisterDisposableBeanifnecessary (Beanname, Bean, MBD); } catch (beandefinitionValidationException ex) {бросить новое BeancreationException (mbd.getresourcedescription (), Beanname, «Инвалидные подписи разрушения», Ex); } вернуть eSposedObject; } createBeanInstance создает объект, используя отражение. Давайте посмотрим на значение атрибута в ранусе earlySingletonExposure судейству 3. Одно из суждений, isSingletonCurrentlyInCreation(beanName)
public boolean issingletoncurryincreation (string beanname) {return this.singletonscurlyincreation.contains (beanname); } Я обнаружил, что используется набор Singletonlyincreation. Beanname была заполнена в вышеуказанных шагах, поэтому его можно найти. Следовательно, свойство earlySingletonExposure определяется как верно в сочетании с другими условиями, и addSingletonFactory добавляется следующий процесс. Вот фабрика объекта, соответствующая бонусию (а). Реализация его метода GetObject достигается с помощью метода getEarlyBeanReference . Во -первых, давайте посмотрим на реализацию addsingletonfactory
Protected void AddsingletonFactory (String Beanname, ObjectFactory <?> SingletonFactory) {assert.notnull (singletonfactory, «Синглтонная фабрика не должна быть нулевой»); синхронизированный (this.singletonObjects) {if (! this.singletonObjects.containskey (beanname)) {this.singletonfactory.put (beanname, singletonfactory); это. this.Reargedsingletons.add (Beanname); }}} Хранение данных на третьем уровне кэша Singletonfactories, очистка данных кэша второго уровня на основе Beanname. Здесь есть очень важный момент, который заключается в том, чтобы установить значение в кэше третьего уровня, который является основной точкой обработки пружины круговых зависимостей. Метод getEarlyBeanReference - это реализация GetObject. Можно просто считать, что он возвращает экземпляр объекта, который заполняется A. После установки кэша уровня 3 начинается процесс заполнения свойств объекта A. В следующем описании нет подсказок исходного кода, просто краткое введение.
При заполнении A я обнаружил, что необходим боб типа B, поэтому я продолжал вызывать метод GetBean, чтобы создать его. Процесс памяти точно такой же, как и выше. Затем я пошел на процесс заполнения боба типа C, и тот же вызов Getbean (C) вызывается для выполнения. При заполнении недвижимости я позвонил в GetBean (A). Давайте продолжим отсюда, что я назвал Object sharedInstance = getSingleton(beanName), один и тот же код, но логика обработки совершенно другая.
Защищенный объект getsingleton (String beanname, boolean ablearlyreference) {Object singletonObject = this.singletonObjects.get (beanname); if (singletonobject == null && issingletoncurryincreation (beanname)) {synchronized (this.singletonobjects) {singletonobject = this.earlysingletonobjects.get (beanname); if (singletonObject == null && allowEarlyReference) {objectFactory <?> singletonfactory = this.singletonfactory.get (beanname); if (singletonfactory! = null) {singletonobject = singletonfactory.getObject (); это. this.singletonfactory.remove (Beanname); }}} return (singletonobject! = null_object? singletonobject: null); } Тем не менее, объект получен из SingletonObjects не может быть получен. Поскольку A находится в наборе singletonsCurrentlyInCreation , он входит в следующую логику и берет ее на кэш второго уровня earlySingletonObjects уровня, но все еще не был найден. Затем он находит соответствующую фабрику объекта из кэша третьего уровня singletonFactories Вызовите метод getObject , чтобы получить объект экземпляра A, который не был полностью заполнен, а затем удаляет данные кэша третьего уровня, заполняет данные кэша второго уровня и возвращает этот объект A. C зависит от заполнения экземпляра A, хотя это A неполное. Независимо от того, как заполняется C-стиль C, вы можете поместить C в Cach Cache singletonObjects и одновременно очистить данные о кэшах второго уровня и третьего уровня. В том же процессе, если C зависит от того, что B заполняется, B заполняется. Точно так же, если B зависит от A заполнена, A заполняется. Вот как Spring решает круглые ссылки.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.