Подтвердить что ты не робот

Отслеживание причины Spring "не подходит для автоматического проксирования"

Когда вы начинаете возиться с файлом Spring auto-proxy, вы часто сталкиваетесь с этим поведением, как описано:

Классы, реализующие Интерфейс BeanPostProcessor - это специальные, и поэтому они обрабатываются иначе контейнером. Все BeanPostProcessors и их непосредственно ссылка на beans будет создана при запуске, как часть специального фаза запуска ApplicationContext, то все эти BeanPostProcessors будут зарегистрированы в порядке сортировки - и применяется к все дальше beans. Поскольку АОП автоматическое проксирование реализовано как BeanPostProcessor сам, нет BeanPostProcessors или напрямую ссылки beans имеют право на автоматическое проксирование (и, следовательно, не будет аспекты "вплетены" в них.

Для любого такого bean вы должны увидеть info log message: "Bean 'foo' не является право на получение всех BeanPostProcessors (например: not для автопроксирования)".

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

Моя проблема заключается в том, что отслеживание там, где эта прямая ссылка может быть очень сложной, поскольку "прямая ссылка" может фактически быть цепочкой транзитивных зависимостей, которая заканчивается тем, что занимает половину beans в контексте приложения. Все Spring дает вам это одноинформационное сообщение, и это не очень помогает, если не сказать вам, когда bean попал в эту сеть ссылок.

Созданный BeanPostProcessor имеет прямые ссылки на другие beans, но это очень ограниченный набор ссылок. Несмотря на это, почти каждый bean в моем контексте затем исключается из автоматического проксирования в соответствии с сообщениями журнала, но я не вижу, где эта зависимость происходит.

Кто-нибудь нашел лучший способ отслеживания этого?

4b9b3361

Ответ 1

Чтобы просто закрыть этот вопрос, крах неинициализированного графа объектов был вызван BeanPostProcessor с помощью @Autowired для получения его зависимостей, а механизм autowire эффективно вызвал инициализацию каждого другого определения bean до того, как мой BeanPostProcessor получил шанс высказаться по этому вопросу. Решение - не используйте autowiring для ваших BPP...

Ответ 2

Следуйте этому рецепту:

  • Откройте BeanPostProcessorChecker в вашей среде IDE (это внутренний класс AbstractApplicationContext)
  • Установите точку останова на if (logger.isInfoEnabled()) { в методе postProcessAfterInitialization
  • Запустите свой код
  • Когда вы нажмете точку останова, найдите вызовы getBean(String,Class<T>) в трассировке стека.

    Один из этих вызовов попытается создать BeanPostProcessor. Этот bean должен быть виновником.

Фон

Представьте себе эту ситуацию:

public class FooPP implements BeanPostProcessor {
    @Autowire
    private Config config;
}

Когда Spring должен создать config (поскольку он зависит от FooPP), у него есть проблема: контракт говорит, что все BeanPostProcessor должны применяться к каждому создаваемому bean. Но когда Spring требуется config, существует хотя бы один PP (а именно FooPP), который не готов к обслуживанию!

Это становится хуже, если вы используете класс @Configuration для определения этого bean:

@Configuration
public class BadSpringConfig {
     @Lazy @Bean public Config config() { return new Config(); }
     @Lazy @Bean public FooPP fooPP() { return new FooPP(); }
}

Каждый класс конфигурации является bean. Это означает, что для создания bean factory из BadSpringConfig, Spring должен применяться постпроцессор FooPP, но для этого ему сначала требуется bean factory...

В этом примере можно разбить одну из циклических зависимостей. Вы можете сделать FooPP реализовать BeanFactoryAware, чтобы получить Spring вставить BeanFactory в почтовый процессор. Таким образом, вам не требуется автоуправление.

Позже в коде вы можете лениво попросить bean:

private LazyInit<Config> helper = new LazyInit<Config>() {

    @Override
    protected InjectionHelper computeValue() {
        return beanFactory.getBean( Config.class );
    }
};

@Override
public Object postProcessBeforeInitialization( Object bean, String beanName ) throws BeansException {
     String value = helper.get().getConfig(...);
}

(источник для LazyInit)

Чтобы разбить цикл между bean factory и пост-процессором, вам нужно настроить почтовый процессор в файле конфигурации XML. Spring может прочитать это и построить все структуры, не запутавшись.

Ответ 3

Не уверен, что это поможет, но Eclipse Spring IDE вид графика выглядит так, как будто это может быть полезно при сортировке bean ссылок..