이 글은 기계 번역의 미러 문서이며, 원본 기사로 바로 이동하려면 여기를 클릭해 주세요.

보기: 15336|회답: 0

[출처] 이 예외는 SpringBoot에 RedisTemplate 인스턴스를 주입함으로써 해결됩니다

[링크 복사]
게시됨 2019. 3. 11. 오후 1: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)
    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)
    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)
    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)
    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'라는 이름의 bean 생성 오류: 필드 '를 통해 표현된 불만족 의존성 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>' 이용 가능: 자동 와이어 후보로 자격이 되는 최소 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)
    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)
    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: 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' 이용 가능: 자동 와이어 후보로 자격이 되는 최소 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개의 공통 프레임은 생략되었습니다
이렇게 큰 오류 로그를 보는 것은 다소 어지럽습니다. 사실 우리는 주요 오류 로그만 봐도 문제를 찾을 수 있습니다. 오류 로그의 두 번째 원인 기록은 주요 오류 로그를 출력합니다:'org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object> 같은 자격별 빈은 없습니다.

작성자는 작성된 코드를 다시 살펴보고 RedisTemplate< K, V>를 주입할 때 특정 타입을 지정합니다.


오류 로그에 따르면, DefaultListableBeanFactory 클래스의 1493행 코드를 확인해 보세요. 소스 코드는 다음과 같습니다:

이 두 방법은 어떤 빈도 RedisTemplate String, Object, > <매칭할 수 없다는 것을 보여주는데, 이 문제를 어떻게 해결할까요? 특정 타입을 지정하지 않고 RedisTemplate< K, V>를 사용하여 코드를 다음과 같이 수정할 수 있습니다:

서비스를 재시작하면 시작 로그에 오류가 보고되지 않고, RedisTemplate이 빈을 성공적으로 주입합니다. 왜 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>가 빈을 성공적으로 주입합니다. 이 오류를 통해 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 for hashcode:1996087296
2018-08-10 18:30:57.360 - strRedisTemplate 해시코드:1996087296
2018-08-10 18:30:57.363 - 결과가 같음(): true)
2018-08-10 18:30:57.364 - redisTemplate과 string 비교 결과RedisTemplate: true입니다
테스트 결과는 redisTemplate과 stringRedisTemplate이 동일한 객체임을 보여줍니다. 잠깐만 기다리세요... 이번에 RedisTemplate을 인젝트할 때 K와 V를 문자열로 지정하는 것이 왜 잘못된 게 아닌가요? 더불어, 두 물체는 동일한 물체임이 밝혀졌습니다. StringRedisTemplate의 소스 코드를 살펴보겠습니다.

소스 코드를 읽어보니, StringRedisTemplate 클래스의 부모 클래스는 RedisTemplate< String, String>이고, bean은 기본적으로 싱글톤이고, 두 클래스는 자연스럽게 같은 객체라는 점을 이해하셨나요?




이전의:값으로 캐스팅 타입 "System.Decimal" 실패...
다음:'threadRedisTemplate'이라는 이름의 빈 생성 오류, 정의된 이름은...
면책 조항:
Code Farmer Network에서 발행하는 모든 소프트웨어, 프로그래밍 자료 또는 기사는 학습 및 연구 목적으로만 사용됩니다; 위 내용은 상업적 또는 불법적인 목적으로 사용되지 않으며, 그렇지 않으면 모든 책임이 사용자에게 부담됩니다. 이 사이트의 정보는 인터넷에서 가져온 것이며, 저작권 분쟁은 이 사이트와는 관련이 없습니다. 위 내용은 다운로드 후 24시간 이내에 컴퓨터에서 완전히 삭제해야 합니다. 프로그램이 마음에 드신다면, 진짜 소프트웨어를 지원하고, 등록을 구매하며, 더 나은 진짜 서비스를 받아주세요. 침해가 있을 경우 이메일로 연락해 주시기 바랍니다.

Mail To:help@itsvse.com