Récemment, RedisTemplate a été utilisé lors du développement du projet, et les tests unitaires ont suscité la demande « Field redisTemplate in com.example.demo1.dao.RedisDao nécessitait un type 'org.springframework.data.redis.core.RedisTemplate' qui n’a pas pu être trouvé », ce qui se traduit par « impossible de trouver un grain de type RedisTemplate ». Bien sûr, en regardant cette phrase seule, nous ne pouvons pas être sûrs de la raison pour laquelle ce problème survient. Maintenant, publiez un journal d’erreurs détaillé.
2018-08-10 14:53:49.761 - Exception prise en permettant à TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] de préparer le test instance [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java :124) sur org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java :83) sur org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java :189) sur org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java :131) sur org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java :230) sur org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java :228) sur org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java :287) sur org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java :12) sur org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java :289) sur org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java :247) sur org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java :94) sur org.junit.runners.ParentRunner$3.run(ParentRunner.java :290) sur org.junit.runners.ParentRunner$1.schedule(ParentRunner.java :71) sur org.junit.runners.ParentRunner.runChildren(ParentRunner.java :288) sur org.junit.runners.ParentRunner.access$000(ParentRunner.java :58) sur org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java :268) sur org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java :61) sur org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java :70) sur org.junit.runners.ParentRunner.run(ParentRunner.java :363) sur org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java :191) sur org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java :86) sur org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java :38) sur org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java :459) sur org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java :675) sur org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java :382) sur org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java :192) Causé par : org.springframework.beans.factory.UnsatisfedDependencyException : Erreur de création de bean avec le nom 'redisDao' : Dépendance insatisfaite exprimée via le champ ' redisTemplate ; Exception imbriquée est org.springframework.beans.factory.NoSuchBeanDefinitionException : Aucun bean qualifiant de type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>Disponible : Attendu au moins 1 haricot qui correspond à un candidat autowire. Annotations de dépendance : {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java :588) sur org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java :88) sur org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java :366) sur org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java :1264) sur org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java :553) sur org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java :483) sur org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java :306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java :230) sur org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java :302) sur org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java :197) sur org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java :761) sur org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java :867) sur org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java :543) sur org.springframework.boot.SpringApplication.refresh(SpringApplication.java :693) sur org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java :360) sur org.springframework.boot.SpringApplication.run(SpringApplication.java :303) sur 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 images courantes omises Causé par : org.springframework.beans.factory.NoSuchBeanDéfinition : Aucun bean qualifiant de type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>Disponible : Attendu au moins 1 haricot qui correspond à un candidat autowire. Annotations de dépendance : {@org.springframework.beans.factory.annotation.Autowired(required=true)} sur org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java :1493) sur org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java :1104) sur org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java :1066) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java :585) ... 43 images communes omises Voir ce grand journal d’erreurs est un peu étourdissant, en fait, il suffit de regarder les journaux d’erreurs clés pour localiser le problème. Le second Causé par dans le journal d’erreurs affiche le journal d’erreur clé :Aucun grain qualifiant de type 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
L’auteur revient sur le code écrit et précise le type spécifique lors de l’injection de RedisTemplate< K, V>.
Selon le journal d’erreurs, vérifiez le code à la ligne 1493 de la classe DefaultListableBeanFactory, le code source est le suivant :
Ces deux méthodes montrent qu’aucun grain ne peut être associé < chaîne RedisTemplate, Object, >, alors comment résoudre ce problème ? Vous pouvez utiliser RedisTemplate< K, V> sans spécifier le type spécifique, et modifier le code comme suit :
Redémarrez le service, aucune erreur n’est signalée dans le journal de démarrage, et le RedisTemplate injecte le bean avec succès. Je me demande pourquoi RedisTemplate< String, Object> injecter des grains échoue. Après y avoir longuement réfléchi, j’ai pensé que RedisTemplate était automatiquement configuré dans le framework SpringBoot, et que la valeur par défaut dans le conteneur était l’instance de RedisTemplate. En y réfléchissant, vous devez parcourir les documents officiels du site officiel pour voir s’il y a une explication dans les documents officiels. Effectivement, la section 30.1.1 de la documentation officielle explique toujours RedisTemplate.
Adresse officielle du document :https://docs.spring.io/spring-bo ... ference/htmlsingle/
Si vous ajoutez le vôtre@Beande tous les types auto-configurés, il remplace le défaut (sauf dans le cas de RedisTemplate, lorsque l’exclusion est basée sur le nom du bean, redisTemplate, et non sur son type). Si vous ajoutez votre propre grain pour le type de configuration automatique, il remplacera le modèle par défaut. Mon code semble correct, attends... Cette phrase entre parenthèses est le point. Traduis une onde,Sauf dans le cas de RedisTemplate, en excluant en fonction du nom du grain, pas de son type. L’anglais n’est pas très bon, et il semble que la traduction ne soit pas très fluide.
Il semble maintenant comprendre que le RedisTemplate< String, Objet > utilisé @Autowired lors de l’injection,@Autowired assemblé par type par défaut。 En d’autres termes, si vous voulez obtenir les grains > RedisTemplate< String, Object, vous devez les assembler selon leurs noms. Puis pensez naturellement à l’utiliser@Resource, il est assemblé par défaut selon le nom。 Modifiez à nouveau le code comme suit :
L’annotation a été modifiée de @Autowired à @Resource Le projet a commencé sans erreur, et il a été parfaitement résolu !
Redémarrez le service, le journal de démarrage ne signale aucune erreur, et le RedisTemplate< String, Object> injecte le bean avec succès. Grâce à cette erreur, j’ai appris une fonctionnalité de la classe auto-configuration dans le framework SpringBoot. En même temps, cela reflète aussi que l’apprentissage d’une technologie doit commencer sur le site officiel afin d’éviter de marcher dans la fosse. Dans le processus de développement proprement dit, en utilisant RedisTemplate< K, V> ne nécessite pas de spécifier le type de K et V, et le bean par défaut peut répondre aux conditions.
Enfin, je souhaite vérifier un petit problème et modifier à nouveau le code comme suit :
Le code ci-dessus spécifie que K et V sont tous deux des types de chaînes lors de l’injection de RedisTemplate, et compare si redisTemplate et stringRedisTemplate sont le même objet dans la méthode compar(). Exécutez la classe de test unitaire, et les résultats du test sont les suivants :
2018-08-10 18:30:57.075 - Début des tests Demo1ApplicationTests en 15,58 secondes (JVM fonctionnant à 16,974) 2018-08-10 18:30:57.360 - hashcode :1996087296 pour redisTemplate 2018-08-10 18:30:57.360 - stringRedisTemplate hashcode :1996087296 2018-08-10 18:30:57.363 - Résultat de égal() : vrai 2018-08-10 18:30:57.364 - Résultat de la comparaison entre redisTemplate et stringRedisTemplate : true Les résultats du test montrent que redisTemplate et stringRedisTemplate sont le même objet. Attends un peu... Pourquoi n’est-il pas faux de spécifier que K et V sont des chaînes lors de l’injection de RedisTemplate cette fois ? De plus, les deux objets se sont avérés être le même objet. Jetons un œil au code source de StringRedisTemplate.
Après avoir lu le code source, comprenez-vous, car la classe parente de la classe StringRedisTemplate est RedisTemplate< String, String>, et le grain est singleton par défaut, et les deux sont naturellement le même objet.
|