Este artigo é um artigo espelhado de tradução automática, por favor clique aqui para ir para o artigo original.

Vista: 15336|Resposta: 0

[Fonte] A exceção é resolvida injetando a instância RedisTemplate no SpringBoot

[Copiar link]
Publicado em 11/03/2019 13:25:56 | | | |
Recentemente, o RedisTemplate foi usado durante o desenvolvimento do projeto, e testes unitários solicitaram "Field redisTemplate em com.example.demo1.dao.RedisDao exigiu um grão do tipo 'org.springframework.data.redis.core.RedisTemplate' que não foi possível encontrar", que se traduz como "não consegui encontrar um grão do tipo RedisTemplate". Claro, olhando apenas para essa frase, não podemos ter certeza do motivo pelo qual esse problema ocorre. Agora, poste um registro detalhado de erros.

2018-08-10 14:53:49.761 - Detectou exceção ao permitir que o TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] preparasse o teste Instância [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    em org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
    em org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
    em org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
    em org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
    em org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
    em org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    em org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
    em org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
    em org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    em org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    em org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    em org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    em org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    em org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    em org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    em org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    em org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    em org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    em org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    em org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    em org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    em org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    em org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    em org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Causado por: org.springframework.beans.factory.UnsatisfiedDependencyException: Erro criando bean com nome 'redisDao': Dependência insatisfeita expressa através do campo ' redisTemplate'; Exceção aninhada é org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean do tipo 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>'Disponível: Espera-se pelo menos 1 feijão que se qualifica como candidato ao autowire. Anotações de dependência: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    em org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
    em org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    em org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
    em org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
    em org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    em org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    em org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    em org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    em org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    em org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    em org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    em org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    em org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    em org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
    em org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
    em org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 25 quadros comuns omitidos
Causado por: org.springframework.beans.factory.NoSuchBeanDefinitionException: Nenhum feijão qualificante do tipo 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>'Disponível: Espera-se pelo menos 1 feijão que se qualifica como candidato ao autowire. Anotações de dependência: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    em org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
    em org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
    em org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
    ... 43 quadros comuns omitidos
Ver esse grande log de erros é um pouco confuso, na verdade, só precisamos olhar os logs de erro chave para localizar o problema. O segundo Causado por no log de erros imprime o log de erro de chave:Sem bean qualificante do tipo 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。

O autor analisa o código escrito e especifica o tipo específico ao injetar RedisTemplate< K, V>.


De acordo com o registro de erros, verifique o código na linha 1493 da classe DefaultListableBeanFactory, o código-fonte é o seguinte:

Esses dois métodos mostram que nenhum feijão pode ser combinado < RedisTemplate String, Object, >, então como resolver esse problema? Você pode querer usar RedisTemplate< K, V> sem especificar o tipo específico e modificar o código da seguinte forma:

Reinicie o serviço, nenhum erro é reportado no log de inicialização e o RedisTemplate injeta o bean com sucesso. Fico me perguntando por que o RedisTemplate< String, Object> injetar feijões falha. Depois de pensar bastante sobre isso, pensei que o RedisTemplate é configurado automaticamente no framework SpringBoot, e o padrão no contêiner é a instância do RedisTemplate. Pensando nisso, você precisa consultar os documentos do site oficial para ver se há alguma explicação nos documentos do site oficial. De fato, a seção 30.1.1 da documentação oficial ainda explica o RedisTemplate.

Endereço oficial do documento:https://docs.spring.io/spring-bo ... ference/htmlsingle/




Se você adicionar o seu próprio@Beande qualquer um dos tipos autoconfigurados, ele substitui o padrão (exceto no caso do RedisTemplate, quando a exclusão é baseada no nome do bean, redisTemplate, e não no tipo).
Se você adicionar seu próprio bean para o tipo de configuração automática, ele substituirá o padrão. Meu código parece estar ok, espere... Esta frase entre parênteses é o ponto. Transfira uma onda,Exceto no caso do RedisTemplate, quando excluído com base no nome do grão, não no tipo. O inglês não é muito bom, e parece que a tradução não é muito suave.

Agora parece entender-se que o RedisTemplate< String, Object > usado @Autowired ao injetar,@Autowired montados por tipo por padrão。 Em outras palavras, se você quer pegar os grãos > RedisTemplate< String, Object, precisa montá-los de acordo com os nomes deles. Depois, naturalmente, pense em usá-lo@Resource, é montado por padrão de acordo com o nome。 Modifique o código novamente da seguinte forma:


A anotação foi alterada de @Autowired para @Resource O projeto começou sem erros, e foi perfeitamente resolvido!

Reinicie o serviço novamente, o log de inicialização não reporta erro, e o RedisTemplate< String, Object> injeta o bean com sucesso. Por meio desse erro, aprendi uma funcionalidade da classe de auto-configuração no framework SpringBoot. Ao mesmo tempo, também reflete que aprender uma tecnologia deve começar pelo site oficial para evitar pisar no poço.
No processo real de desenvolvimento, usando RedisTemplate< K, V> não é necessário especificar o tipo de K e V, e o feijão padrão pode atender aos requisitos.

Por fim, quero verificar um pequeno problema e modificar o código novamente da seguinte forma:


O código acima especifica que K e V são ambos tipos de String ao injetar RedisTemplate, e compara se redisTemplate e stringRedisTemplate são o mesmo objeto no método compar(). Execute a classe de teste unitário, e os resultados do teste são os seguintes:

2018-08-10 18:30:57.075 - Iniciei o Demo1ApplicationTests em 15,58 segundos (JVM rodando para 16,974)
2018-08-10 18:30:57.360 - código hash:1996087296 para redisTemplate
2018-08-10 18:30:57.360 - stringRedisTemplate código hash:1996087296
2018-08-10 18:30:57.363 - Resultado de igual(): verdadeiro
2018-08-10 18:30:57.364 - Resultado da comparação entre redisTemplate e stringRedisTemplate: true
Os resultados do teste mostram que redisTemplate e stringRedisTemplate são o mesmo objeto. Espere um minuto... Por que não é errado especificar que K e V são Strings ao injetar o RedisTemplate desta vez? Além disso, os dois objetos acabaram sendo o mesmo objeto. Vamos dar uma olhada no código-fonte do StringRedisTemplate.

Depois de ler o código-fonte, você entende, porque a classe mãe da classe StringRedisTemplate é RedisTemplate< String, String>, e o bean é singleton por padrão, e os dois são naturalmente o mesmo objeto.




Anterior:Cast to value type "System.Decimal" falhou...
Próximo:Erro ao criar feijão com o nome 'stringRedisTemplate' definido em...
Disclaimer:
Todo software, material de programação ou artigos publicados pela Code Farmer Network são apenas para fins de aprendizado e pesquisa; O conteúdo acima não deve ser usado para fins comerciais ou ilegais, caso contrário, os usuários terão todas as consequências. As informações deste site vêm da Internet, e disputas de direitos autorais não têm nada a ver com este site. Você deve deletar completamente o conteúdo acima do seu computador em até 24 horas após o download. Se você gosta do programa, por favor, apoie um software genuíno, compre o registro e obtenha serviços genuínos melhores. Se houver qualquer infração, por favor, entre em contato conosco por e-mail.

Mail To:help@itsvse.com