1. Предисловие
Мы знаем, что пружина может быть лень загружать, то есть экземпляры бобов, когда он фактически используется. Конечно, это не так. Например, настройка свойства Lazy-Init Bean может управлять временем загрузки пружины. Теперь производительность, память и т. Д. Машины относительно высоки и в основном не используют ленивую нагрузку. Бин загружается в начале контейнера, а время запуска немного длиннее. Таким образом, когда бобы фактически получают для делового использования, много бремени может быть уменьшено. Это будет проанализировано позже. Когда мы используем бобы, наиболее прямым способом является получение их из Factroy, которая является источником загрузки экземпляров бобов.
Недавно я столкнулся с странной проблемой при работе над проектами, то есть точность инъекции зависимости от бобов связана с порядком прямой инъекции бобов, но при нормальных обстоятельствах это не имеет ничего общего с порядком. Если вы спешите, позвольте мне рассказать вам один за другим.
2. Обычная циклическая зависимость бобов-не связан с приказом об инъекции
2.1 Примеры круговой зависимости и принципы
открытый класс Beana {Private Beanb Beanb; Public Beanb getbeanb () {return beanb;} public void setbeanb (beanb beanb) {this.beanb = beanb;}} открытый класс Beanb {Private Beana Beana; Public Beana getbeana () {return beana;} public void setbeana (beana beana) {this.beana = beana;}}<bean id = "beana"> <name = "beanb"> <ref bean = "beanb"/> </property> </bean>
<bean id = "beanb"> <name = "beana"> <ref bean = "beana"/> </property> </bean>
Вышеупомянутая инъекция круговой зависимости работает обычно, потому что пружина обеспечивает раннюю функцию BeanReference. Во -первых, весна есть параллельная карта под названием SingletonObjects для хранения всех созданных и инициализированных бобов, в то время как SingletonFactories используется для хранения информации о бобах (Beanname и фабрики обратного вызова), которую необходимо решить. При создании Beana, getBean(“beanA”); Во -первых, посмотрите, есть ли Beana в SingletonObjects, она вернется:
(1)
Object sharedinstance = getsingleton (beanname); // getsingleton (beanname, true); if (sharedinstance! = Null && args == null) {if (logger.isdebugenabled ()) {if (issingletoncurrlyIncreation (beanname) {logger.debugugrally egerly egerly egerly egerly egerlyncreation (beanname)) « + Beanname +», который еще не полностью инициализирован - следствие круговой ссылки »); } else {logger.debug ("возвращающий кэшированный экземпляр синглтонского бона '" + beanname + "'"); }} // Если это обычный бон, он возвращает sharedinstance.getobject (); bean = getObjectforbeanInstance (sharedinstance, имя, beanname, null);} Защищенный объект getsingleton (String beanname, boolean ablearlyreference) {Object singletonObject = this.singletonObjects.get (beanname); if (singletonObject == null) {synchronized (this.singletonObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && allowEarlyReference) {objectFactory singletonFactory = (objectFactory) this.singletonfactory.get (beanname); if (singletonfactory! = null) {singletonobject = singletonfactory.getObject (); это. this.singletonfactory.remove (Beanname); }}} return (singletonobject! = null_object? SingletonObject: null);} Вначале, определенно нет Beana, поэтому, если allowCircularReferences=true установлен (по умолчанию верно), а текущий бон является однонадельным, и в настоящее время создается фасоль, а затем перед инициализацией атрибута поместите информацию о бобах в однокомнатные карты SingletonFactories: перед инициализацией атрибута.
(2)
Boolean RangeSingleToneXposture = (mbd.issingleton () && this.allowcircularReferences && issingletoncurryNuriation (Beanname));
if (RanachsingleTonexposture) {if (logger.isdebugenabled ()) {logger.debug ("Эгояло кэширующий бон '" + beanname + "' 'для разрешения потенциальных циркулярных ссылок");} addsingletonfactor GetearlybeanReference (Beanname, MBD, Bean); Protected void AddsingletonFactory (String Beanname, ObjectFactory SingletonFactory) {assert.notnull (singletonfactory, "Singleton Factory не должна быть нулевой"); синхронизированный (this.singletonobjects) {if (! this.singletonobjects.containskey (beanname) {if.sistony., beannamepuse., beannamepuse.pactory. singletonfactory); это. this.Reargedsingletons.add (Beanname); }}} Затем введите Beanb в атрибут экземпляра. При введении атрибута getBean(“beanB”) и обнаружите, что Beanb не находится в SingletonObjects, он создаст экземпляр Beanb, затем положит Singletonfactories, затем вводит Beana, а затем запустит getBean(“beanA”); В настоящее время Гетрингтон вернет создательную Бина. После того, как Beanb будет инициализирован, добавьте Beanb в SingletonObjects, а затем возвращайтесь, затем инициализируется Beana, добавьте Beana в SingletonObjects и затем возвращайте
2.2 Переключатели, которые позволяют зависимостям петли
открытый класс testcircle2 {private final State ClassPathxMlapplicationContext ModuleContext; Private Static Test Test; Static {moduleContext = new ClassPathxMlApplicationContext (new String [] {"Beans-circile.xml"}); modulecontext.setAllowcircularReferences (false); test = (test) modulecontext.getbean ("test");} public static void main (string [] args) {System.out.println (test.name);}}В классе ClassPathXmlApplicationContext есть свойство разрешений, чтобы контролировать, разрешено ли круговые зависимости быть правдой по умолчанию. После того, как он установил его на false, обнаружено, что круглые зависимости все еще могут работать нормально. Посмотрите на исходный код:
public classpathxmlapplicationcontext (String [] configlocations) Throws Beansexception {this (configlocations, true, null);} public classpathxmlapplicationcontext (string [] configlocations, boolean refresh, applicatecontext parent) throws beansexception {super (parent); setConfiglocations (configlocations); if (rebresh) {refresh ();}} public classpathxmlapplicationcontext (string [] configlocations, boolean refresh, applicatecontext parent) throws beansexception {super (parent); setConfiglocations (configlocations); if (rebresh) {refresh ();}} Знайте, что контейнер будет обновлен, когда ClassPathXmlApplicationContext будет по умолчанию.
Метод обновления будет называть обновленным фактором:
Защищенный final void refreshbeanfactory () бросает Beansexception {if (hasbeanFactory ()) {destroyBeans (); CloseBeanFactory ();} try {// Создать фабрику фабрики deffliebableBeanFactory beanFactory = createBeanFactory (); // Настроить свойства фабрики фабрики настройки custombeanfactory (beanfactory); LoadBeandefinitions (BeanFactory); синхронизированный (this.beanfactorymonitor) {this.beanfactory = beanfactory; }} catch (ioException ex) {throw new ApplicationContexTextexception ("IN/O Дизайн xml Document для контекста приложения [" + getDisplayName () + "]", ex);}} Protected void CommandizeBeanFactory (по умолчанию stistableBeanFactory BeanFactory) {if (this.AllowBeanDefinitionOverriding! = null) {beanfactory.setAllowBeanDefinitionOverriding (this.allowbeanDefinitionOverriding.booleAnvalue ();} if (this.allowcirlences! beanfactory.setallowcircularReferences (this.allowcircularReferences.booleAnvalue ());}} Здесь вы узнаете, что прежде чем мы вызовуте moduleContext.setAllowCircularReferences(false) , был выполнен InformizeBeanfactory of CustomizeBeanfactory, оставленную пружиной. Последняя причина заключается в том, что перед вызовом настройки фабрика фабрики обновляется, поэтому тестовый код изменяется на:
открытый класс testcircle {private final static classpathxmlapplication context modulecontext; частный статический тест-тест; static {// инициализировать контекст контейнера, но не обновляйте контейнер modulecontext = new classpathxmlapplicationcontext (new String [] {"beans-circile.xml"}, false); modulecontext.setAllowcircularReferences (false); // обновить контейнер modulecontext.refresh (); test = (test) modulecontext.getbean ("test");} public static void main (string [] args) {System.out.println (test.name);}}Теперь тест сделает исключение:
Вызвано: org.springframework.beans.factory.beancreationException: Ошибка создания боба с именем «Beana», определенной в ресурсе класса [Beans-circile.xml]: не может разрешить ссылку на бобовый «Beanb», когда устанавливает собственность бобов «beanb»; Вложенное исключение-org.springframework.beans.factory.beancreationException: Ошибка создания боба с именем «Beanb», определенной в ресурсе класса [Beans-circile.xml]: не может разрешить ссылку на Bean «Beana», когда устанавливает собственность бобов «Beana»; Вложенное исключение - org.springframework.beans.factory.beancurlyIncreationException: Ошибка создания боба с именем «Beana»: Запрашиваемый Bean в настоящее время находится в создании: есть ли неразрешимая круговая ссылка?
3. Заводские бобы и обычные бобы Циклические зависимости - связанные с приказом об инъекции
3.1 Тестовый код
Фабрика бобов
Общедоступный класс MyFactoryBean реализует FactoryBean, инициализация Bean {Private String name; частный тест Test; public String getName () {return name;} public void setName (String name) {this.name = name;} public DependentBeanbean getDepentBean () {return visendentbean;} public void setDepentBean (dependentbean {this this This This This This This This ThisePendEnbean). Зависимость System.out.println ("name:" + this.name); тест = новый тест (); test.name = dependentbean.dosomething () + this.name;}} Для простоты просто напишите общественную переменную
Общественный тест класса {public String name;} открытый класс DevendentBean {public String dosomething () {return "hello:";}@test test autowiredprivate;} конфигурация XML
<bean id = "test"> <name = "dependentbean"> <bean> </bean> </property> <name = "name =" name "value =" zlx "> </property> </bean>
Функция Factory Bean MyFactoryBean - это завершение тестового класса. Сначала установите свойства для MyFactoryBean, затем создайте тестовый экземпляр в методе MyFactoryBean и установите свойства. Сменьшаясь MyFactoryBean в конечном итоге вызовет метод GetObject, чтобы вернуть созданный тестовый объект. Здесь MyFactoryBean зависит от Depentbean, а сами зависит от самого зависимости, так что это круговая зависимость
тест:
открытый класс testcircle2 {private final State ClassPathxMlapplicationContext ModuleContext; Private Static Test Test; Static {moduleContext = new ClassPathxMlApplicationContext (new String [] {"Beans-circile.xml"}); test = (test) modulecontext.getbean ("test");} public static void main (string [] args) {System.out.println (test.name);}}результат:
Вызвано: org.springframework.beans.factory.beancreationException: Ошибка Создание боба с именем 'com.alibaba.test.circle.pectentionbean#1C701A27': автоматическое использование полей; Вложенное исключение - org.springframework.beans.factory.beancreationexception: не удалось. Вложенное исключение - org.springframework.beans.factory.beancurlyIncreationException: Ошибка создания боба с именем «Тест»: FactoryBean, который в настоящее время находится в создании.
3.2 Анализ причин
При создании тестирования getBean(“test”) будет запускается, и он увидит, существует ли текущий боб
Если его не существует, создайте экземпляр теста. После создания текущая информация о бобах будет размещена на карте однокурсников SingletonFactories.
Затем введите атрибут зависимый подразделение в экземпляр. Когда используется инъекция атрибута, будет использоваться getBean(“depentBean”) .
Если вы обнаружите, что зависимости не существует, вы создадите экземпляры «Зависимость», а затем поместите его в Singletonfactories.
Затем на автоматическом инъекционном тесте, а затем getBean(“test”); В настоящее время (1) Гетрингтон возвращает экземплярный тест. Поскольку тест является фабричным бобом, return test.getObject();
MyFactoryBean's Afterpropertiesset еще не был вызван, поэтому test.getObject() возвращает NULL.
Ниже приведены следующий процесс создания Bean Bean:
getBean ()-> Создать экземпляр-> AutoWireD-> SET Property-> AfterProperTiesset
То есть вызов метода getObject был вызван ранее, чем метод Afterpropertiesset.
Затем давайте изменим MyFactoryBean, чтобы быть следующим:
public Object getObject () Throws Exception {// TODO Auto Generated Method Stubif (null == test) {Afterpropertiesset ();} return Test;} public void AfterProperTiesset () Throws Exception {if (null == test) {System.out.println ("name:" + this.name); тест = новый тест (); test.name = dependentbean.dosomething () + this.name;}} То есть, если вы судите в сначала в GetObject, лучше test==null Затем вызовите AfterPropertiesset, а затем, если test==null создает тестовый экземпляр в AfterPropertiesset, он выглядит хорошо, и я действительно хочу решить нашу проблему. Но на самом деле, это все еще не работает, потому что Afterpropertiesset использует иждивенную часть внутренне, и в это время depentBean=null .
3.3 думать о том, как это решить
3.2 Причина анализа заключается в том, что MyFactoryBean была впервые создана, и депутата была создана в процессе создания MyFactoryBean. При создании депутаты требуется экземпляр MyFactoryBean Autowired MyFactoryBean. Затем метод getObject вызывается перед вызовом Afterpropertiesset, поэтому нулевой возвращается.
Так что, если вы сначала создаете депутату, а затем создадите MyFactoryBean? Следующий анализ сделан:
Во -первых, Depentbean будет создан и добавлен в Singletonfactories
Экземпляр Depentbean будет автоматическим тестом, поэтому в первую очередь будет создан экземпляр тестового тестирования.
Создайте экземпляр испытаний, а затем присоединяйтесь к SingletonFactories
Тестовый экземпляр будет вводить экземпляр Depentbean в атрибутах, так что он будет getBean(“depentBean”);
getBean(“depentBean”) обнаруживает, что в SingletonFactories уже есть зависимость и возвращает объект «Зависимый» объект
Поскольку зависимость не является фабричным бобом, он непосредственно возвращает иждивенную часть
Тестовый экземпляр будет успешно вводится в экземпляр Depentbean, инициализация экземпляра тестирования OK
Экземпляр для экземпляра для экземпляра Depentbean
Согласно этому анализу, можно сначала создать депутатую, а затем создать мгновенность MyFactoryBean. Изменить XML на следующее:
<bean id = "dependentbean"> </bean> <bean id = "test"> <name = "dependentbean"> <ref bean = "dependentbean"/> </propetion> <name = "name" value = "zlx"> </property> </bean>
Результаты тестового прогона:
Имя: Zlx
Привет: Zlx
Если это действительно в порядке, то в соответствии с этим анализом, если приведенная выше конфигурация XML регулирована, она определенно допустит ошибку, поскольку тест был создан раньше, чем зависимость, и это верно после теста. Кроме того, можно себе представить, что, когда фабричный боб полагается на фабричный боб, он неизбежно пройдет независимо от порядка декларации.
3.3 мысль
Вышеуказанное сначала вводит зависимость, которую необходимо использовать в MyFactoryBean, а затем вводит MyFactorybean, и проблема решается. Так что, если вам нужно использовать созданный объект с id = "test" в другой бобе, как должен быть введен этот боб?
Будет ли это успешным аналогичным образом? Оставьте это для всех, чтобы подумать ^^
открытый класс useTest {@autowiredPrivate тест теста;}<bean id = "usetest"> </bean> <bean id = "dependentbean"> </bean> <bean id = "test"> <name = "dependentbean"> <ref bean = "devendentbean"/> </propetion> <name = "name" value = "zlx"> </propetion> </bean>
4. Резюме
Когда обычные бобы взаимозависимы, порядок инъекции бобов не связан, но когда заводские бобы и обычные бобы взаимозависимы, обычные бобы должны быть созданы в первую очередь. Это из -за специфики фабричных бобов, то есть он имеет метод getObject.
Хорошо, вышеупомянутое содержимое этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.