この記事は機械翻訳のミラー記事です。元の記事にジャンプするにはこちらをクリックしてください。

眺める: 15336|答える: 0

[出典] 例外はSpringBootにRedisTemplateインスタンスを注入することで解決されます

[リンクをコピー]
掲載地 2019/03/11 13:25:56 | | | |
最近では、プロジェクト開発時に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>で、ビーンはデフォルトでシングルトンであり、両者は自然に同じオブジェクトだからです。




先の:値型「System.Decimal」へのキャストは失敗しました...
次に:エラー:名前の「stringRedisTemplate」でビーンを生成し、...に定義されています。
免責事項:
Code Farmer Networkが発行するすべてのソフトウェア、プログラミング資料、記事は学習および研究目的のみを目的としています。 上記の内容は商業的または違法な目的で使用されてはならず、そうでなければ利用者はすべての結果を負うことになります。 このサイトの情報はインターネットからのものであり、著作権紛争はこのサイトとは関係ありません。 ダウンロード後24時間以内に上記の内容を完全にパソコンから削除してください。 もしこのプログラムを気に入ったら、正規のソフトウェアを支持し、登録を購入し、より良い本物のサービスを受けてください。 もし侵害があれば、メールでご連絡ください。

Mail To:help@itsvse.com