Отслеживание причины Spring "не имеет права на авто-проксирование" - PullRequest
40 голосов
/ 29 июля 2009

Когда вы начинаете возиться с авто-прокси Spring, вы часто сталкиваетесь с этим, как описано в документации:

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

Для любого такого боба вы должны увидеть сообщение в журнале информации: «Bean« foo »не является право на получение обработки всеми BeanPostProcessors (например: не право на авто-проксирование) ».

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

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

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

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

Ответы [ 3 ]

29 голосов
/ 30 октября 2013

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

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

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

Фон

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

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

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

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

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

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

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

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

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 )

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

20 голосов
/ 06 сентября 2009

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

4 голосов
/ 02 августа 2009

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

...