Recently, RedisTemplate was used during project development, and unit testing prompted "Field redisTemplate in com.example.demo1.dao.RedisDao required a bean of type 'org.springframework.data.redis.core.RedisTemplate' that could not be found", which translates to "could not find a bean of type RedisTemplate". Of course, looking at this sentence alone, we cannot be sure why this problem occurs. Now, post a detailed error log.
2018-08-10 14:53:49.761 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@5af3afd9] to prepare test instance [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) at 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) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at 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) at 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) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisDao': Unsatisfied dependency expressed through field ' 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: expected at least 1 bean which qualifies as autowire candidate. 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) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) at 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 common frames omitted Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' available: expected at least 1 bean which qualifies as autowire candidate. 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 common frames omitted Seeing this large error log is a bit dizzy, in fact, we only need to look at the key error logs to locate the problem. The second Caused by in the error log prints the key error log:No qualifying bean of type ‘org.springframework.data.redis.core.RedisTemplate< java.lang.String, java.lang.Object>。
The author looks back at the code written and specifies the specific type when injecting RedisTemplate< K, V>.
According to the error log, check the code on line 1493 of the class DefaultListableBeanFactory, the source code is as follows:
These two methods show that no bean can be matched < RedisTemplate String, Object, >, so how to solve this problem? You may wish to use RedisTemplate< K, V> without specifying the specific type, and modify the code as follows:
Restart the service, no error is reported in the startup log, and the RedisTemplate injects the bean successfully. I wonder why RedisTemplate< String, Object> injecting beans fails. After thinking about it for a long time, I thought that RedisTemplate is automatically configured in the SpringBoot framework, and the default in the container is the instance of RedisTemplate. Thinking of this, you need to turn through the official website documents to see if there is any explanation in the official website documents. Sure enough, section 30.1.1 of the official documentation still explains RedisTemplate.
Official document address:https://docs.spring.io/spring-bo ... ference/htmlsingle/
If you add your own@Beanof any of the auto-configured types, it replaces the default (except in the case of RedisTemplate, when the exclusion is based on the bean name, redisTemplate, not its type). If you add your own bean for the auto-configuration type, it will replace the default one. My code seems to be fine, wait... This sentence in parentheses is the point. Translate a wave,Except in the case of RedisTemplate, when excluding based on the bean's name, not its type. The English is not very good, and it seems that the translation is not very smooth.
Now it seems to be understood that the RedisTemplate< String, Object > used @Autowired when injecting,@Autowired assembled by type by default。 In other words, if you want to get the beans > RedisTemplate< String, Object, you need to assemble them according to their names. Then naturally think of using it@Resource, it is assembled by default according to the name。 Modify the code again as follows:
The annotation has been changed from @Autowired to @Resource The project started without error, and it was perfectly solved!
Restart the service again, the startup log does not report an error, and the RedisTemplate< String, Object> inject the bean successfully. Through this error, I learned a feature of the auto-configuration class in the SpringBoot framework. At the same time, it also reflects that learning a technology should start from the official website to avoid stepping on the pit. In the actual development process, using RedisTemplate< K, V> does not require specifying the type of K and V, and the default bean can meet the requirements.
Finally, I want to verify a small problem, and modify the code again as follows:
The above code specifies that K and V are both String types when injecting RedisTemplate, and compares whether redisTemplate and stringRedisTemplate are the same object in the compare() method. Run the unit test class, and the test results are as follows:
2018-08-10 18:30:57.075 - Started Demo1ApplicationTests in 15.58 seconds (JVM running for 16.974) 2018-08-10 18:30:57.360 - hashcode:1996087296 for redisTemplate 2018-08-10 18:30:57.360 - stringRedisTemplate hashcode:1996087296 2018-08-10 18:30:57.363 - Result of equal(): true 2018-08-10 18:30:57.364 - Comparison result of redisTemplate and stringRedisTemplate: true The test results show that redisTemplate and stringRedisTemplate are the same object. Wait a minute... Why is it not wrong to specify that K and V are Strings when injecting RedisTemplate this time? Moreover, the two objects turned out to be the same object. Let's take a look at the source code of StringRedisTemplate.
After reading the source code, do you understand, because the parent class of the StringRedisTemplate class is RedisTemplate< String, String>, and the bean is singleton by default, and the two are naturally the same object.
|