简要说明:今天遇到这个问题,百度了一下,发现网上全部是结论,并没有找到分析原因的文章,因此决定自己尝试写一下自己的分析过程。如有不对的欢迎留言讨论。
背景描述:今天在写一个小例子的时候,new一个被注解修饰的类,发现该类被注解修饰的属性为null。即
redisTemplate为null。
@Component
public class Threada implements Runnable{
@Autowired
RedisTemplate redisTemplate;
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public void run() {
while(true) {
if (redisTemplate.opsForValue().setIfAbsent("count:key", "1", 1000, TimeUnit.SECONDS)) {
for (int i = 0; i < 1000; ++i) {
count++;
}
redisTemplate.delete("count:key");
break;
}
}
}
}
猜想1:是不是在启动项目的时候,该注解没有扫描到导致该属性没有被注入?于是做出下面测试,在启动的打印一下spring容易中是否有redisTemplate对象。发现有点,那说明注解被扫描到了。
@SpringBootApplication(scanBasePackages = "com.redis.redis")
public class RedisApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(RedisApplication.class, args);
String[] beanNames = ctx.getBeanDefinitionNames();
for (String str : beanNames) {
if(str.equals("redisTemplate")) {
System.out.println(str);
}
}
}
}
猜想2:现在的问题就是new的对象属性为空,但是在spring容器中存在该对象。于是猜想是不是自己new了对象之后,导致spring容器中的对象被free掉了。
对于这个猜想,想到的测试方法是,sping启动之后,我在new一个Threada对象,看一下spring容器中是否存在threada对象以及redisTemplate对象。
结果发现spring容器中还是存在该对象,猜想2也不成立。
猜想3:spring容器的bean和我new对象会不会不是同一个对象?答案是肯定的,而我之前一直没想到的原因是,想到spring容器的bean都是单例的。于是做了下面测试。
发现打印的地址不同,也就证实了猜想3.假如:spring容器中的threada对象我们称为threada1,而我手动new的对象称为thread2.thread1是在springBoot启动时被加载到spring容器中的,那threada1的属性redisTemplate也是由spring加载的,因此redisTemplate在spring容器中存在。但是threada2是被手动new的,那threada2的创建过程是没有spring参与的,即threada2的redisTemplate应该是在new的时候,再手动创建才行,否则我们只是new了thread2而redisTemplate为null。就比如java对象数组,我们只是new了数组,而数组中的对象没有创建的。
废话了一堆:简单来说就是new的对象和spring容器的对象在jvm中是两个对象,互不影响。