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

StackOverflow https://stackoverflow.com/questions/1201726

  •  05-07-2019
  •  | 
  •  

Вопрос

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

Классы, которые реализуют интерфейс BeanpostProcessor, являются особенными, и поэтому они по -разному обрабатываются контейнером.Все Beanpostprocessors и их непосредственно ссылаемые бобы будут создаваться на стартапе, как часть специальной фазы запуска ApplicationContext, тогда все эти Beanpostprocessors будут зарегистрированы в сортированном виде - и применяться ко всем дальнейшим бобам.Поскольку AOP Автопроксимирование реализуется в качестве самого бобовогопроцессора, ни один из бобовых процессоров или непосредственно упоминаемых бобов не имеет права на автопроксимирование (и, следовательно, не будут иметь в них аспекты.

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

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

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

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

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

Это было полезно?

Решение 2

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

Другие советы

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

  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 должен применяться к каждому создаваемому компоненту.Но когда весна нуждается config, существует хотя бы один ПП (а именно FooPP), который не готов к эксплуатации!

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

@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 может прочитать это и построить все структуры, не запутавшись.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top