1. 程式人生 > >spring建立多例

spring建立多例

最近遇到一個了問題,簡單的描述一下。
按模組呼叫介面,比如a、b、c、d四個模組每個模組2~3個介面,一筆交易最多四個模組,所以在呼叫時每個模組開啟一個執行緒。那麼問題來了模組執行緒在主執行緒中是通過註解自動注入的(模組執行緒依賴其他的bean,所以不能new),即模組執行緒單例的。
多執行緒環境下,把介面呼叫需要使用到的引數從主執行緒傳到模組執行緒時,雖然在主執行緒中每一次都new一個新的引數,但因為模組執行緒是單例的,所以會有可能產生髒讀的可能性(引數被其他執行緒覆蓋掉了)

明確了問題後,解決方案是什麼呢,當然對應的就是將單例的變成多例的。
通過上網查詢後在模組執行緒的類加上註解
@Scope("prototype")
但是加上這個註解後並沒有用(並不能多例),梳理了一下問題,當我在一個單例的類中通過@Autowired自動裝配時,並不能產生多例的,原因@Autowired自動裝配時,在spring容器中發現這個類的例項就會裝配進取,所以並沒有顯式的建立新的例項。所以並不能在單例中這樣建立多例。
//獲取Spring上下文
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
ThreadModuleA module_A = wac.getBean("threadModuleA", ThreadModuleA.class);

這是一種不依賴於servlet,不需要注入的方式。但是需要注意一點,在伺服器啟動時,Spring容器初始化時,不能通過以下方法獲取Spring 容器。
這樣的話就可以建立多例了。

下面簡單的放一下程式碼
主執行緒

reportBody = new ReportBody();
List<Task<ReportBody>> tasks = new ArrayList<Task<ReportBody>>(); Map<String, Object> map_report = new HashMap<String, Object>(); map_report.put("reportBody", reportBody); // Body //獲取Spring上下文 WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext
(); if(reportType.contains(CommonEnum.THEMIS_DATA_A.getCode())){ map_report.put("paramsMap_base", paramsMap_base); //獲取物件,此操作可以獲取多例物件(ThreadModuleA 需要配置@Scope("prototype")) ThreadModuleA module_A = wac.getBean("threadModuleA", ThreadModuleA.class); module_A.taskParams(map_report); tasks.add(module_A); } if(reportType.contains(CommonEnum.THEMIS_DATA_B.getCode())){ map_report.put("paramsMap_base", paramsMap_base); ThreadModuleB module_B = wac.getBean("threadModuleB", ThreadModuleB.class); module_B.taskParams(map_report); tasks.add(module_B); } if(reportType.contains(CommonEnum.THEMIS_DATA_C.getCode())) { map_report.put("paramsMap_C", paramsMap_base); ThreadModuleC module_C = wac.getBean("threadModuleC", ThreadModuleC.class); module_C.taskParams(map_report); tasks.add(module_C); } if(reportType.contains(CommonEnum.THEMIS_DATA_D.getCode())){ map_report.put("paramsMap_D", paramsMap_base); ThreadModuleD module_D = wac.getBean("threadModuleD", ThreadModuleD.class); module_D.taskParams(map_report); tasks.add(module_D); }

模組執行緒父類,賦值取值(其中Task繼承了Callable)

public abstract class RunTask<T> implements Task<T>{
    //傳入引數
    private Map<String, Object> params;

    @Override
    public void taskParams(Map<String, Object> params) {
        this.params = params;
    }

    public Map<String, Object> getParams() {
        return params;
    }

}

模組執行緒

@Component
@Scope(“prototype”)
public class ThreadModuleA extends RunTask{

// 日誌
private static Logger logger = LoggerFactory.getLogger(ThreadModuleA.class);

@Override
public ReportBody call() throws Exception {
    // 初始化非同步呼叫所需資訊
    //獲取引數
    Map<String, Object> map = this.getParams();

    return reportBody;
}

}