在使用SpringBoot写一个异步定时器调用时发现了一个问题。即对于相同的对象使用不同的入参进行调用。
但发现其中有一个异步进程一直没有得到调用。经过分析,发现SpringBoot @Autowired有一个隐藏的信息,他是默认单例执行的。
所以对于2个进程中的laserService实例,实际上使用的是相同的对象
@Autowired
LaserService laserService;
@Async
@Scheduled(cron = "0 5 * * * ?")
public void scheduled(){
String host = "1.1.1.1";
boolean result = laserService.Update(host);
}
@Async
@Scheduled(cron = "0 5 * * * ?")
public void scheduled2(){
String host = "2.2.2.2";
boolean result = laserService.Update(host);
}
参考https://blog.youkuaiyun.com/baidu_36528788/article/details/81237922
需要使用getBean的方式进行多例
@Scope("prototype")的正确用法——解决Bean的多例问题 - adaandy - 博客园
@Scope("prototype")的正确用法——解决Bean的多例问题 - 简书
最后参考上述文章,由于我是定时任务,未使用controller,所以直接在Impl层的class上增加@Scope("prototype"),并在TimerUtils调用时使用getBean模式:
LaserService laserservice1 = SpringBeanUtil.getBean(LaserService.class);
boolean result = laserservice1.UpdateOdps(host);
新增一个getBean的class
package com.net.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringBeanUtil implements ApplicationContextAware {
/**
* 上下文对象实例
*/
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 获取applicationContext
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通过name获取 Bean.
*
* @param name
* @return
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通过class获取Bean.
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过name,以及Clazz返回指定的Bean
*
* @param name
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
另一种更简洁的方法是:放弃注解。直接将class作为类进行调用 直接new Impl
但这种方式会导致其他@Autowired注解失效。
原因不明。
怀疑为创建新的实例时,引用了相同的单例子实例存在冲突