|
|
Опубліковано 11.03.2019 13:25:56
|
|
|
|

Нещодавно під час розробки проєкту використовували RedisTemplate, і модульне тестування викликало запит «Field redisTemplate in 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.run(ParentRunner.java:290) на org.junit.runners.ParentRunner$1.розклад(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) на org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) на org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) на org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) на 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.abstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) на org.springframework.beans.factory.support.abstractBeanFactory.getBean(AbstractBeanFactory.java:197) на 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 поширені кадри пропущені Бачити цей великий журнал помилок трохи запаморочливо, насправді нам достатньо лише подивитися на журнали ключових помилок, щоб знайти проблему. Другий Causeed by у журналі помилок друкує журнал ключових помилок:No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
Автор переглядає написаний код і вказує конкретний тип при впровадженні RedisTemplate< K, V>.
Згідно з журналом помилок, перевірте код у рядку 1493 класу DefaultListableBeanFactory, вихідний код виглядає так:
Ці два методи показують, що жоден боб не може бути зіставлений < рядком, об'єктом > RedisTemplate, то як вирішити цю проблему? Ви можете використовувати 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, коли виключення базується на назві bean — RedisTemplate, а не на типі). Якщо додати власне зерно для типу автоматичної конфігурації, воно замінить стандартне. Мій код здається в порядку, зачекай... Це речення в дужках — і є суть. Перекладіть хвилю,За винятком випадку RedisTemplate, коли виключають за назвою зерна, а не за типом. Англійська не дуже хороша, і, здається, переклад не дуже плавний.
Тепер, здається, зрозуміло, що RedisTemplate< рядок, об'єкт > використовувався @Autowired при ін'єкції,@Autowired за замовчуванням збирається за типом。 Інакше кажучи, якщо ви хочете отримати зерна > RedisTemplate< String, Object, вам потрібно зібрати їх відповідно до їхніх назв. Потім природно подумайте про використання@Resource він збирається за замовчуванням відповідно до назви。 Змініть код ще раз наступним чином:
Анотація була змінена з @Autowired на @Resource Проєкт почався без помилок і був ідеально вирішений!
Перезапустіть сервіс знову, журнал запуску не повідомляє про помилку, і RedisTemplate< рядок, об'єкт> успішно вводять bean. Через цю помилку я дізнався функцію класу автоконфігурації у фреймворку SpringBoot. Водночас це свідчить про те, що вивчення технології має починатися з офіційного сайту, щоб не наступати на яму. У самому процесі розробки, за допомогою RedisTemplate< K, V> не вимагає вказівки типу K і V, і стандартний bean може відповідати вимогам.
Нарешті, я хочу перевірити невелику проблему і знову змінити код наступним чином:
Вищенаведений код визначає, що K і V є типами рядків при впровадженні RedisTemplate, і порівнює, чи є redisTemplate і stringRedisTemplate одним і тим самим об'єктом у методі compare(). Запустіть клас модульного тестування, і результати тесту такі:
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 - Результат рівномірно(): true 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', визначеним у...
|