Äskettäin RedisTemplatea käytettiin projektin kehityksessä, ja yksikkötestaus aiheutti "Field redisTemplate com.example.demo1.dao.RedisDao vaati pavun tyyppiin 'org.springframework.data.redis.core.RedisTemplate', joka ei löytynyt", mikä tarkoittaa "ei löytynyt RedisTemplate-tyyppistä papua". Tietenkään pelkästään tämän lauseen perusteella emme voi olla varmoja, miksi tämä ongelma syntyy. Nyt laita yksityiskohtainen virheloki.
2018-08-10 14:53:49.761 - Poikkeus havaittu, kun TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] valmistautui testiin Instanssi [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) osoitteessa org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) osoitteessa org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) osoitteessa org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131) osoitteessa org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) osoitteessa org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) osoitteessa org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) osoitteessa org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) osoitteessa org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) osoitteessa org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) osoitteessa org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) osoitteessa org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) osoitteessa org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) osoitteessa org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) osoitteessa org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) osoitteessa org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) osoitteessa org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) osoitteessa org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) osoitteessa org.junit.runners.ParentRunner.run(ParentRunner.java:363) osoitteessa org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) osoitteessa org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) osoitteessa org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) osoitteessa org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) osoitteessa org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) osoitteessa org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) osoitteessa org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Aiheutettu: org.springframework.beans.factory.UnsatisfiedDependencyException: Virhe papujen luomisessa nimellä 'redisDao': Tyytymätön riippuvuus, joka ilmenee kentän kautta ' redisTemplate'; sisäkkäinen poikkeus on org.springframework.beans.factory.NoSuchBeanDefinitionException: Ei kelpaavia papuja tyyppiä 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' saatavilla: odotetaan vähintään yksi papu, joka täyttää autowire-ehdokkaan. Riippuvuusmerkinnät: {@org.springframework.beans.factory.annotation.Autowired(required=true)} osoitteessa org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) osoitteessa org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) osoitteessa org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) osoitteessa org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) osoitteessa org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) osoitteessa org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) osoitteessa org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) osoitteessa org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) osoitteessa org.springframework.beans.factory.support.abstractBeanFactory.getBean(AbstractBeanFactory.java:197) osoitteessa org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) osoitteessa org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) osoitteessa org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) osoitteessa org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) osoitteessa org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) osoitteessa org.springframework.boot.SpringApplication.run(SpringApplication.java:303) osoitteessa 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 yleistä kehystä jätetty pois Aiheutettu: org.springframework.beans.factory.NoSuchBeanDefinitionException: Ei kelpaavia papuja tyyppiä 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' saatavilla: odotetaan vähintään yksi papu, joka täyttää autowire-ehdokkaan. Riippuvuusmerkinnät: {@org.springframework.beans.factory.annotation.Autowired(required=true)} osoitteessa org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) osoitteessa org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) osoitteessa org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) osoitteessa org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 43 yleistä kehystä jätetty pois Tämän suuren virhelokin näkeminen on hieman huimaavaa, itse asiassa riittää, että katsomme avainvirhelokkeja löytääksemme ongelman. Toinen Caused by virhelokissa tulostaa näppäinvirhelokin:Ei kelpaavia papuja tyyppiä 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
Kirjoittaja katsoo kirjoitettua koodia ja määrittelee tietyn tyypin injektioidessaan RedisTemplate< K, V>.
Virhelokin mukaan tarkista koodi riviltä 1493 luokasta DefaultListableBeanFactory, lähdekoodi on seuraava:
Nämä kaksi menetelmää osoittavat, ettei yhtäkään papua voi yhdistää < RedisTemplate-merkkijonoa, objektia >, joten miten tämä ongelma ratkaistaan? Voit haluta käyttää RedisTemplate< K, V> ilman tarkkaa tyyppiä ja muokata koodia seuraavasti:
Käynnistä palvelu uudelleen, eikä käynnistyslokissa raportoida virhettä, ja RedisTemplate injektoi pavun onnistuneesti. Mietin, miksi RedisTemplate< String, Object> papujen injektiointi epäonnistuu. Pitkän pohdinnan jälkeen ajattelin, että RedisTemplate on automaattisesti konfiguroitu SpringBoot-kehyksessä, ja kontin oletus on RedisTemplaten instanssi. Tätä ajatellen sinun täytyy käydä läpi viralliset verkkosivuston asiakirjat nähdäksesi, löytyykö niistä mitään selitystä. Totta kai virallisen dokumentaation kohta 30.1.1 selittää edelleen RedisTemplaten.
Virallinen asiakirjan osoite:https://docs.spring.io/spring-bo ... ference/htmlsingle/
Jos lisäät oman@Beankaikista automaattisesti konfiguroiduista tyypeistä se korvaa oletusarvon (paitsi RedisTemplaten tapauksessa, jossa poissulkeminen perustuu papunimeen, redisTemplate, ei sen tyyppiin). Jos lisäät oman pavun automaattiseen konfigurointityyppiin, se korvaa oletustyypin. Koodini vaikuttaa olevan kunnossa, odota... Tämä lause sulkeissa on pointti. Käännä aalto,Paitsi RedisTemplaten tapauksessa, kun se sulkee pois pavun nimen, ei tyypin perusteella. Englanti ei ole kovin hyvä, eikä käännös vaikuta kovin sujuvalta.
Nyt näyttää ymmärrettävän, että RedisTemplate< String, Object > @Autowired injektioissa,@Autowired koottu tyypin mukaan oletuksena。 Toisin sanoen, jos haluat saada pavut > RedisTemplate< String, Object, sinun täytyy koota ne nimien mukaan. Sitten luonnollisesti harkitse sen käyttöä@Resource se kootaan oletuksena nimen mukaisesti。 Muokkaa koodia uudelleen seuraavasti:
Merkintä on muutettu @Autowired:sta @Resource Projekti alkoi virheettömästi ja ratkaistiin täydellisesti!
Kun palvelu käynnistetään uudelleen, käynnistysloki ei raportoi virhettä, ja RedisTemplate< String, Object > injektoi pavun onnistuneesti. Tämän virheen kautta opin SpringBoot-kehyksen automaattisen konfigurointiluokan ominaisuuden. Samalla se heijastaa myös, että teknologian oppiminen tulisi aloittaa viralliselta verkkosivustolta, jotta ei astuisi kuoppaan. Varsinaisessa kehitysprosessissa RedisTemplate< K, V> ei vaadi K:n ja V:n tyypin määrittelyä, ja oletuspapu voi täyttää vaatimukset.
Lopuksi haluan varmistaa pienen ongelman ja muokata koodia uudelleen seuraavasti:
Yllä oleva koodi määrittelee, että K ja V ovat molemmat merkkijonotyyppejä, kun RedisTemplate injektoidaan, ja vertaa, ovatko redisTemplate ja stringRedisTemplate sama objekti compare()-menetelmässä. Suorita yksikkötestikurssi, ja testitulokset ovat seuraavat:
2018-08-10 18:30:57.075 - Demo1ApplicationTests aloitettiin 15,58 sekunnissa (JVM ajaa 16,974) 2018-08-10 18:30:57.360 - hashcode:1996087296 redisTemplatelle 2018-08-10 18:30:57.360 - stringRedisTemplate hashcode:1996087296 2018-08-10 18:30:57.363 - Tulos equal(): true 2018-08-10 18:30:57.364 - redisTemplaten ja stringRedisTemplaten vertailutulos: true Testitulokset osoittavat, että redisTemplate ja stringRedisTemplate ovat sama objekti. Odota hetki... Miksi ei ole väärin täsmentää, että K ja V ovat merkkijonoja, kun tällä kertaa injektioidaan RedisTemplate? Lisäksi nämä kaksi esinettä osoittautuivat samaksi esineeksi. Katsotaanpa StringRedisTemplaten lähdekoodia.
Luettuasi lähdekoodin, ymmärrätkö, koska StringRedisTemplate-luokan emoluokka on RedisTemplate< String, String> ja papu on oletuksena singleton, ja nämä kaksi ovat luonnostaan sama objekti.
|