Ostatnio podczas rozwoju projektu użyto RedisTemplate, a testy jednostkowe spowodowały, że "Field redisTemplate in com.example.demo1.dao.RedisDao wymagał ziarna typu 'org.springframework.data.redis.core.RedisTemplate', który nie można było znaleźć", co tłumaczy się jako "nie udało się znaleźć ziarna typu RedisTemplate". Oczywiście, patrząc tylko na to zdanie, nie możemy być pewni, dlaczego ten problem się pojawia. Teraz opublikuj szczegółowy log błędów.
2018-08-10 14:53:49.761 - Złapano wyjątek podczas pozwalania TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] na przygotowanie testu Instancja [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) na org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) na 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 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 stronie org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) na stronie 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) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) na org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) na org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Spowodowane przez: org.springframework.beans.factory.UnsatisfiedDependencyException: Błąd tworzący fasolę o nazwie 'redisDao': Niespełniona zależność wyrażona przez pole ' redisTemplate'; zagnieżdżony wyjątek to org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean typu 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' dostępne: oczekiwana co najmniej 1 fasolka, która kwalifikuje się jako kandydat do Autowire. Adnotacje zależności: {@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) na org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) na 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 wspólnych ramek pominiętych Spowodowane przez: org.springframework.beans.factory.NoSuchBeanDefinitionException: Brak kwalifikującego beanu typu 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' dostępne: oczekiwana co najmniej 1 fasolka, która kwalifikuje się jako kandydat do Autowire. Adnotacje zależności: {@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 wspólne klatki pominięte Widok tego dużego rejestru błędów jest trochę zawrotny – w rzeczywistości wystarczy spojrzeć na kluczowe logi błędów, by zlokalizować problem. Drugie Caused by w logu błędów drukuje kluczowy log błędów:No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
Autor analizuje napisany kod i określa konkretny typ podczas wstrzykiwania RedisTemplate< K, V>.
Według logu błędów, sprawdź kod na linii 1493 klasy DefaultListableBeanFactory, gdzie kod źródłowy wygląda następująco:
Te dwie metody pokazują, że żadna fasola nie może być dopasowana < RedisTemplate String, Object >, więc jak rozwiązać ten problem? Możesz chcieć użyć RedisTemplate< K, V> bez określania konkretnego typu i modyfikować kod w następujący sposób:
Po ponownym uruchomieniu usługi nie pojawia się żaden błąd w logu uruchamiania, a RedisTemplate skutecznie wstrzykuje to ziarno. Zastanawiam się, dlaczego RedisTemplate< String, Object> wstrzykujący ziarna zawodzi. Po dłuższym namyśle pomyślałem, że RedisTemplate jest automatycznie skonfigurowany w frameworku SpringBoot, a domyślnym w kontenerze jest instancja RedisTemplate. Myśląc o tym, powinieneś przejrzeć oficjalne dokumenty strony, aby sprawdzić, czy w nich nie ma jakiegoś wyjaśnienia. Rzeczywiście, sekcja 30.1.1 oficjalnej dokumentacji nadal wyjaśnia RedisTemplate.
Oficjalny adres dokumentu:https://docs.spring.io/spring-bo ... ference/htmlsingle/
Jeśli dodasz własne@Beanspośród wszystkich automatycznie skonfigurowanych typów zastępuje domyślny (z wyjątkiem przypadku RedisTemplate, gdzie wykluczenie opiera się na nazwie ziarna, redisTemplate, a nie na jego typie). Jeśli dodasz własne ziarno do typu automatycznej konfiguracji, zastąpi ono domyślne. Mój kod wydaje się być w porządku, czekaj... To zdanie w nawiasie jest sednem sprawy. Przetłumacz falę,Z wyjątkiem przypadku RedisTemplate, gdy wyłącza się ze względu na nazwę ziarna, a nie jego rodzaj. Angielski nie jest zbyt dobry, a tłumaczenie wydaje się nie jest zbyt płynne.
Obecnie wydaje się, że RedisTemplate< String, Object > używany @Autowired podczas wstrzykiwania,@Autowired domyślnie składane według typu。 Innymi słowy, jeśli chcesz zdobyć fasolki > RedisTemplate< String, Object, musisz je złożyć zgodnie z ich nazwami. Potem naturalnie pomyśl o jego użyciu@Resource domyślnie jest składany zgodnie z nazwą。 Zmodyfikuj kod ponownie w następujący sposób:
Adnotacja została zmieniona z @Autowired na @Resource Projekt rozpoczął się bez błędu i został rozwiązany perfekcyjnie!
Po ponownym uruchomieniu usługi dziennik startowy nie zgłasza błędu, a RedisTemplate< String, Object> skutecznie wstrzyknął ziołkę. Dzięki temu błędowi nauczyłem się funkcji klasy auto-configuration w frameworku SpringBoot. Jednocześnie odzwierciedla to również, że nauka technologii powinna zaczynać się od oficjalnej strony internetowej, aby uniknąć wejścia na dół (pit). W rzeczywistym procesie rozwoju, korzystając z RedisTemplate< K, V> nie wymaga określenia typu K i V, a domyślne ziarno spełnia wymagania.
Na koniec chcę zweryfikować mały problem i ponownie zmodyfikować kod w następujący sposób:
Powyższy kod określa, że K i V są typami String podczas wstrzykiwania RedisTemplate i porównuje, czy redisTemplate i stringRedisTemplate to ten sam obiekt w metodzie compare(). Uruchom klasę testu jednostkowego, a wyniki testu są następujące:
2018-08-10 18:30:57.075 - Rozpoczęto Demo1ApplicationTests w 15,58 sekundy (JVM działające przez 16,974) 2018-08-10 18:30:57.360 - hashcode:1996087296 for redisTemplate 2018-08-10 18:30:57.360 - stringRedisTemplate hashcode:1996087296 2018-08-10 18:30:57.363 - Wynik equal(): true 2018-08-10 18:30:57.364 - Wyniki porównania redisTemplate i stringRedisTemplate: true Wyniki testów pokazują, że redisTemplate i stringRedisTemplate to ten sam obiekt. Poczekaj chwilę... Dlaczego tym razem nie jest błędem określić, że K i V to są Stringi przy wstrzykiwaniu RedisTemplate? Co więcej, okazało się, że oba obiekty są tym samym obiektem. Przyjrzyjmy się kodowi źródłowemu StringRedisTemplate.
Po przeczytaniu kodu źródłowego, czy rozumiesz, ponieważ klasa nadrzędna klasy StringRedisTemplate to RedisTemplate< String, String>, a bean domyślnie jest singleton i oba są naturalnie tym samym obiektem.
|