Baru-baru ini, RedisTemplate digunakan selama pengembangan proyek, dan pengujian unit meminta "Field redisTemplate di com.example.demo1.dao.RedisDao memerlukan bean jenis 'org.springframework.data.redis.core.RedisTemplate' yang tidak dapat ditemukan", yang diterjemahkan menjadi "tidak dapat menemukan kacang jenis RedisTemplate". Tentu saja, melihat kalimat ini saja, kita tidak dapat memastikan mengapa masalah ini terjadi. Sekarang, posting log kesalahan terperinci.
2018-08-10 14:53:49.761 - Tertangkap pengecualian saat mengizinkan TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] untuk menyiapkan pengujian instance [com.example.demo1.Demo1ApplicationTests@2361365c]
java.lang.IllegalStateException: Failed to load ApplicationContext di org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) di org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) di org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) di org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131) di org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) di org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) di org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) di org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) di org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) di org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) di org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) di org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) di org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) di org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) di org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) di org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) di org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) di org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) di org.junit.runners.ParentRunner.run(ParentRunner.java:363) di org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) di org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) di org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) di org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) di org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) di org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) di org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Disebabkan oleh: org.springframework.beans.factory.UnsatisfiedDependencyException: Kesalahan membuat bean dengan nama 'redisDao': Dependensi yang tidak terpuas dinyatakan melalui bidang ' redisTemplate'; pengecualian berlapis adalah org.springframework.beans.factory.NoSuchBeanDefinitionException: Tidak ada bean yang memenuhi syarat dari jenis 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' tersedia: diharapkan setidaknya 1 kacang yang memenuhi syarat sebagai kandidat autowire. Anotasi dependensi: {@org.springframework.beans.factory.annotation.Autowired(required=true)} di org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) di org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) di org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) di org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) di org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) di org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) di org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) di org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) di org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) di org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) di org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) di org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) di org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) di org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) di org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) di org.springframework.boot.SpringApplication.run(SpringApplication.java:303) di org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) di org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) di org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) ... 25 bingkai umum dihilangkan Disebabkan oleh: org.springframework.beans.factory.NoSuchBeanDefinitionException: Tidak ada bean yang memenuhi syarat dari jenis 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' tersedia: diharapkan setidaknya 1 kacang yang memenuhi syarat sebagai kandidat autowire. Anotasi dependensi: {@org.springframework.beans.factory.annotation.Autowired(required=true)} di org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) di org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) di org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) di org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 43 bingkai umum dihilangkan Melihat log kesalahan besar ini agak pusing, nyatanya kita hanya perlu melihat log kesalahan utama untuk menemukan masalahnya. Yang kedua Disebabkan oleh dalam log kesalahan mencetak log kesalahan kunci:Tidak ada bean yang memenuhi syarat dari jenis 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
Penulis melihat kembali kode yang ditulis dan menentukan jenis spesifik saat menyuntikkan RedisTemplate< K, V>.
Menurut log kesalahan, periksa kode pada baris 1493 dari kelas DefaultListableBeanFactory, kode sumbernya adalah sebagai berikut:
Kedua metode ini menunjukkan bahwa tidak ada bean yang dapat dicocokkan < RedisTemplate String, Object, >, jadi bagaimana cara mengatasi masalah ini? Anda mungkin ingin menggunakan RedisTemplate< K, V> tanpa menentukan jenis tertentu, dan memodifikasi kode sebagai berikut:
Mulai ulang layanan, tidak ada kesalahan yang dilaporkan dalam log startup, dan RedisTemplate berhasil menyuntikkan bean. Saya bertanya-tanya mengapa RedisTemplate< String, Object> menyuntikkan kacang gagal. Setelah memikirkannya untuk waktu yang lama, saya pikir RedisTemplate secara otomatis dikonfigurasi dalam kerangka kerja SpringBoot, dan default dalam kontainer adalah instance RedisTemplate. Memikirkan hal ini, Anda perlu memeriksa-balik dokumen situs web resmi untuk melihat apakah ada penjelasan dalam dokumen situs web resmi. Benar saja, bagian 30.1.1 dari dokumentasi resmi masih menjelaskan RedisTemplate.
Alamat dokumen resmi:https://docs.spring.io/spring-bo ... ference/htmlsingle/
Jika Anda menambahkan sendiri@Beandari salah satu jenis yang dikonfigurasi secara otomatis, ini menggantikan default (kecuali dalam kasus RedisTemplate, ketika pengecualian didasarkan pada nama bean, redisTemplate, bukan jenisnya). Jika Anda menambahkan bean Anda sendiri untuk jenis konfigurasi otomatis, itu akan menggantikan yang default. Kode saya sepertinya baik-baik saja, tunggu ... Kalimat dalam tanda kurung ini adalah intinya. Menerjemahkan gelombang,Kecuali dalam kasus RedisTemplate, ketika mengecualikan berdasarkan nama kacang, bukan jenisnya. Bahasa Inggrisnya tidak terlalu bagus, dan tampaknya terjemahannya tidak terlalu halus.
Sekarang tampaknya dipahami bahwa RedisTemplate< String, Object > digunakan @Autowired saat menyuntikkan,@Autowired dirakit berdasarkan jenis secara default。 Dengan kata lain, jika Anda ingin mendapatkan kacang > RedisTemplate< String, Object, Anda perlu merakitnya sesuai dengan namanya. Kemudian secara alami berpikir untuk menggunakannya@Resource, itu dirakit secara default sesuai dengan namanya。 Ubah kode lagi sebagai berikut:
Anotasi telah diubah dari @Autowired menjadi @Resource Proyek dimulai tanpa kesalahan, dan terselesaikan dengan sempurna!
Mulai ulang layanan lagi, log startup tidak melaporkan kesalahan, dan RedisTemplate< String, Object> berhasil menyuntikkan bean. Melalui kesalahan ini, saya mempelajari fitur kelas konfigurasi otomatis di kerangka kerja SpringBoot. Pada saat yang sama, ini juga mencerminkan bahwa mempelajari teknologi harus dimulai dari situs web resmi untuk menghindari menginjak lubang. Dalam proses pengembangan yang sebenarnya, menggunakan RedisTemplate< K, V> tidak memerlukan menentukan jenis K dan V, dan bean default dapat memenuhi persyaratan.
Terakhir, saya ingin memverifikasi masalah kecil, dan memodifikasi kode lagi sebagai berikut:
Kode di atas menentukan bahwa K dan V adalah jenis String saat menyuntikkan RedisTemplate, dan membandingkan apakah redisTemplate dan stringRedisTemplate adalah objek yang sama dalam metode compare(). Jalankan kelas pengujian unit, dan hasil pengujiannya adalah sebagai berikut:
2018-08-10 18:30:57.075 - Memulai Demo1ApplicationTests dalam 15.58 detik (JVM berjalan selama 16.974) 2018-08-10 18:30:57.360 - hashcode:1996087296 untuk redisTemplate 2018-08-10 18:30:57.360 - stringRedisTemplate hashcode:1996087296 2018-08-10 18:30:57.363 - Hasil sama (): benar 2018-08-10 18:30:57.364 - Hasil perbandingan redisTemplate dan stringRedisTemplate: true Hasil pengujian menunjukkan bahwa redisTemplate dan stringRedisTemplate adalah objek yang sama. Tunggu sebentar... Mengapa tidak salah untuk menentukan bahwa K dan V adalah String saat menyuntikkan RedisTemplate kali ini? Apalagi kedua benda tersebut ternyata adalah objek yang sama. Mari kita lihat kode sumber StringRedisTemplate.
Setelah membaca kode sumber, apakah Anda mengerti, karena kelas induk dari kelas StringRedisTemplate adalah RedisTemplate< String, String>, dan bean adalah singleton secara default, dan keduanya secara alami adalah objek yang sama.
|