For nylig blev RedisTemplate brugt under projektudvikling, og enhedstest gav en prompt "Field redisTemplate in com.example.demo1.dao.RedisDao krævede en bean af typen 'org.springframework.data.redis.core.RedisTemplate', som kunne ikke findes", hvilket oversættes til "kunne ikke finde en bønne af typen RedisTemplate". Selvfølgelig, hvis vi ser på denne sætning alene, kan vi ikke være sikre på, hvorfor dette problem opstår. Læg nu en detaljeret fejllog op.
2018-08-10 14:53:49.761 - Fangede undtagelse, mens TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] forberedte test instans [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext på org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) på org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestTestInstance(ServletTestExecutionListener.java:131) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) på org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) på org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) på org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) på org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) på org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) på org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) på org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) på org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) på org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) på org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) på org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) på org.junit.runners.ParentRunner.run(ParentRunner.java:363) på org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) på org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) på org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) på org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) på org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) på org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) på org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Forårsaget af: org.springframework.beans.factory.UnsatisfiedDependencyException: Fejl ved oprettelse af bønne med navnet 'redisDao': Utilfredsstillet afhængighed udtrykt gennem feltet ' redisTemplate'; Nested exception er org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean af typen 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' Tilgængelig: forventer mindst 1 bønne, som kvalificerer sig som autowire-kandidat. Afhængighedsannotationer: {@org.springframework.beans.factory.annotation.Autowired(required=true)} på org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) på org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) på org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) på org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) på org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) på org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) på org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) på org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) på org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) på org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) på org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) på org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) på org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) på org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) på org.springframework.boot.SpringApplication.run(SpringApplication.java:303) på org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) på org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) på org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) ... 25 almindelige rammer udeladt Forårsaget af: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean af typen 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' Tilgængelig: forventer mindst 1 bønne, som kvalificerer sig som autowire-kandidat. Afhængighedsannotationer: {@org.springframework.beans.factory.annotation.Autowired(required=true)} på org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) på org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 43 almindelige rammer udeladt At se denne store fejllog er lidt svimmel, faktisk behøver vi kun at kigge på nøglefejlloggene for at finde problemet. Den anden Forårsaget af i fejlloggen udskriver nøglefejlloggen:No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
Forfatteren ser tilbage på den skrevne kode og specificerer den specifikke type, når RedisTemplate indsættes< K, V>.
Ifølge fejlloggen, tjek koden på linje 1493 i klassen DefaultListableBeanFactory, kildekoden er som følger:
Disse to metoder viser, at ingen bønne kan matches < RedisTemplate String, Object, >, så hvordan løser man dette problem? Du kan ønske at bruge RedisTemplate< K, V> uden at specificere den specifikke type, og ændre koden som følger:
Genstart tjenesten, der rapporteres ingen fejl i opstartsloggen, og RedisTemplate injicerer bønnen med succes. Jeg undrer mig over, hvorfor RedisTemplate< String, Object> injicering beans fejler. Efter at have tænkt længe over det, tænkte jeg, at RedisTemplate automatisk konfigureres i SpringBoot-frameworket, og at standarden i containeren er instansen af RedisTemplate. Med dette i tankerne skal du gennemgå de officielle hjemmesidedokumenter for at se, om der er nogen forklaring i de officielle hjemmesidedokumenter. Ganske rigtigt forklarer afsnit 30.1.1 i den officielle dokumentation stadig RedisTemplate.
Officiel dokumentadresse:https://docs.spring.io/spring-bo ... ference/htmlsingle/
Hvis du tilføjer din egen@Beanaf alle de autokonfigurerede typer erstatter den standarden (undtagen i tilfældet RedisTemplate, hvor udelukkelsen er baseret på bønnenavnet redisTemplate, ikke dens type). Hvis du tilføjer din egen bønne til auto-konfigurationstypen, vil den erstatte standarden. Min kode ser ud til at være fin, vent... Denne sætning i parentes er pointen. Oversæt en bølge,Undtagen i tilfældet med RedisTemplate, hvor man udelukker baseret på bønnens navn, ikke dens type. Engelsk er ikke særlig god, og det virker som om, oversættelsen ikke er særlig glat.
Nu synes det at være forstået, at RedisTemplate< String, Object > brugt @Autowired ved injektion,@Autowired samlet efter type som standard。 Med andre ord, hvis du vil have bønnerne > RedisTemplate< String, Object, skal du samle dem efter deres navne. Så tænk naturligt på at bruge det@Resource samles den som standard i henhold til navnet。 Ændr koden igen som følger:
Annotationen er blevet ændret fra @Autowired til @Resource Projektet startede fejlfrit, og det blev perfekt løst!
Genstart tjenesten igen, opstartsloggen rapporterer ingen fejl, og RedisTemplate< String, Object> injicerer bønnen med succes. Gennem denne fejl lærte jeg en funktion fra auto-konfigurationsklassen i SpringBoot-frameworket. Samtidig afspejler det også, at det at lære en teknologi bør starte fra den officielle hjemmeside for at undgå at træde i graven. I selve udviklingsprocessen kræver brugen af RedisTemplate< K, V> ikke specificering af typen K og V, og standardbønnen kan opfylde kravene.
Endelig vil jeg verificere et lille problem og ændre koden igen som følger:
Ovenstående kode specificerer, at K og V begge er strengtyper, når man injicerer RedisTemplate, og sammenligner om redisTemplate og stringRedisTemplate er det samme objekt i compare()-metoden. Kør enhedstestklassen, og testresultaterne er som følger:
2018-08-10 18:30:57.075 - Startede Demo1ApplicationTests på 15,58 sekunder (JVM kørte på 16,974) 2018-08-10 18:30:57.360 - hashcode:1996087296 for redisTemplate 2018-08-10 18:30:57.360 - stringRedisTemplate hashkode:1996087296 2018-08-10 18:30:57.363 - Resultat af lig(): sand 2018-08-10 18:30:57.364 - Sammenligningsresultat af redisTemplate og stringRedisTemplate: true Testresultaterne viser, at redisTemplate og stringRedisTemplate er det samme objekt. Vent et minut... Hvorfor er det ikke forkert at specificere, at K og V er strenge, når man injicerer RedisTemplate denne gang? Desuden viste de to objekter sig at være det samme objekt. Lad os se på kildekoden til StringRedisTemplate.
Efter at have læst kildekoden, forstår du så, fordi forældreklassen til StringRedisTemplate-klassen er RedisTemplate< String, String>, og bønnen er som standard singleton, og de to er naturligt det samme objekt.
|