這周在項目中遇到這樣一個Bug,代碼大致是這樣的,有一個LogEntity日志類,里面有一個InnerLog負責存儲每次請求的RPCInfo相關信息,
每次請求的時候會把RPC相關信息加入到InnerLog中。
public class LogEntity {
public LogEntity() {
}
private InnerLog inner = new InnerLog();
public void addRpcInfo(RpcInfo rpcInfo) {
if (gene == null) {
initRpcGene();
}
if (rpcInfo.getRpctype() != null) {
if (StringUtils.isBlank(rpcInfo.getRpcid())) {
rpcInfo.setRpcid(gene.genRpcId());
}
inner.getInnerinfo().add(rpcInfo);
}
}
}
然后在Controller中,注入LogEntity,記錄日志信息。
@RestController
@RequestMapping("/v")
public class VideoController extends BaseController {
@Autowired
public VideoService videoService;
@Autowired
LogEntity logEntity;
@Override
@RequestMapping(value = "/search", method = RequestMethod.GET)
public Response search(Request request) {
long start = System.currentTimeMillis();
logEntity.put(LogConst.STARTTIMESTAMP, String.valueOf(start));
......
......
logEntity.logging(logger);
}
}
然后在壓測的時候發現日志很快就到幾十個G了。排查發現第二次請求時候的InnerLog中也包括第一次的InnerLog信息。這說明第二次請求和第一次請求
的時候用的是一個LogEntity實例。因此,想到這應該是注入的問題。因為對SpringBoot研究不是很深入,只是會簡單的實用。因此,對一些性質還不是很
了解。查閱資料發現,注入的Bean是有范圍可選的,默認的范圍是Singleton,也就是容器中只有一個Bean實例。接下來,詳細的看看Bean都有那幾類范
圍:
(1)singleton: 表示在spring容器中的單例,通過spring容器獲得該bean時總是返回唯一的實例
(2)prototype:表示每次獲得bean都會生成一個新的對象
(3)request:表示在一次http請求內有效(只適用於web應用)
(4)session:表示在一個用戶會話內有效(只適用於web應用)
(5)globalSession:表示在全局會話內有效(只適用於web應用)
在多數情況,我們只會使用singleton和prototype兩種scope,如果未指定scope屬性,默認為singleton。
因此,針對這個問題,我們可以再LogEntity類上加上@Scope("prototype")注解,問題就解決了。也可以不改變LogEntity的范圍,不過每次請求的時候新建
一個InnerLog就好了。