Spring circular reference example

у меня есть циклическая ссылка в одном из моих проектов на работе с использованием spring, который я не могу исправить, и не удается со следующей ошибкой при запуске:

'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference?

Я попытался воссоздать ту же проблему на меньшем уровне в образце проекта (без всех деталей моего рабочего проекта). Однако я не смог придумать правдоподобный сценарий, в котором весна терпит неудачу с ошибкой. Вот что у меня есть:

public class ClassA {
    @Autowired
    ClassB classB;
}

public class ClassB {
    @Autowired
    ClassC classC;
}

@Component
public class ClassC {
    @Autowired
    ClassA classA;
}

@Configuration
public class Config {
    @Bean
    public ClassA classA() {
        return new ClassA();
    }

    @Bean
    public ClassB classB() {
        return new ClassB();
    }
}

у меня есть аналогичный сценарий в мой проект, который терпит неудачу, и я ожидал, что весна также пожалуется в моем образце проекта. Но это работает отлично! Может ли кто-нибудь дать мне простой пример того, как сломать пружину с круговой опорной ошибкой?

Edit: я исправил проблему с помощью javax.впрыскивать.Поставщик. Единственным другим отличием в 2 проектах были аннотации, используемые javax.впрыскивать.Вкачать и javax.аннотация.ManagedBean вместо @Autowired и @Component.

4 ответов


Это старая тема, так что я думаю, вы почти забыли о проблеме, но я хочу, чтобы вы знали о тайне. Я столкнулся с той же проблемой, и моя не исчезла волшебным образом, поэтому я должен был решить проблему. Я буду решать ваши вопросы шаг за шагом.

1. Почему вы не смогли воспроизвести исключение круговой ссылки?

, потому что Весна заботится об этом. Он создает фасоли и впрыскивает их как требуется.

2. Тогда почему ваш проект создает исключение?

  • как сказал @sperumal, Spring может создать круговое исключение, если вы используете инъекцию конструктора
  • согласно журналу, вы используете Spring Security в своем проекте
  • в конфигурации безопасности Spring они используют инъекцию конструктора
  • ваши бобы, которые впрыскивает authenticationManager имел круговой ссылка

3. Тогда почему исключение исчезло мистически?

исключение может произойти или не произойти, зависит от порядка создания бобов. Я думаю, вы сделали несколько *context.xml файлы или около того, и загрузите их с конфигурацией что-то вроде ниже в интернете.в XML

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:*-context.xml</param-value>
</context-param>

xml-файлы будут загружены XmlWebApplicationContext класс и порядок загрузки файлов не гарантируется. Он просто загружает файлы из файловой системы. Проблема здесь. Есть нет проблем, если класс сначала загружает файл контекста приложения, потому что ваши бобы уже созданы, когда они используются для инъекции конструкции Spring Security. Но если он сначала загружает файл контекста безопасности Spring, возникает проблема круговой ссылки, потому что Spring пытается использовать ваши бобы в инъекции конструктора до их создания.

4. Как решить проблему?

Force порядок загрузки xml-файлов. В моем в случае, я загрузил XML-файл контекста безопасности в конце файла контекста приложения, используя <import resource="">. Порядок загрузки может быть изменен в зависимости от среды даже с тем же кодом, поэтому я рекомендую установить порядок для устранения потенциальных проблем.


вы могли бы использовать @Lazy чтобы указать, что Боб лениво создан, нарушая нетерпеливый цикл автозапуска.

идея в том, что какой-то боб в цикле может быть создан как прокси, и как раз в тот момент, когда он действительно нужен, он будет инициализирован. Это означает, что инициализируются все бобы, кроме того, который является прокси. Использование его в первый раз вызовет конфигурацию, и поскольку другие компоненты уже настроены, это не будет проблемой.

от один выпуск весной-Jira:

@Lazy аннотация, которая может использоваться в сочетании с @Configuration чтобы указать, что все бобы в этом классе конфигурации должны быть лениво инициализирован. Конечно, @Lazy также может использоваться в сочетании с отдельными методами @Bean для указания ленивой инициализации на a один-на-один основе. https://jira.springsource.org/browse/SJC-263

Это означает, что аннотирование вашего bean как @Lazy будет хватить. Или, если вы предпочитаете просто аннотировать класс конфигурации как @Lazy следующим образом:

@Configuration
@Lazy
public class Config {
    @Bean
    public ClassA classA() {
        return new ClassA();
    }

    @Bean
    public ClassB classB() {
        return new ClassB();
    }
}

если вы реализуете интерфейс ваших бобов это будет работать достаточно хорошо.


согласно документации весны, возможно получить круговую проблему зависимости или BeanCurrentlyInCreationException с помощью конструктор инъекций.

решение решить проблему-использовать сеттеры вместо впрыска конструктор.

ссылка http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html.


некоторые чтения по этому вопросу:

http://blog.jdevelop.eu/?p=382

такие круговые зависимости не круты и должны быть исключены, когда это возможно