Son zamanlarda proje geliştirme sırasında RedisTemplate kullanıldı ve birim testi "com.example.demo1.dao.RedisDao içindeki redisTemplate alanı, 'org.springframework.data.redis.core.RedisTemplate' tipinde bir bean gerektiriyordu bulunamadı" anlamına gelir, bu da "RedisTemplate tipi bir çekirdek bulamadım" anlamına gelir. Tabii ki, sadece bu cümleye bakarak bu sorunun neden ortaya çıktığından emin olamıyoruz. Şimdi, detaylı bir hata kaydı paylaşın.
2018-08-10 14:53:49.761 - TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] testi hazırlamasına izin verirken istisna yakaladı örnek [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) org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) adresinde 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) org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) adresinde org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) adresinde org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) adresinde at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) adresinde org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) adresinde org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) adresinde org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) adresinde org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) adresinde at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) org.junit.runners.ParentRunner.run(ParentRunner.java:363) adresinde at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) adresinde org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) adresinde org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) adresinde org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) adresinde org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) adresinde org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) adresinde Nedeni: org.springframework.beans.factory.UnsatisfiedDependencyException: 'redisDao' adlı fasulye oluşturma hatası: Alan ' aracılığıyla ifade edilen tatmin edilmemiş bağımlılık redisTemplate'; iç içe istisna org.springframework.beans.factory.NoSuchBeanDefinitionException: 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object' tipinde nitelikli bir çekirdek yoktur>' Kullanılabilir: En az 1 fasulye bekleniyor ve bu otomatik kablo adayı olarak nitelendiriliyor. Bağımlılık annotasyonları: {@org.springframework.beans.factory.annotation.Autowired(required=true)} org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) adresinde org.springframework.beans.factory.annotation.injectionMetadata.inject(InjectionMetadata.java:88) adresinde org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) adresinde org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) adresinde org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) adresinde org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) adresinde org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) adresinde at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) adresinde org.springframework.beans.factory.support.abstractBeanFactory.getBean(AbstractBeanFactory.java:197) adresinde at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) adresinde org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) adresinde org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) adresinde 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 yaygın çerçeve çıkarıldı Nedeni: org.springframework.beans.factory.NoSuchBeanDefinitionException: 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object' tipinde nitelikli bir çekirdek yok>' Kullanılabilir: En az 1 fasulye bekleniyor ve bu otomatik kablo adayı olarak nitelendiriliyor. Bağımlılık annotasyonları: {@org.springframework.beans.factory.annotation.Autowired(required=true)} org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) adresinde at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) adresinde ... 43 yaygın çerçeve çıkarıldı Bu büyük hata günlüğünü görmek biraz baş döndürücü, aslında sorunu bulmak için sadece anahtar hata kayıtlarına bakmamız yeterli. İkinci Caused by hata logunda anahtar hata günlüğünü yazdırır:'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。 tipinde bir niteleyici bean yok
Yazar, yazılmış kodu tekrar bakar ve RedisTemplate< K, V> enjekte ederken belirli tipi belirtir.
Hata günlüğüne göre, DefaultListableBeanFactory sınıfının 1493 satırındaki kodu kontrol edin, kaynak kodu şu şekildedir:
Bu iki yöntem, hiçbir fasulyeyin RedisTemplate Dizisi, Nesne, > < eşleşemeyeceğini gösteriyor, peki bu sorunu nasıl çözebilirim? RedisTemplate< K, V> kullanmayı ve kodu aşağıdaki gibi değiştirmeyi tercih edebilirsiniz:
Hizmeti yeniden başlatın, başlangıç günlüğünde hata bildirilmez ve RedisTemplate çekirdeki başarıyla enjekte eder. RedisTemplate< String, Object> çekirdek enjekte etmenin neden başarısız olduğunu merak ediyorum. Uzun düşündükten sonra, RedisTemplate'in SpringBoot framework'te otomatik olarak yapılandırıldığını ve konteynerdeki varsayılan olarak RedisTemplate örneği olduğunu düşündüm. Bunu düşününce, resmi web sitesi belgelerinde herhangi bir açıklama olup olmadığını görmek için resmi web sitesi belgelerini gözden geçirmeniz gerekir. Gerçekten de, resmi dokümantasyonun 30.1.1 bölümü hâlâ RedisTemplate'i açıklıyor.
Resmi belge adresi:https://docs.spring.io/spring-bo ... ference/htmlsingle/
Kendi ekinizi eklerseniz@Beanotomatik yapılandırılan tiplerin herhangi birinden varsayılanı değiştirir (RedisTemplate hariç, hariç tutma bean adı olan redisTemplate'e dayanır, tipine değil). Otomatik yapılandırma türü için kendi bean'inizi eklerseniz, varsayılan olanı değiştirir. Kodum iyi görünüyor, bekle... Parantez içindeki bu cümle asıl nokta. Bir dalgayı çevir,RedisTemplate hariç, hariç hariç olarak, fasulyenin adına göre hariç tutulurken, tipine değil. İngilizce çok iyi değil ve çeviri de pek akıcı değil gibi görünüyor.
Şimdi anlaşıldığı anlaşılıyor ki RedisTemplate< Dizisi, Nesne > enjekte edilirken @Autowired kullanılıyor,@Autowired varsayılan olarak tipe göre derlenir。 Başka bir deyişle, çekirdekleri RedisTemplate< String, Object > almak istiyorsanız, onları isimlerine göre birleştirmeniz gerekir. O zaman doğal olarak kullanmayı düşün@Resource, ismine göre varsayılan olarak birleştirilir。 Kodu tekrar aşağıdaki gibi değiştirin:
Annotasyon @Autowired'dan @Resource'a değiştirildi. Proje hatasız başladı ve mükemmel şekilde çözüldü!
Hizmeti tekrar başlatın, başlangıç günlüğü hata rapor etmez ve RedisTemplate< String, Object> çekirdeki başarıyla enjekte eder. Bu hata sayesinde, SpringBoot framework'teki otomatik yapılandırma sınıfının bir özelliğini öğrendim. Aynı zamanda, bir teknolojiyi öğrenmenin resmi web sitesinden başlaması gerektiğini, çukura basmaktan kaçınması gerektiğini de yansıtıyor. Gerçek geliştirme sürecinde, RedisTemplate< K kullanılarak V> K ve V türlerini belirtmek zorunda kalmaz ve varsayılan çekirdek gereksinimleri karşılayabilir.
Son olarak, küçük bir sorunu doğrulamak ve kodu tekrar şu şekilde değiştirmek istiyorum:
Yukarıdaki kod, RedisTemplate enjekte edilirken K ve V'nin her ikisinin de String tipi olduğunu belirtir ve compare() yönteminde redisTemplate ile stringRedisTemplate'in aynı nesne olup olmadığını karşılaştırır. Birim test sınıfını çalıştırın, test sonuçları aşağıdaki gibidir:
2018-08-10 18:30:57.075 - Demo1ApplicationTests 15.58 saniyede başladı (JVM 16.974 saniyede çalışıyor) 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 - Eşit(): doğru sonucu 2018-08-10 18:30:57.364 - redisTemplate ile stringRedisTemplate'in karşılaştırma sonucu doğrudur Test sonuçları, redisTemplate ve stringRedisTemplate'in aynı nesne olduğunu gösteriyor. Bir dakika bekle... Bu sefer RedisTemplate enjekte edilirken K ve V'nin String olduğunu belirtmek neden yanlış değil? Ayrıca, iki nesne aynı nesne çıktı. StringRedisTemplate'in kaynak koduna bir göz atalım.
Kaynak kodunu okuduktan sonra anladınız mı, çünkü StringRedisTemplate sınıfının ana sınıfı RedisTemplate< String, String> ve çekirdek varsayılan olarak singleton, ayrıca ikisi doğal olarak aynı nesne.
|