下面的代码出现一种意想不到的情况,RestButton是单例,RestDao是多例,按照常识,RestButton注入成功后,RestDao也会是固定的bean,不会变。
但是下面的代码出现的情况是,在高并发情况下,偶发出现 restDao.setHost方法执行完后,restDao.getHost()获取为null
@Scope("prototype")
@Repository
public class RestDao implements InitializingBean {
private String host;
private String serviceName;
private static final Logger logger = LoggerFactory.getLogger(RestDao.class);
public void invoke(String action, String method, JSONObject param) {
StringBuilder url = new StringBuilder();
String host1 = getHost();
url.append(ConfigUtil.getNetworkProtocol() + "://").append(host1).append("/").append(getServiceName()).append(method);
String str = url.toString();
logger.info("this:{} host:{} url:{}", this, host1, str);
}
public String getHost() {
logger.info("this:{} target host:{}", this, host);
return host; // host存在为null的情况
}
public void setHost(String host) {
this.host = host;
logger.info("this:{} param host:{} result host:{}", this, host, this.host);
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
@Override
public void afterPropertiesSet() throws Exception {
logger.info("this:{} afterPropertiesSet", this);
}
}
@Component
@Path("/button")
public class RestButton {
@Autowired
private RestDao restDao;
private static final Logger logger = LoggerFactory.getLogger(RestButton.class);
@GET
@Path("/getPageButtonAuth")
@Produces(MediaType.APPLICATION_JSON)
public Object getPageButtonAuth(@QueryParam("paramInfo") String paramInfoStr) {
logger.info("RestButton:{} restDao:{}", this, restDao);
String aasHost = ConfigUtil.getAasHost();
String aasRestServiceName = ConfigUtil.getAasRestServiceName();
logger.info("aasHost:{} aasRestServiceName:{}", aasHost, aasRestServiceName);
restDao.setHost(aasHost);
restDao.setServiceName(aasRestServiceName);
logger.info("aasHost1:{} aasRestServiceName1:{}", restDao.getHost(), restDao.getServiceName());
return null;
}
排查方式,断点
logger.info("this:{} afterPropertiesSet", this);
这行代码,只有当RestDao再次初始化的时候才会被断点到,当断点后发现看不到堆栈,在Debugger中输入
Thread.currentThread().getStackTrace()
来观察堆栈情况,发现是源头jersey触发的,那么这时候我想的是原因是不是来源于jersey,为了验证,我把jersey改成Spring Controller来调用,结果问题没有出现,果然是jersey导致的,但是不清楚为什么jersey会出现这种结果,要么是jersey的BUG,要么是jersey的什么配置没有配(求指教)。
解决方案:将RestButton改成多例,这样RestButton不会被复用,RestDao也就不会被重新初始化而被覆盖。