Автор оригинала: Eugen Paraschiv.
1. Обзор
В этой статье мы обсуждаем Spring org.springframework.beans.factory.NoSuchBeanDefinitionException – это обычное исключение, создаваемое BeanFactory при попытке разрешить компонент, который просто не определен в контексте Spring.
Мы проиллюстрируем возможные причины этой проблемы и доступные решения.
И, конечно, исключения случаются, когда вы меньше всего их ожидаете; посмотрите полный список исключений и решений весной .
Дальнейшее чтение:
Учебник по весенним исключениям
Весеннее BeanCreationException
2. Причина: Нет квалифицирующего компонента типа […] Найдено для зависимости
Наиболее распространенной причиной этого исключения является просто попытка ввести компонент, который не определен. Например – BeanB подключается к соавтору – BeanA:
@Component public class BeanA { @Autowired private BeanB dependency; //... }
Теперь, если зависимость – BeanB – не определена в контексте Spring, процесс начальной загрузки завершится неудачей с исключением определения такого компонента/|:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.BeanB] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Причина четко указана весной: ” ожидается, что по крайней мере 1 компонент, который квалифицируется как кандидат autowire для этой зависимости “
Одна из причин , по которой BeanB может не существовать в контексте – если бобы автоматически выбираются сканированием classpath и если BeanB правильно аннотирован как боб ( @Component , @Repository , @Service , @Controller и т. Д.), – заключается в том, что он может быть определен в пакете, который не сканируется Spring :
package com.baeldung.packageB; @Component public class BeanB { ...}
В то время как сканирование путей к классам может быть настроено следующим образом:
@Configuration @ComponentScan("com.baeldung.packageA") public class ContextWithJavaConfig { ... }
Если бобы не сканируются автоматически с помощью , определенного вручную , то BeanB просто не определен в текущем контексте Spring.
3. Причина: Поле […] в […] Требуется компонент типа […] Этого Не Удалось Найти
В приложении Spring Boot для описанного выше сценария мы получаем другое сообщение.
Давайте возьмем тот же пример, где Bean подключен к Beans , но он не определен:
@Component public class BeanA { @Autowired private BeanB dependency; //... }
Если мы попытаемся запустить это простое приложение, которое попытается загрузить Beans :
@SpringBootApplication public class NoSuchBeanDefinitionDemoApp { public static void main(String[] args) { SpringApplication.run(NoSuchBeanDefinitionDemoApp.class, args); } }
Приложение не запустится с сообщением об ошибке:
*************************** APPLICATION FAILED TO START *************************** Description: Field dependency in com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA required a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' that could not be found. Action: Consider defining a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' in your configuration.
Здесь com.baeldung.spring boot mvc.nosuchbeandefinitionexception является пакетом для BeanA , BeanB и NoSuchBeanDefinitionDemoApp .
Фрагмент кода для этого примера можно найти в этом проекте Github.
4. Причина: Нет квалифицирующего боба типа […] Определяется
Другой причиной исключения является существование двух определений компонентов в контексте вместо одного. Например, если интерфейс – IBeanB реализован двумя компонентами – BeanB1 и BeanB2 :
@Component public class BeanB1 implements IBeanB { // } @Component public class BeanB2 implements IBeanB { // }
Теперь, если Bean автоматически подключит этот интерфейс, Spring не будет знать, какую из двух реализаций внедрить:
@Component public class BeanA { @Autowired private IBeanB dependency; ... }
И снова это приведет к тому, что NoSuchBeanDefinitionException будет вызвано BeanFactory :
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: expected single matching bean but found 2: beanB1,beanB2
Аналогично, Spring четко указывает причину сбоя проводки: “ожидался один соответствующий боб, но найдено 2” .
Обратите внимание, однако, что в этом случае создается точное исключение не NoSuchBeanDefinitionException , а подкласс – исключение NoUniqueBeanDefinitionException . Это новое исключение было введено весной 3.2.1 именно по этой причине – чтобы провести различие между причиной , по которой не было найдено определение компонента, и этой причиной, по которой в контексте найдено несколько определений.
До этого изменения исключение, приведенное выше, было:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: expected single matching bean but found 2: beanB1,beanB2
Одним из решений этой проблемы является использование @квалификатора аннотации для точного указания имени компонента, который мы хотим передать:
@Component public class BeanA { @Autowired @Qualifier("beanB2") private IBeanB dependency; ... }
Теперь у Spring достаточно информации, чтобы принять решение о том, какой боб вводить – BeanB1 или BeanB2 (имя по умолчанию BeanB2 – beanB2 ).
5. Причина: Боб Не назван […] Определяется
Исключение NoSuchBeanDefinitionException также может быть вызвано, когда компонент, который не определен, запрашивается по имени из контекста Spring:
@Component public class BeanA implements InitializingBean { @Autowired private ApplicationContext context; @Override public void afterPropertiesSet() { context.getBean("someBeanName"); } }
В этом случае нет определения компонента для “someBeanName”, что приводит к следующему исключению:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'someBeanName' is defined
Опять же, Spring четко и лаконично указывает причину сбоя: ” Не определен боб с именем X “.
6. Причина: Проксированные бобы
Когда компонент в контексте проксируется с помощью механизма динамического прокси JDK, то прокси не будет расширять целевой компонент (однако он будет реализовывать те же интерфейсы).
Из-за этого, если боб вводится интерфейсом, он будет правильно подключен. Однако если компонент вводится фактическим классом, то Spring не найдет определение компонента, соответствующее классу, поскольку прокси – сервер фактически не расширяет класс.
Очень распространенной причиной, по которой боб может быть проксирован, является поддержка транзакций Spring , а именно бобы, аннотированные @Transactional .
Например, если Service вводит Service , и обе службы являются транзакционными, ввод по определению класса не будет работать:
@Service @Transactional public class ServiceA implements IServiceA{ @Autowired private ServiceB serviceB; ... } @Service @Transactional public class ServiceB implements IServiceB{ ... }
Те же две службы, на этот раз правильно вводимые интерфейсом , будут в порядке:
@Service @Transactional public class ServiceA implements IServiceA{ @Autowired private IServiceB serviceB; ... } @Service @Transactional public class ServiceB implements IServiceB{ ... }
7. Заключение
В этом учебном пособии рассматриваются примеры возможных причин для общего NoSuchBeanDefinitionException – с акцентом на том, как устранить эти исключения на практике.
Примеры реализации всех этих исключений можно найти в проекте GitHub – это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.
Наконец, полный список исключений и решений весной может стать хорошим ресурсом для закладки.