Primavera NoSuchBeanDefinitionException
*1. Visão geral *
Neste artigo, estamos discutindo o* Spring org.springframework.beans.factory.NoSuchBeanDefinitionException - essa é uma exceção comum lançada pelo BeanFactory ao tentar resolver um bean que simplesmente não está definido *no contexto de primavera.
Ilustraremos as possíveis causas para esse problema e as soluções disponíveis.
E, é claro, as exceções acontecem quando você menos as espera; dê uma olhada no link:/spring-exceptions [a lista completa de exceções e soluções no Spring].
Leitura adicional:
https://www..com/spring-exceptions [Tutorial de exceções da Primavera]
Algumas das exceções mais comuns no Spring com exemplos - por que elas ocorrem e como resolvê-las rapidamente.
https://www..com/spring-exceptions [Leia mais] →
https://www..com/spring-beancreationexception [Spring BeanCreationException]
Um guia rápido e prático para lidar com diferentes causas do Spring BeanCreationException
https://www..com/spring-beancreationexception [Leia mais] →
===* 2. Causa: Nenhum Bean Qualificado do Tipo […] Encontrado para Dependência *
A causa mais comum dessa exceção é simplesmente tentar injetar um bean que não está definido. Por exemplo - BeanB está conectando um colaborador - _BeanA: _
@Component
public class BeanA {
@Autowired
private BeanB dependency;
//...
}
Agora, se a dependência - BeanB - não estiver definida no Contexto Spring, o processo de inicialização falhará com* a exceção de definição de bean *:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [org..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)}
O motivo é claramente indicado pelo Spring: "expected pelo menos 1 bean que se qualifica como candidato a fio automático para essa dependência"
Um motivo pelo qual BeanB pode não existir no contexto - se os beans forem selecionados automaticamente pela varredura do caminho de classe e se BeanB for anotado corretamente como um bean (_ @ Component_, _ @ Repository_, _ @ Service_, _ @ Controller_, etc) - é que ele pode ser definido em um pacote que não é verificado pelo Spring :
package org..packageB;
@Component
public class BeanB { ...}
Enquanto a verificação do caminho de classe pode ser configurada da seguinte maneira:
@Configuration
@ComponentScan("org..packageA")
public class ContextWithJavaConfig {
...
}
Se os beans não forem automaticamente verificados por definidos manualmente , BeanB simplesmente não será definido no contexto atual do Spring.
*3. Causa: O campo […] em […] exigia um bean do tipo […] que não pôde ser encontrado *
Em um aplicativo Spring Boot para o cenário acima, recebemos uma mensagem diferente.
Vamos dar o mesmo exemplo em que BeanB está conectado em BeanA, mas não está definido:
@Component
public class BeanA {
@Autowired
private BeanB dependency;
//...
}
Se tentarmos executar este aplicativo simples, ele tentará carregar BeanA:
@SpringBootApplication
public class NoSuchBeanDefinitionDemoApp {
public static void main(String[] args) {
SpringApplication.run(NoSuchBeanDefinitionDemoApp.class, args);
}
}
O aplicativo falhará ao iniciar com a mensagem de erro:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field dependency in com..springbootmvc.nosuchbeandefinitionexception.BeanA required a bean of type 'com..springbootmvc.nosuchbeandefinitionexception.BeanB' that could not be found.
Action:
Consider defining a bean of type 'com..springbootmvc.nosuchbeandefinitionexception.BeanB' in your configuration.
Aqui, com..springbootmvc.nosuchbeandefinitionexception é o pacote para BeanA, BeanB e NoSuchBeanDefinitionDemoApp.
O trecho de código deste exemplo pode ser encontrado em este projeto do Github.
*4. Causa: nenhum bean qualificado do tipo […] está definido *
Outra causa para a exceção é a existência de duas definições de bean no contexto, em vez de uma. Por exemplo, se uma interface - IBeanB for implementada por dois beans - BeanB1 e BeanB2:
@Component
public class BeanB1 implements IBeanB {
//
}
@Component
public class BeanB2 implements IBeanB {
//
}
Agora, se BeanA autoriza esta interface, o Spring não saberá qual das duas implementações injetar:
@Component
public class BeanA {
@Autowired
private IBeanB dependency;
...
}
E, novamente, isso resultará em um NoSuchBeanDefinitionException sendo lançado pelo BeanFactory:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type
[org..packageB.IBeanB] is defined:
expected single matching bean but found 2: beanB1,beanB2
Da mesma forma, o Spring indica claramente o motivo da falha na fiação: _ “bean de correspondência única esperado, mas encontrado 2” _.
Observe, no entanto, que, nesse caso, a exceção exata lançada não é NoSuchBeanDefinitionException, mas uma subclasse -* the NoUniqueBeanDefinitionException *. Essa nova exceção foi introduced in Spring 3.2.1, exatamente por esse motivo - para diferenciar entre a causa em que nenhuma definição de bean foi encontrada e esta - em que várias definições são encontradas no contexto.
Antes dessa alteração, a exceção acima era:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [org..packageB.IBeanB] is defined:
expected single matching bean but found 2: beanB1,beanB2
Uma solução para esse problema é usar a anotação _ @ Qualifier_ para especificar exatamente o nome do bean que queremos conectar:
@Component
public class BeanA {
@Autowired
@Qualifier("beanB2")
private IBeanB dependency;
...
}
Agora o Spring possui informações suficientes para tomar a decisão de qual bean injetar - BeanB1 ou BeanB2 (o nome padrão de BeanB2 é beanB2).
*5. Causa: nenhum bean nomeado […] está definido *
Um NoSuchBeanDefinitionException também pode ser lançado quando um bean não definido é* solicitado pelo nome *no contexto do Spring:
@Component
public class BeanA implements InitializingBean {
@Autowired
private ApplicationContext context;
@Override
public void afterPropertiesSet() {
context.getBean("someBeanName");
}
}
Nesse caso, não há definição de bean para "someBeanName" - levando à seguinte exceção:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'someBeanName' is defined
Novamente, o Spring indica clara e concisamente o motivo da falha: "_ Nenhum bean chamado X está definido_".
===* 6. Causa: Feijão Proxido *
Quando um bean no contexto é submetido a proxy usando o mecanismo JDK Dynamic Proxy,* o proxy não estende o bean de destino *(no entanto, implementa as mesmas interfaces).
Por esse motivo, se o bean for injetado por uma interface, ele será conectado corretamente. Se, no entanto, o bean for injetado pela classe real, o Spring não encontrará uma definição de bean que corresponda à classe - já que o proxy não estende a classe.
Um motivo muito comum pelo qual o bean pode ser submetido a proxy é o* Suporte transacional Spring *- ou seja, beans anotados com _ @ Transactional_.
Por exemplo, se ServiceA injeta ServiceB, e ambos os serviços são transacionais,* a injeção pela definição de classe *não funcionará:
@Service
@Transactional
public class ServiceA implements IServiceA{
@Autowired
private ServiceB serviceB;
...
}
@Service
@Transactional
public class ServiceB implements IServiceB{
...
}
Os mesmos dois serviços, desta vez corretamente* injetados pela interface *, estarão OK:
@Service
@Transactional
public class ServiceA implements IServiceA{
@Autowired
private IServiceB serviceB;
...
}
@Service
@Transactional
public class ServiceB implements IServiceB{
...
}
7. Conclusão
Este tutorial discutiu exemplos das possíveis causas da NoSuchBeanDefinitionException comum - com foco em como abordar essas exceções na prática.
A implementação de todos esses exemplos de exceções pode ser encontrada em the GitHub project - this é um projeto baseado em Eclipse, portanto, deve ser fácil importar e executar como está.
Por fim, o link:/spring-exceptions [ a lista completa de exceções e soluções ] no Spring pode ser um bom recurso para adicionar aos favoritos.