使用jersey单例的接口注入多例的Spring bean,导致bean偶发性被替换掉

下面的代码出现一种意想不到的情况,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也就不会被重新初始化而被覆盖。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容