Пример пружинного кругового примера

У меня есть круговая ссылка в одном из моих проектов на работе с использованием 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();
    }
}

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

Изменить: я исправил проблему с помощью javax.inject.Provider. Единственной другой разницей в двух проектах были аннотации: javax.inject.Inject и javax.annotation.ManagedBean вместо @Autowired и @Component.

Ответ 1

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

Из одного номера весной-Жира:

@Lazy-аннотация, которая может использоваться в сочетании с @Configuration, чтобы указать, что все бобы в этом классе конфигурации должны быть лениво инициализированы. Конечно, @Lazy может также использоваться в сочетании с отдельными методами @Bean для обозначения ленивой инициализации по отдельности. 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();
    }
}

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

Ответ 3

Согласно документации Spring, можно получить проблему зависимости Circular или BeanCurrentlyInCreationException, используя инъекцию конструктора.

Решение проблемы заключается в использовании сеттеров вместо инсталляции конструктора.

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

Ответ 4

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

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

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