Перейти к основному содержимому

Исключение Spring BeanCreationException

· 7 мин. чтения

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, поэтому его легко импортировать и запускать как есть.