最近では、プロジェクト開発時にRedisTemplateが使用され、ユニットテストでは「com.example.demo1.dao.RedisDaoにredisTemplateをフィールドで入力する必要があります。RedisDaoは型のビーン('org.springframework.data.redis.core.RedisTemplate)」を必要としました。 「見つからなかった」と訳され、これは「RedisTemplate型のビーンを見つけられなかった」という意味です。 もちろん、この文だけを見ても、なぜこの問題が起こるのかは確信が持てません。 さて、詳細なエラーログを投稿してください。
2018-08-10 14:53:49.761 - TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9]がテストを準備する際に例外が検出されました インスタンス [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) 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) org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 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) 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) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 原因:org.springframework.beans.factory.UnsatisfiedDependencyException: 'redisDao' という名前の豆を作成するエラー:フィールド ' で表現された未満足の依存関係 redisTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' available:Autowire候補として認められる少なくとも1本のビーンが期待されます。 Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) 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の共通フレームは省略されています 原因:org.springframework.beans.factory.NoSuchBeanDefinitionException: no qualifying bean 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' available:Autowire候補として認められる少なくとも1本のビーンが期待されます。 Dependency annotations: {@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個は省略されています この大きなエラーログを見るのは少し目が回る気がします。実際、問題を特定するために主要なエラーログを見れば十分です。 エラーログ内の2つ目のCause Byはキーエラーログを印刷します:型 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object> の限定豆はありません。
著者は書かれたコードを振り返り、RedisTemplateを注入する際<K、V>の具体的なタイプを指定します。
エラーログによると、クラスDefaultListableBeanFactoryの1493行目のコードを確認してください。ソースコードは以下の通りです:
これら2つの方法は、どのビーンもRedisTemplate String, Object, ><マッチングできないことを示しているので、この問題をどう解決すればいいのでしょうか? 具体的なタイプを指定せずにRedisTemplate<K, V>を使用し、以下のようにコードを修正したい場合があります。
サービスを再起動すると、起動ログにエラーは報告されず、RedisTemplateはビーンを正常に注入します。 なぜRedisTemplate<String、Object>Beansの注入が失敗するのか不思議です。 長い間考えた結果、RedisTemplateはSpringBootフレームワークで自動的に設定されており、コンテナのデフォルトはRedisTemplateのインスタンスだと思いました。 このことを考えると、公式ウェブサイトの文書に説明がないか確認する必要があります。 案の定、公式ドキュメントの30.1.1セクションにはRedisTemplateの説明が残っています。
公式文書宛先:https://docs.spring.io/spring-bo ... ference/htmlsingle/
自分のものを追加すると@Bean自動設定型のいずれかのうち、デフォルトを置き換えます(RedisTemplateの場合は除外がビーン名redisTemplateであって型別ではありません)。 自動設定タイプに自分でビーンを追加すれば、デフォルトのものに代わってきます。 コードは問題なさそうです、ちょっと待って... 括弧内のこの文がポイントです。 波を翻訳し、ただし、RedisTemplateの場合は、ビーンの名前に基づいて除外し、種類を除きます。 英語はあまり良くなく、翻訳もあまりスムーズではないようです。
現在では、RedisTemplate< String、オブジェクト > が注入時に@Autowired使われていることが理解されているようです。@Autowiredタイプごとにデフォルトで組み立てられます。 つまり、RedisTemplate<String、Object>豆を入手したいなら、名前に従って組み立てる必要があります。 そして自然と使うことを考えます@Resource、名前に従ってデフォルトで組み立てられています。 コードを再度修正します。
注釈が@Autowiredから@Resourceに変更されました。プロジェクトはエラーなく始まり、完璧に解決されました!
サービスを再度再起動しても、起動ログにエラーは報告されず、RedisTemplate<文字列、Object>がビーンを正常に注入します。 このエラーを通じて、SpringBootフレームワークの自動設定クラスの機能を学びました。 同時に、技術の学習は公式ウェブサイトから始めるべきで、穴を踏まないようにすることも反映しています。 実際の開発プロセスでは、RedisTemplate< K, V> を用いてKとVの種類を指定する必要がなく、デフォルトのビーンで要件を満たすことができます。
最後に、小さな問題を確認し、コードを以下のように再度修正したいと思います。
上記のコードでは、RedisTemplateを注入する際にKとVが両方のString型であることを明記し、compare()メソッドでredisTemplateとstringRedisTemplateが同一オブジェクトかどうかを比較します。 ユニットテストクラスを実行し、テスト結果は以下の通りです。
2018-08-10 18:30:57.075 - Demo1ApplicationTestsを15.58秒で開始(JVMは16.974秒で動作) 2018-08-10 18:30:57.360 - redisTemplate のhashcode:1996087296 2018-08-10 18:30:57.360 - stringRedisTemplate ハッシュコード:1996087296 2018-08-10 18:30:57.363 - 結果はequal(): true) 2018-08-10 18:30:57.364 - redisTemplateとstringRedisTemplateの比較結果RedisTemplate: trueです テスト結果では、redisTemplateとstringRedisTemplateは同一のオブジェクトであることが示されています。 ちょっと待ってください。。。 今回RedisTemplateを注入する際にKとVを文字列と指定するのはなぜ間違っていないのでしょうか? さらに、その二つの物体は同一の物体であることが判明しました。 StringRedisTemplateのソースコードを見ていきましょう。
ソースコードを読んで理解しましたか?StringRedisTemplateクラスの親クラスはRedisTemplate< String、String>で、ビーンはデフォルトでシングルトンであり、両者は自然に同じオブジェクトだからです。
|