1. Обзор
В этом руководстве мы обсудим Spring org.springframework.beans.factory.BeanCreationException.
Это очень распространенное исключение, возникающее, когда BeanFactory
создает bean-компоненты из определений bean-компонентов и сталкивается с проблемой. В этой статье будут рассмотрены наиболее распространенные причины этого исключения, а также решения.
2. Причина: org.springframework.beans.factory.NoSuchBeanDefinitionException
На сегодняшний день наиболее распространенной причиной BeanCreationException
является попытка Spring внедрить bean-компонент, который не существует в контексте.
Например, BeanA
пытается внедрить BeanB
:
@Component
public class BeanA {
@Autowired
private BeanB dependency;
...
}
Если BeanB
не найден в контексте, будет выдано следующее исключение (ошибка создания Bean):
Error creating bean with name 'beanA': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.foreach.web.BeanB cpm.foreach.web.BeanA.dependency;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.foreach.web.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)}
Чтобы диагностировать этот тип проблемы, мы сначала удостоверимся, что bean-компонент объявлен:
- либо в файле конфигурации XML с использованием элемента
<bean />
- или в классе Java
@Configuration
через аннотацию@Bean
- или аннотируется с
помощью @Component
,@Repository
,@Service
,@Controller
и сканирование classpath активно для этого пакета
Мы также проверим, действительно ли Spring подхватывает файлы конфигурации или классы и загружает их в основной контекст.
3. Причина: org.springframework.beans.factory.NoUniqueBeanDefinitionException
Другой похожей причиной исключения создания компонента является попытка Spring внедрить компонент по типу, а именно по его интерфейсу, и обнаружение двух или более компонентов, реализующих этот интерфейс в контексте.
Например, BeanB1
и BeanB2
реализуют один и тот же интерфейс:
@Component
public class BeanB1 implements IBeanB { ... }
@Component
public class BeanB2 implements IBeanB { ... }
@Component
public class BeanA {
@Autowired
private IBeanB dependency;
...
}
Это приведет к следующему исключению, выдаваемому фабрикой bean-компонентов Spring:
Error creating bean with name 'beanA': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.foreach.web.IBeanB com.foreach.web.BeanA.b;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.foreach.web.IBeanB] is defined:
expected single matching bean but found 2: beanB1,beanB2
4. Причина: org.springframework.beans.BeanInstantiationException
4.1. Пользовательское исключение
Следующим на очереди является bean-компонент, который выдает исключение в процессе своего создания. Упрощенный пример, позволяющий легко понять проблему, — создание исключения в конструкторе bean-компонента:
@Component
public class BeanA {
public BeanA() {
super();
throw new NullPointerException();
}
...
}
Как и ожидалось, это приведет к быстрому сбою Spring со следующим исключением:
Error creating bean with name 'beanA' defined in file [...BeanA.class]:
Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.foreach.web.BeanA]:
Constructor threw exception;
nested exception is java.lang.NullPointerException
4.2. java.lang.InstantiationException
Другим возможным случаем возникновения BeanInstantiationException
является определение абстрактного класса как компонента в XML; это должно быть в XML, потому что это невозможно сделать в файле Java @Configuration
, а сканирование пути к классам будет игнорировать абстрактный класс:
@Component
public abstract class BeanA implements IBeanA { ... }
Вот XML-определение bean-компонента:
<bean id="beanA" class="com.foreach.web.BeanA" />
Эта настройка приведет к аналогичному исключению:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'beanA' defined in class path resource [beansInXml.xml]:
Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.foreach.web.BeanA]:
Is it an abstract class?;
nested exception is java.lang.InstantiationException
4.3. java.lang.NoSuchMethodException
Если у bean-компонента нет конструктора по умолчанию, и Spring пытается создать его экземпляр, ища этот конструктор, это приведет к исключению во время выполнения:
@Component
public class BeanA implements IBeanA {
public BeanA(final String name) {
super();
System.out.println(name);
}
}
Когда механизм сканирования classpath обнаружит этот bean-компонент, произойдет сбой:
Error creating bean with name 'beanA' defined in file [...BeanA.class]: Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.foreach.web.BeanA]:
No default constructor found;
nested exception is java.lang.NoSuchMethodException: com.foreach.web.BeanA.<init>()
Аналогичное исключение, но его сложнее диагностировать, может возникнуть, когда зависимости Spring в пути к классам имеют разные версии. Такая несовместимость версий может привести к исключению NoSuchMethodException
из-за изменений API. Решение такой проблемы — убедиться, что все библиотеки Spring имеют одну и ту же версию в проекте.
5. Причина: org.springframework.beans.NotWritablePropertyException
Еще одна возможность заключается в определении bean-компонента BeanA
со ссылкой на другой bean -компонент BeanB
без соответствующего метода установки в BeanA
:
@Component
public class BeanA {
private IBeanB dependency;
...
}
@Component
public class BeanB implements IBeanB { ... }
Вот конфигурация Spring XML:
<bean id="beanA" class="com.foreach.web.BeanA">
<property name="beanB" ref="beanB" />
</bean>
Опять же, это может произойти только в конфигурации XML , потому что при использовании Java @Configuration
компилятор сделает невозможным воспроизведение этой проблемы.
Конечно, чтобы решить эту проблему, нам нужно добавить сеттер для IBeanB
:
@Component
public class BeanA {
private IBeanB dependency;
public void setDependency(final IBeanB dependency) {
this.dependency = dependency;
}
}
6. Причина: org.springframework.beans.factory.CannotLoadBeanClassException
Spring выдает это исключение, когда не может загрузить класс определенного bean-компонента . Это может произойти, если конфигурация Spring XML содержит компонент, у которого просто нет соответствующего класса. Например, если класс BeanZ
не существует, следующее определение приведет к исключению:
<bean id="beanZ" class="com.foreach.web.BeanZ" />
Основной причиной ClassNotFoundException
и полного исключения в этом случае является:
nested exception is org.springframework.beans.factory.BeanCreationException:
...
nested exception is org.springframework.beans.factory.CannotLoadBeanClassException:
Cannot find class [com.foreach.web.BeanZ] for bean with name 'beanZ'
defined in class path resource [beansInXml.xml];
nested exception is java.lang.ClassNotFoundException: com.foreach.web.BeanZ
7. Дети BeanCreationException
7.1. Исключение
org.springframework.beans.factory.BeanCurrentlyInCreationException ``
Одним из подклассов BeanCreationException
является BeanCurrentlyInCreationException.
Обычно это происходит при использовании внедрения конструктора, например, в случае циклических зависимостей:
@Component
public class BeanA implements IBeanA {
private IBeanB beanB;
@Autowired
public BeanA(final IBeanB beanB) {
super();
this.beanB = beanB;
}
}
@Component
public class BeanB implements IBeanB {
final IBeanA beanA;
@Autowired
public BeanB(final IBeanA beanA) {
super();
this.beanA = beanA;
}
}
Spring не сможет разрешить такой сценарий подключения, и конечным результатом будет:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'beanA':
Requested bean is currently in creation: Is there an unresolvable circular reference?
Полное исключение очень подробное:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'beanA' defined in file [...BeanA.class]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.foreach.web.IBeanB]: :
Error creating bean with name 'beanB' defined in file [...BeanB.class]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.foreach.web.IBeanA]: :
Error creating bean with name 'beanA': Requested bean is currently in creation:
Is there an unresolvable circular reference?;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'beanA':
Requested bean is currently in creation:
Is there an unresolvable circular reference?;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'beanB' defined in file [...BeanB.class]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.foreach.web.IBeanA]: :
Error creating bean with name 'beanA':
Requested bean is currently in creation:
Is there an unresolvable circular reference?;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'beanA':
Requested bean is currently in creation: Is there an unresolvable circular reference?
7.2. Исключение
org.springframework.beans.factory.BeanIsAbstractException ``
Это исключение создания экземпляра может возникнуть, когда фабрика компонентов пытается получить и создать экземпляр компонента, который был объявлен как абстрактный:
public abstract class BeanA implements IBeanA {
...
}
Мы объявляем это в конфигурации XML как:
<bean id="beanA" abstract="true" class="com.foreach.web.BeanA" />
Если мы попытаемся получить BeanA
из контекста Spring по имени, например, при создании экземпляра другого компонента:
@Configuration
public class Config {
@Autowired
BeanFactory beanFactory;
@Bean
public BeanB beanB() {
beanFactory.getBean("beanA");
return new BeanB();
}
}
Это приведет к следующему исключению:
org.springframework.beans.factory.BeanIsAbstractException:
Error creating bean with name 'beanA': Bean definition is abstract
И полная трассировка стека исключений:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'beanB' defined in class path resource
[org/foreach/spring/config/WebConfig.class]: Instantiation of bean failed;
nested exception is org.springframework.beans.factory.BeanDefinitionStoreException:
Factory method
[public com.foreach.web.BeanB com.foreach.spring.config.WebConfig.beanB()] threw exception;
nested exception is org.springframework.beans.factory.BeanIsAbstractException:
Error creating bean with name 'beanA': Bean definition is abstract
8. Заключение
В этой статье мы узнали, как ориентироваться в различных причинах и проблемах, которые могут привести к BeanCreationException
в Spring, а также получили хорошее представление о том, как исправить все эти проблемы.
Реализацию всех примеров исключений можно найти в проекте на github . Это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.