Nedávno sa počas vývoja projektu použil RedisTemplate a unit testing vyvolal "Field redisTemplate in com.example.demo1.dao.RedisDao vyžadoval fazuľu typu 'org.springframework.data.redis.core.RedisTemplate', ktorá nebolo možné nájsť", čo znamená "nepodarilo sa nájsť fazuľu typu RedisTemplate". Samozrejme, keď sa pozrieme len na túto vetu, nemôžeme si byť istí, prečo tento problém vzniká. Teraz zverejnite podrobný záznam chýb.
2018-08-10 14:53:49.761 - Zachytil výnimku pri umožnení TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] pripraviť test Príklad [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) na stránkach org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) na org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) na org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) na org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) na org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) na org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) na org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) na org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) na org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) na org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Spôsobené: org.springframework.beans.factory.UnsatisfiedDependencyException: Chyba vytvárajúca fazuľu s názvom 'redisDao': Nesplnená závislosť vyjadrená cez pole ' redisTemplate'; vnorená výnimka je org.springframework.beans.factory.NoSuchBeanDefinitionException: Žiadny kvalifikujúci bean typu 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' Dostupné: očakáva sa aspoň 1 fazuľa, ktorá spĺňa kritériá Autowire. Anotácie závislostí: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) na org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) na org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) na org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) na org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) na org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) na org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) na org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) na org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) na org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) na org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) at 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 bežných rámcov vynechaných Spôsobené: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' Dostupné: očakáva sa aspoň 1 fazuľa, ktorá spĺňa kritériá Autowire. Anotácie závislostí: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at 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) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 43 bežných rámcov vynechaných Vidieť tento veľký záznam chýb je trochu mätúce, v skutočnosti stačí pozrieť kľúčové záznamy chýb, aby sme našli problém. Druhý Caused by v error logu vypíše kľúčový error log:No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
Autor sa spätne pozrie na napísaný kód a špecifikuje konkrétny typ pri vkladaní RedisTemplate< K, V>.
Podľa záznamu chýb, skontrolujte kód na riadku 1493 triedy DefaultListableBeanFactory, zdrojový kód je nasledovný:
Tieto dve metódy ukazujú, že žiadna fazuľa nemožno priradiť < RedisTemplate String, Object >, takže ako tento problém vyriešiť? Môžete použiť RedisTemplate< K, V> bez špecifikovania konkrétneho typu a upraviť kód nasledovne:
Reštartujem službu, v spustovacom logu sa nehlási žiadna chyba a RedisTemplate úspešne vstrekne zrno. Zaujímalo by ma, prečo RedisTemplate< String, Object> injektovanie fazúľ zlyháva. Po dlhom premýšľaní som si myslel, že RedisTemplate je automaticky konfigurovaný v SpringBoot frameworku a predvolená inštancia v kontajneri je inštancia RedisTemplate. Keď nad tým premýšľate, mali by ste si prelistovať oficiálne dokumenty na webovej stránke, aby ste zistili, či v oficiálnych dokumentoch nie je nejaké vysvetlenie. A naozaj, sekcia 30.1.1 oficiálnej dokumentácie stále vysvetľuje RedisTemplate.
Oficiálna adresa dokumentu:https://docs.spring.io/spring-bo ... ference/htmlsingle/
Ak si pridáte svoje vlastné@Beanz akéhokoľvek automaticky konfigurovaného typu nahrádza predvolený (okrem prípadu RedisTemplate, kde je vylúčenie založené na názve zrna redisTemplate, nie na jeho type). Ak pridáte vlastné zrno pre automatickú konfiguráciu, nahradí to predvolené. Môj kód sa zdá byť v poriadku, počkaj... Táto veta v zátvorkách je pointa. Prelož vlnu,Okrem prípadu RedisTemplate, keď sa vylučuje podľa názvu zrna, nie podľa jeho typu. Angličtina nie je veľmi dobrá a zdá sa, že preklad nie je veľmi plynulý.
Teraz sa zdá, že RedisTemplate< String, Object > použitý @Autowired pri injekcii,@Autowired zostavené podľa typu predvolene。 Inými slovami, ak chcete získať zrná > RedisTemplate< String, Object, musíte ich zostaviť podľa ich názvov. Potom prirodzene uvažuj o jeho použití@Resource sa zostavuje predvolene podľa názvu。 Kód upravte znova nasledovne:
Anotácia bola zmenená z @Autowired na @Resource Projekt začal bez chyby a bol dokonale vyriešený!
Reštartujte službu znova, štartovací log nehlási chybu a RedisTemplate< String, Object> úspešne vstrekne bean. Vďaka tejto chybe som sa naučil funkciu triedy automatickej konfigurácie v rámci SpringBootu. Zároveň to tiež odráža, že učenie technológie by sa malo začať na oficiálnej webovej stránke, aby sa predišlo stúpeniu na jamu. V skutočnom vývojovom procese, pri použití RedisTemplate< K, V> nevyžaduje špecifikovanie typu K a V a predvolené zrno môže splniť požiadavky.
Nakoniec chcem overiť malý problém a kód opäť upraviť nasledovne:
Vyššie uvedený kód špecifikuje, že K a V sú oba typy reťazcov pri injekcii RedisTemplate, a porovnáva, či sú redisTemplate a stringRedisTemplate ten istý objekt v metóde compare(). Spustite triedu jednotkového testu a výsledky testu sú nasledovné:
2018-08-10 18:30:57.075 - Spustili Demo1ApplicationTests za 15,58 sekundy (JVM bežal 16,974) 2018-08-10 18:30:57.360 - hashcode:1996087296 pre redisTemplate 2018-08-10 18:30:57.360 - stringRedisTemplate hashcode:1996087296 2018-08-10 18:30:57.363 - Výsledok equal(): true 2018-08-10 18:30:57.364 - Výsledok porovnania redisTemplate a stringRedisTemplate: true Výsledky testu ukazujú, že redisTemplate a stringRedisTemplate sú ten istý objekt. Počkaj chvíľu... Prečo nie je nesprávne špecifikovať, že K a V sú reťazce pri injektovaní RedisTemplate tentoraz? Navyše, ukázalo sa, že oba objekty sú ten istý objekt. Pozrime sa na zdrojový kód StringRedisTemplate.
Po prečítaní zdrojového kódu, rozumiete, pretože nadradená trieda triedy StringRedisTemplate je RedisTemplate< String, String> a bean je predvolene singleton, takže oba sú prirodzene ten istý objekt.
|