Тази статия е огледална статия за машинен превод, моля, кликнете тук, за да преминете към оригиналната статия.

Изглед: 15336|Отговор: 0

[Източник] Изключението се решава чрез инжектиране на инстанцията RedisTemplate в SpringBoot

[Копирай линк]
Публикувано в 11.03.2019 г. 13:25:56 ч. | | | |
Напоследък RedisTemplate беше използван при разработка на проекта, а unit testing предизвика "Field redisTemplate в com.example.demo1.dao.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
    на org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    на org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
    на org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
    на org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
    на org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
    на org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
    на org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
    на org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    на org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
    на org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
    на org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    на org.junit.runners.ParentRunner$3.бягай(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)
    на org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    на org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    на org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    на org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    на org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    на 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)
    на 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'; Вложено изключение е org.springframework.beans.factory.NoSuchBeanDefinitionException: Няма квалифициращо bean от типа 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' Налично: очаква се поне 1 боб, който отговаря на условията за Autowire кандидат. Зависимости анотации: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    на org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
    на org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    на org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
    на org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.populateBeanBean(AbstractAutowireCapableBeanFactory.java:1264)
    на org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    на org.springframework.beans.factory.support.abstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    на org.springframework.beans.factory.support.abstractBeanBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    на org.springframework.beans.factory.support.abstractBeanBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    на org.springframework.beans.factory.support.abstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    на 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)
    на org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
    на org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
    на org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    на org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 25 често използвани рамки са пропуснати
Причинено от: org.springframework.beans.factory.NoSuchBeanDefinitionException: Няма квалифициращ боб от типа 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' Налично: очаква се поне 1 боб, който отговаря на условията за Autowire кандидат. Зависимости анотации: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    на org.springframework.beans.factory.support.defaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
    на org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
    на org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    на org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
    ... 43 често използвани рамки, пропуснати
Виждането на този голям лог с грешки е малко замайващо, всъщност трябва само да разгледаме логовете за ключови грешки, за да открием проблема. Вторият Причинен от в лога за грешки отпечатва лог за ключови грешки:No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。

Авторът преглежда написания код и уточнява конкретния тип при инжектиране на RedisTemplate< K, V>.


Според лога за грешки, проверете кода на ред 1493 от класа DefaultListableBeanFactory, изходният код е следният:

Тези два метода показват, че няма зърно < RedisTemplate String, Object >, така че как да се реши този проблем? Може да пожелаете да използвате RedisTemplate< K, V> без да уточнявате конкретния тип и да модифицирате кода по следния начин:

Рестартирайте услугата, в лога за стартиране не се докладва грешка и RedisTemplate успешно инжектира bean. Чудя се защо RedisTemplate< String, Object> инжектирането на зърна се проваля. След дълго мислене, реших, че RedisTemplate е автоматично конфигуриран във фреймуърка на SpringBoot, а по подразбиране в контейнера е инстанцията на RedisTemplate. Като мислите за това, трябва да прегледате официалните документи на уебсайта, за да видите дали има някакво обяснение в официалните документи. И наистина, раздел 30.1.1 от официалната документация все още обяснява RedisTemplate.

Официален адрес на документа:https://docs.spring.io/spring-bo ... ference/htmlsingle/




Ако добавиш свой собствен@Beanна всеки от автоматично конфигурираните типове, той замества стандартния (с изключение на случая с RedisTemplate, когато изключването се базира на името на зърното, RedisTemplate, а не на неговия тип).
Ако добавиш свой собствен боб за типа автоматична конфигурация, той ще замени стандартния. Кодът ми изглежда наред, чакай... Това изречение в скоби е смисълът. Преведи вълна,С изключение на случая с RedisTemplate, когато се изключва въз основа на името на зърното, а не на типа. Английският не е много добър, а изглежда, че преводът не е много гладък.

Сега изглежда се разбира, че RedisTemplate< String, Object > се използва @Autowired при инжектиране,@Autowired по подразбиране се сглобява по тип。 С други думи, ако искате да получите зърната > RedisTemplate< String, Object, трябва да ги сглобите според имената им. После естествено помисли да го използваш@Resource, тя се сглобява по подразбиране според името。 Модифицирайте кода отново по следния начин:


Анотацията е променена от @Autowired на @Resource Проектът започна без грешка и беше перфектно решен!

Рестартирайте услугата, логът за стартиране не докладва грешка, а RedisTemplate< String, Object> успешно инжектират bean. Чрез тази грешка научих функция на класа за автоматична конфигурация във фреймуърка SpringBoot. В същото време това показва, че научаването на технология трябва да започне от официалния уебсайт, за да не стъпвате в яма.
В самия процес на разработка, използвайки RedisTemplate< K, V> не изисква посочване на типа K и V, а стандартният боб може да отговаря на изискванията.

Накрая искам да проверя малък проблем и да модифицирам кода отново по следния начин:


Горният код уточнява, че K и V са и двата типа String при инжектиране на RedisTemplate и сравнява дали redisTemplate и stringRedisTemplate са един и същ обект в метода compare(). Пуснете класа за unit test и резултатите от теста са следните:

2018-08-10 18:30:57.075 - Започнах Demo1ApplicationTests за 15.58 секунди (JVM работи за 16.974)
2018-08-10 18:30:57.360 - хашкод:1996087296 за redisTemplate
2018-08-10 18:30:57.360 - stringRedisTemplate хашкод:1996087296
2018-08-10 18:30:57.363 - Резултат на равенство(): вярно
2018-08-10 18:30:57.364 - Резултат от сравнение на redisTemplate и stringRedisTemplate: true
Резултатите от теста показват, че redisTemplate и stringRedisTemplate са един и същ обект. Една минута... Защо не е грешно този път да се уточни, че K и V са низове при инжектиране на RedisTemplate? Освен това двата обекта се оказаха един и същ обект. Нека разгледаме изходния код на StringRedisTemplate.

След като прочетохте изходния код, разбирате ли, защото родителският клас на класа StringRedisTemplate е RedisTemplate< String, String> а bean е singleton по подразбиране, и двата естествено са един и същ обект.




Предишен:Кръстване на стойност тип "System.Decimal" не успя...
Следващ:Грешка при създаване на боб с име 'stringRedisTemplate', дефинирано в...
Отричане:
Целият софтуер, програмни материали или статии, публикувани от Code Farmer Network, са само за учебни и изследователски цели; Горното съдържание не трябва да се използва за търговски или незаконни цели, в противен случай потребителите ще понесат всички последствия. Информацията на този сайт идва от интернет, а споровете за авторски права нямат нищо общо с този сайт. Трябва напълно да изтриете горното съдържание от компютъра си в рамките на 24 часа след изтеглянето. Ако ви харесва програмата, моля, подкрепете оригинален софтуер, купете регистрация и получете по-добри услуги. Ако има нарушение, моля, свържете се с нас по имейл.

Mail To:help@itsvse.com