版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
你設(shè)計(jì)的服務(wù)是“微”服務(wù)還是“?!狈?wù)微服務(wù)技術(shù)架構(gòu)設(shè)計(jì)最佳實(shí)踐
架構(gòu)的演變過程經(jīng)歷了從單體架構(gòu)、SOA架構(gòu)、微服務(wù)架構(gòu),再進(jìn)入容器化,如今又流行無服務(wù)架構(gòu),雖然架構(gòu)在逐步在升級,但是隨著業(yè)務(wù)量的發(fā)展會發(fā)現(xiàn)版本迭代頻率會逐步頻繁,隨之而引發(fā)的代碼沖突、模塊耦合問題似乎并沒有減少。既然都已經(jīng)是微服務(wù)架構(gòu)了,怎么還是會出現(xiàn)這樣的問題呢?架構(gòu)師們宣導(dǎo)的微服務(wù)的優(yōu)勢不是已經(jīng)解決了這些問題嗎?為什么微服務(wù)的這些優(yōu)勢在項(xiàng)目中并沒有很好的體現(xiàn)出來呢?以下是在實(shí)際工作中遇到若干真實(shí)案例,我們看看微服務(wù)是否真的解決了所面臨的問題。一、多分支條件筆者從事的行業(yè)是為銀行提供金融科技服務(wù),實(shí)現(xiàn)銀行數(shù)字化轉(zhuǎn)型,與銀行對接過程中會高頻的和銀行的內(nèi)部系統(tǒng)交互的情況,系統(tǒng)與系統(tǒng)之間是通過ESB的方式來通訊。架構(gòu)設(shè)計(jì)思路為了屏蔽業(yè)務(wù)系統(tǒng)和ESB的耦合,獨(dú)立了銀行網(wǎng)關(guān)服務(wù),目的是將RPC請求換為ESB請求。同時業(yè)務(wù)系統(tǒng)自身也會暴露ESB服務(wù)給合作伙伴調(diào)用以及行內(nèi)業(yè)務(wù)系統(tǒng)異步回調(diào)。整體架構(gòu)如下圖所示:隨著項(xiàng)目逐步推進(jìn),會發(fā)現(xiàn)銀行網(wǎng)關(guān)代碼沖突現(xiàn)象以及Bug出現(xiàn)頻率明顯提高。出現(xiàn)了因一個問題引發(fā)其他bug的現(xiàn)象,修復(fù)Bug的效率明顯降低,項(xiàng)目進(jìn)度明顯降低,通過深入分析后發(fā)現(xiàn)問題的根源出現(xiàn)在代碼層面。例如以下代碼,設(shè)計(jì)初衷是針對ESB給出不同的actionCode做不同的業(yè)務(wù)處理,而且項(xiàng)目初期接入的系統(tǒng)比較少,簡單的IF、ELSE判斷就能解決,隨著接入系統(tǒng)逐步變多,整個代碼變成不可控局面,相關(guān)代碼如下。StringnotifySystem(StringactionCode,StringrespBody){if(actionCode.equals("A01")){//業(yè)務(wù)邏輯處理return"";}elseif(actionCode.equals("A02")){//業(yè)務(wù)邏輯處理return"";}elseif(actionCode.equals("A03")){//業(yè)務(wù)邏輯處理return"";}elseif(actionCode.equals("A04")){//業(yè)務(wù)邏輯處理return"";}elseif(actionCode.equals("A05")){//業(yè)務(wù)邏輯處理return"";}return"";}當(dāng)項(xiàng)目進(jìn)入SIT階段時會發(fā)現(xiàn)這個通知類已經(jīng)出現(xiàn)N多個分支條件,會有一堆人同時在修改這份代碼,代碼被覆蓋、合并沖突、合并錯誤等問題高頻出現(xiàn)。此時你還敢說你的服務(wù)是“微”的嗎?那么,為什么采用了微服務(wù)架構(gòu)思想來設(shè)計(jì)系統(tǒng),而且服務(wù)劃分的也很合理,但是在編程階段“微服務(wù)”卻變成了“危服務(wù)”呢?事實(shí)上無論是單體架構(gòu)還是微服務(wù)架構(gòu),在進(jìn)入編碼階段需要關(guān)注開閉原則和單一原則這二大原則。開閉原則(對于擴(kuò)展是開放的,但是對于修改是封閉的):軟件實(shí)體(模塊、類、函數(shù)等)應(yīng)該可以擴(kuò)展,但是盡量不要做不必要的修改。單一原則(規(guī)定一個類應(yīng)該只有一個發(fā)生變化的原因):修改任何類型的分支邏輯代碼,都需要只改動當(dāng)前類的代碼。上述的例子其實(shí)就是一個非常典型的多分支處理場景,盡管使用微服務(wù)架構(gòu),而且設(shè)計(jì)了合理的服務(wù)拆分策略,但是并不能解決多分支判斷的情況。在開發(fā)過程中要求架構(gòu)師或者技術(shù)經(jīng)理能經(jīng)常性的審查代碼,一旦發(fā)現(xiàn)代碼變成不可控局面是,要求研發(fā)人員去盡早重構(gòu)代碼,把不可控變成可控。例如本例則可以通過策略方式來實(shí)現(xiàn)多分支的場景條件判斷,實(shí)現(xiàn)對修改關(guān)閉,對擴(kuò)展開放的設(shè)計(jì)思路。所謂策略模式簡單說分二步:1、定義一個接口,用來定義需要具體處理的方法2、定義一個Map來存放具體策略對象,其中key是對應(yīng)actionCode,value是具體的實(shí)現(xiàn)類策略模式實(shí)現(xiàn)方式如下:1、先定義接口ESBHandler,用來約束策略需要實(shí)現(xiàn)的方法publicinterfaceESBHandler{
StringhandlerESBRequest(Stringebsxml);
StringactionCode();}2、定義策略的具體內(nèi)容,假設(shè)支付通知的actionCode=A02,定義一個支付通知處理類PayNoticeHandler@ServicepublicclassPayNoticeHandlerimplementsESBHandler{@OverridepublicStringhandlerESBRequest(Stringebsxml){return"支持通知結(jié)果處理";}
@OverridepublicStringactionCode(){return"A02";}}假設(shè)用戶額度的actionCode=A01,定義一個額度變更處理類UserQuotaHandler@ServicepublicclassUserQuotaHandlerimplementsESBHandler{@OverridepublicStringhandlerESBRequest(Stringebsxml){return"用戶額度變動通知處理:"+ebsxml;}
@OverridepublicStringactionCode(){return"A01";}}3、目前框架已經(jīng)搭建完成,還需要定義一個Map用來存放acionCode和具體類的映射關(guān)系,因此再定義一個HandlerContext,用來存放映射關(guān)系,相關(guān)代碼如下:publicclassHandlerContext{
privateMap<String,ESBHandler>handlerMap=null;
publicHandlerContext(Map<String,ESBHandler>handlerMap){
this.handlerMap=handlerMap;}publicESBHandlergetHandler(Stringtype){if(type==null){thrownewBusinessException(101,"type參數(shù)不能為空");}ESBHandlerclazz=handlerMap.get(type);if(clazz==null){thrownewBusinessException(9999,"該類型沒有定義,請定義:"+type);}returnclazz;}}最后需要查詢ESBHandler接口所有的實(shí)現(xiàn)類,并將actionCode和具體類的映射關(guān)系放入HandlerContext。因此再定義HandlerProccessor,@ComponentpublicclassHandlerProccessorimplementsBeanFactoryPostProcessor{/***獲取接口ESBHandler的所有實(shí)現(xiàn)類,初始化HandlerContext,將其注冊到spring容器**@parambeanFactorybean工廠*@throwsBeansException*/@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{Map<String,ESBHandler>handlerMap=newHashMap<>();Map<String,ESBHandler>beanMaps=beanFactory.getBeansOfType(ESBHandler.class);beanMaps.forEach((name,bean)->{handlerMap.put(bean.actionCode(),bean);});HandlerContextcontext=newHandlerContext(handlerMap);//單例方式注入到Spring容器,目的是統(tǒng)一管控beanFactory.registerSingleton(HandlerContext.class.getName(),context);}
}最后,策略模式使用方式就比較簡單了,首先解析esb的報(bào)文獲取actionCode,其次根據(jù)actionCode查詢對應(yīng)的處理類,最后再調(diào)用具體的策略類。@AutowiredHandlerContextholderContext;@RequestMapping(value="/{code}",method=RequestMethod.GET)publicStringgetAction(@PathVariableStringesbxml){//解析esb報(bào)文,獲取actionCodeStringactionCode=getActonCode(esbxml);returnholderContext.getHandler(actionCode).handlerESBRequest(esbxml);}策略模式減少了各種分支條件的判斷,降低的程序的復(fù)雜度。那么在實(shí)際開發(fā)過程中是否遇到了有分支條件的就必須使用策略模式呢?這里沒有確定的答案,需要在編碼前有對當(dāng)前流程以及后續(xù)擴(kuò)展有預(yù)判。但是有一點(diǎn)可以肯定的是在編碼過程中使用設(shè)計(jì)模式,有利于架構(gòu)的清晰以及提高程序員的編碼水平。二、前后依賴校驗(yàn)的處理列舉一個用戶登錄的場景,用戶使用驗(yàn)證碼登錄APP,后端需要校驗(yàn)驗(yàn)證碼是否有效、是否是黑名單用戶、是否是常用設(shè)備…….等非常多的前置條件校驗(yàn),只有當(dāng)所有條件都滿足后才完成登錄,而且對于每項(xiàng)檢查的先后順序也有要求。下面的代碼是開發(fā)人員的具體實(shí)現(xiàn)方式,從功能實(shí)現(xiàn)角度來看這些代碼完全滿足業(yè)務(wù)要求,但是從可維護(hù)性角度來看,任何邏輯的變動都需要修改LoginService這個類,不滿足“開閉原則”的代碼要求。publicclassLoginService{
publicStringuserLogin(StringloginRequest){checkVerifyCode(loginRequest);checkIsBlackUser(loginRequest);checkCommonEquipment(loginRequest);//登錄邏輯處理return"login_success";}/***校驗(yàn)驗(yàn)證碼是否正確*@paramloginRequest*/publicvoidcheckVerifyCode(StringloginRequest){//業(yè)務(wù)邏輯處理thrownewBusinessException(1001,"驗(yàn)證碼錯誤,請重新輸入");}/***判斷用戶是否是黑名單用戶*@paramloginRequest*/publicvoidcheckIsBlackUser(StringloginRequest){//業(yè)務(wù)邏輯處理thrownewBusinessException(1002,"用戶身份異常,登錄失敗!");}/***常用設(shè)備登錄,若非常用設(shè)備則需要做身份核驗(yàn)*@paramloginRequest*/publicvoidcheckCommonEquipment(StringloginRequest){//業(yè)務(wù)邏輯處理thrownewBusinessException(1003,"非常用設(shè)備,需要先執(zhí)行身份核驗(yàn)!");}}面對這種需求和如此風(fēng)格的代碼,到底該不該去重構(gòu)以及如何重構(gòu),這是考察一個技術(shù)管理者的一道命題作文。重構(gòu)短期內(nèi)看不到效果,而且會增加人力投入,不重構(gòu)則是存在的一個隱性風(fēng)險(xiǎn)。在此也是建議每個技術(shù)人員應(yīng)該都有一份“極客”精神,將風(fēng)險(xiǎn)和問題盡早暴露盡早修復(fù)。面對如此多的判斷條件,當(dāng)然是使用設(shè)計(jì)模式才能讓代碼更優(yōu),而且在編碼設(shè)計(jì)過程中同樣需要遵循開閉原則和單一原則,本需求中開閉原則指增加新的判斷邏輯通過擴(kuò)展來實(shí)現(xiàn),而不用修改LoginService,單一原則是指每個擴(kuò)展的類只處理本身相關(guān)的邏輯。為此可以考慮使用責(zé)任鏈模式來重構(gòu)這段代碼,所有關(guān)聯(lián)的檢查條件都使用“鏈”的方式來串聯(lián)起來,每個“鏈”上的節(jié)點(diǎn)只完成獨(dú)立的事件,任何規(guī)則的調(diào)整都不會影響登錄主流程。責(zé)任鏈模式簡單來說分以下幾個步驟:1、創(chuàng)建抽象類,并定義抽象方法,在抽象類中以遞歸調(diào)用的方式來實(shí)現(xiàn)節(jié)點(diǎn)和節(jié)點(diǎn)之間首尾連接2、創(chuàng)建子類并實(shí)現(xiàn)抽象類中的方法3、創(chuàng)建鏈的初始化類,指定上下游對應(yīng)鏈的關(guān)系具體方式方式如下,首先創(chuàng)建抽象類AbstractCheckChainpublicabstractclassAbstractCheckChain{privateAbstractCheckChainnextChain;/***責(zé)任鏈的下一個對象*/publicvoidsetNextChain(AbstractCheckChainnextChain){this.nextChain=nextChain;}publicAbstractCheckChaingetNextChain(){returnnextChain;}/***核心點(diǎn),遞歸調(diào)用*@paramloginRequest*/publicvoiddoCheck(LoginRequestloginRequest){execCheck(loginRequest);if(getNextChain()!=null){getNextChain().doCheck(loginRequest);}return;}publicabstractvoidexecCheck(LoginRequestloginRequest);}其次,創(chuàng)建相關(guān)子類例如驗(yàn)證碼校驗(yàn),完成相關(guān)業(yè)務(wù)邏輯。@Component@Order(1)publicclassCheckVerifyCodeChainextendsAbstractCheckChain{@OverridepublicvoidexecCheck(LoginRequestloginRequest){System.out.println("驗(yàn)證碼校驗(yàn)");}}創(chuàng)建子類(黑名單校驗(yàn))@Component@Order(2)@Slf4jpublicclassCheckBlackUserChainextendsAbstractCheckChain{@OverridepublicvoidexecCheck(LoginRequestloginRequest){System.out.println("黑名單檢查");}}最后,初始化鏈路,各節(jié)點(diǎn)首尾相連接,實(shí)現(xiàn)“鏈”。@ComponentpublicclassLoginCheckService{
@AutowiredprivateList<AbstractCheckChain>abstractCheckChainList;privateAbstractCheckChainfirstChain;@PostConstructprivatevoidinitializeCheckChain(){for(inti=0;i<abstractCheckChainList.size();i++){if(i==0){firstChain=abstractCheckChainList.get(0);}else{AbstractCheckChaincurrentHander=abstractCheckChainList.get(i-1);AbstractCheckChainnextHander=abstractCheckChainList.get(i);currentHander.setNextChain(nextHander);}}}
publicStringcheck(LoginRequestloginRequest){//登錄前置判斷firstChain.doCheck(loginRequest);//登錄后的邏輯處理return"登錄成功";}}用戶登錄接口在執(zhí)行登錄前先執(zhí)行前置LoginCheckService#check方法即可。通過責(zé)任鏈模式重構(gòu)后代碼結(jié)構(gòu)非常清晰,各節(jié)點(diǎn)的責(zé)任明確,假設(shè)需要修改黑名單功能,則只需要調(diào)整CheckBlackUserChain即可,對主流程無影響。如要調(diào)整鏈執(zhí)行的前后順序,則只需調(diào)整@Order()接口對應(yīng)的值即可。若后續(xù)擴(kuò)展新的校驗(yàn)規(guī)則則直接繼承抽象類AbstractCheckChain即可。三、分庫后的多表關(guān)聯(lián)查詢服務(wù)拆分后分為用戶服務(wù)、產(chǎn)品服務(wù)、訂單服務(wù)等各種服務(wù),后臺管理系統(tǒng)查詢訂單后顯示需要用戶姓名、手機(jī)號碼、注冊時間、產(chǎn)品名稱、價格、購買數(shù)量,這就涉及到多表關(guān)聯(lián)查詢,但是對應(yīng)的數(shù)據(jù)都存在在各自獨(dú)立的數(shù)據(jù)庫,傳統(tǒng)的join方式關(guān)聯(lián)查詢模式已經(jīng)不能解決這種需求。正確處理的流程如下1、獲取當(dāng)前分頁記錄訂單記錄表2、當(dāng)前記錄根據(jù)用戶ID去重,獲取當(dāng)前頁的所有用戶3、根據(jù)當(dāng)前頁用戶ID的集合批量查詢用戶信息4、當(dāng)前記錄根據(jù)產(chǎn)品ID去重,獲取當(dāng)前頁的所有產(chǎn)品5、根據(jù)當(dāng)前頁產(chǎn)品ID的集合批量查詢產(chǎn)品信息6、將查詢結(jié)果組織成最終輸出的對象具體代碼實(shí)現(xiàn)方式很多中,在本例中我們?nèi)匀徊捎秘?zé)任鏈模式,將查詢出來的每個對象都丟到鏈中,各節(jié)點(diǎn)負(fù)責(zé)對鏈上對象進(jìn)行賦值。相關(guān)代碼如下1、定義抽象類AbstractOrderConvertChain,定義需要轉(zhuǎn)換的方法convert以及遞歸方法doConvertpublicabstractclassAbstractOrderConvertChain{
privateAbstractOrderConvertChainnextChain;/***責(zé)任鏈的下一個對象*/publicvoidsetNextChain(AbstractOrderConvertChainnextChain){this.nextChain=nextChain;}publicAbstractOrderConvertChaingetNextChain(){returnnextChain;}
publicvoiddoConvert(UserOrderDTOuserOrderDTO,UserOrderPOuserOrderPO,ChainContextcontext){convert(userOrderDTO,userOrderPO,context);if(this.getNextChain()!=null){this.getNextChain().doConvert(userOrderDTO,userOrderPO,context);}}
publicabstractvoidconvert(UserOrderDTOuserOrderDTO,UserOrderPOuserOrderPO,ChainContextcontext);}2、定義用戶信息轉(zhuǎn)化類UserInfoConvert@ComponentpublicclassUserInfoConvertextendsAbstractOrderConvertChain{@Overridepublicvoidconvert(UserOrderDTOuserOrderDTO,UserOrderPOuserOrderPO,ChainContextcontext){Map<String,UserPO>userMap=context.getUserPOList().stream().collect(Collectors.toMap(UserPO::getUserID,Function.identity(),(key1,key2)->key1));userOrderDTO.setUserName(userMap.get(userOrderPO.getUserID()).getUserName());userOrderDTO.setMobilePhone(userMap.get(userOrderPO.getUserID()).getMobilePhone());}}3、定義產(chǎn)品信息轉(zhuǎn)化率ProductInfoConvert@ComponentpublicclassProductInfoConvertextendsAbstractOrderConvertChain{@Overridepublicvoidconvert(UserOrderDTOuserOrderDTO,UserOrderPOuserOrderPO,ChainContextcontext){Map<String,ProductPO>productMap=context.getProductPOList().stream().collect(Collectors.toMap(ProductPO::getId,Function.identity(),(key1,key2)->key1));userOrderDTO.setProdctName(productMap.get(userOrderPO.getProductID())==null?"未知":productMap.get(userOrderPO.getProductID()).getProductName());}}4、定義鏈的初始化類UserOrderConvertChainService@ComponentpublicclassUserOrderConvertChainService{
@AutowiredprivateList<AbstractOrderConvertChain>abstractOrderConvertChainList;privateAbstractOrderConvertChainfirstChain;@PostConstructprivatevoidinitializeCheckChain(){for(inti=0;i<abstractOrderConvertChainList.size();i++){if(i==0){firstChain=abstractOrderConvertChainList.get(0);}else{AbstractOrderConvertChaincurrentHander=abstractOrderConvertChainList.get(i-1);AbstractOrderConvertChainnextHander=abstractOrderConvertChainList.get(i);currentHander.setNextChain(nextHander);}}}publicvoiddoConvert(UserOrderDTOuserOrderDTO,UserOrderPOuserOrderPO,ChainContextcontext){firstChain.doConvert(userOrderDTO,userOrderPO,context);}}最后在使用前需要先組織好查詢的對象,為了方便擴(kuò)展,定義了ChainContext類處理上下午關(guān)系。publicStringsearchUserOrderList(){List<UserOrderPO>searcResList=getUserOrderList();List<UserOrderDTO>userOrderDTOS=newArrayList<>();ChainContextcontext=newChainContext();context.setProductPOList(builderProduct(null));context.setUserPOList(builderUser(null));List<UserOrderDTO>userOrderDTOList=searcResList.stream().map(userOrderPO->{UserOrderDTOuserOrderDTO=newUserOrderDTO();userOrderConvertChainService.doConvert(userOrderDTO,userOrderPO,context);returnuserOrderDTO;}).collect(Collectors.toList());System.out.println(userOrderDTOList);return"";}這種分庫分表后的聚合查詢適合查詢頻率不高,查詢維度簡單的場景,如果查詢條件復(fù)雜,查詢頻率高,那這種方法就不合適。四、MQ解耦的補(bǔ)償措施在微服務(wù)架構(gòu)下,通常使用MQ(消息隊(duì)列)來解決服務(wù)之間的相互依賴,但是使用了MQ后業(yè)務(wù)一定能按預(yù)期完成完整的業(yè)務(wù)流嗎?在此列舉金融項(xiàng)目中用戶在線申請借款的一個業(yè)務(wù)場景。用戶通過APP或者微信小程序在線借款時需要用戶授權(quán)在線簽署合同,在線簽署合同會調(diào)用第三方有資質(zhì)的簽章公司,最終會形成一份PDF格式的合同。因?yàn)楹炚卤容^耗時,因此通過發(fā)送MQ消息方式驅(qū)動簽章服務(wù)完成簽章,并更新簽章狀態(tài)。相關(guān)偽代碼如下:publicvoidsignatureLoanApply1(StringorderDTO){//先發(fā)送MQ消息,發(fā)送成功后寫入簽章事件if(sendMQ(orderDTO)){//寫入簽章事件insertSignature(orderDTO);}return;}這段代碼從架構(gòu)角度來看,使用了MQ來解耦執(zhí)行耗時的事件。符合期望,但是在具體使用過程中卻出現(xiàn)了問題。假設(shè)MQ發(fā)送失敗了,簽章事件就不能正常寫入,這個對業(yè)務(wù)來說是不允許出現(xiàn)的異常。因此工程師又把流程重新調(diào)整,先插入數(shù)據(jù),再發(fā)起簽章流程,相關(guān)代碼如下:publicvoidsignatureLoanApply2(StringorderDTO){if(insertSignature(orderDTO)){sendMQ(orderDTO);}return;}先寫入簽章事件,寫入成功后再發(fā)MQ消息。綜合考慮方案2比方案一要好,但是方案2還是缺少了消息補(bǔ)償機(jī)制。若簽章服務(wù)收到MQ消息后調(diào)用第三方服務(wù)執(zhí)行簽章失敗,若已達(dá)到MQ的重試次數(shù),那么這個消息就進(jìn)入死信隊(duì)列。因此需要使用定時任務(wù)去定期掃描未完成簽章的事件,再次發(fā)送MQ消息。最終在項(xiàng)目中定下一條鐵律“使用MQ的場景一定需要有補(bǔ)償機(jī)制來確認(rèn)最終結(jié)果”。五、數(shù)據(jù)一致性分布式架構(gòu)下因數(shù)據(jù)不一致性所引發(fā)的問題會逐步增多,稍有不慎就會出現(xiàn)系統(tǒng)之間的異常導(dǎo)致各種問題出現(xiàn),大多數(shù)情況下研發(fā)人員在編碼過程中都不會發(fā)現(xiàn)潛在的風(fēng)險(xiǎn)。筆者所在研發(fā)團(tuán)隊(duì)曾經(jīng)為未某銀行開發(fā)了一套存款理財(cái)系統(tǒng),其流程是用戶先
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026河南益民控股招聘9人備考題庫及完整答案詳解1套
- 2026年薪酬體系科學(xué)設(shè)計(jì)實(shí)戰(zhàn)課程
- 2026河南安陽市直機(jī)關(guān)遴選公務(wù)員3人備考題庫(安陽市檢察院遴選3名)及答案詳解(新)
- 四川省成都市第十一中學(xué)2026年1月儲備教師招聘備考題庫及完整答案詳解一套
- 露營地水電供應(yīng)與使用管理手冊
- 2026福建福州市志愿者聯(lián)合會專職工作人員(勞務(wù)派遣)招聘3人備考題庫完整答案詳解
- 2026年氫能產(chǎn)業(yè)鏈發(fā)展實(shí)務(wù)指南
- 2026年食品安全快速檢測技術(shù)課程
- 化工行業(yè)2026年度策略報(bào)告:成長與分紅并重價值再發(fā)現(xiàn)
- 職業(yè)噪聲與阻塞性睡眠呼吸暫停關(guān)聯(lián)研究
- 危險(xiǎn)化學(xué)品安全法解讀
- 廣東省佛山市南海區(qū)2025-2026學(xué)年上學(xué)期期末八年級數(shù)學(xué)試卷(含答案)
- 放射應(yīng)急演練及培訓(xùn)制度
- 儲能技術(shù)培訓(xùn)課件模板
- 2026元旦主題班會:馬年猜猜樂新春祝福版 教學(xué)課件
- 光伏收購合同范本
- 2025海洋水下機(jī)器人控制系統(tǒng)行業(yè)市場需求及發(fā)展趨勢分析投資評估規(guī)劃報(bào)告
- 物流金融管理培訓(xùn)課件
- 微專題:突破語病題+2026屆高考語文二輪復(fù)習(xí)
- 羽毛球裁判二級考試題庫及答案
- 醫(yī)院安全教育與培訓(xùn)課件
評論
0/150
提交評論