女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

系統完成熱部署,并切換該接口的實現

Android編程精選 ? 來源:zhangzhiqiang_0912 ? 作者:Android編程精選 ? 2022-07-23 11:03 ? 次閱讀

近期開發系統過程中遇到的一個需求,系統給定一個接口,用戶可以自定義開發該接口的實現,并將實現打成jar包,上傳到系統中。系統完成熱部署,并切換該接口的實現。

定義簡單的接口

這里以一個簡單的計算器功能為例,接口定義比較簡單,直接上代碼。

publicinterfaceCalculator{
intcalculate(inta,intb);
intadd(inta,intb);
}

該接口的一個簡單的實現

考慮到用戶實現接口的兩種方式,使用spring上下文管理的方式,或者不依賴spring管理的方式,這里稱它們為注解方式和反射方式。calculate方法對應注解方式,add方法對應反射方式。計算器接口實現類的代碼如下:

@Service
publicclassCalculatorImplimplementsCalculator{
@Autowired
CalculatorCorecalculatorCore;
/**
*注解方式
*/
@Override
publicintcalculate(inta,intb){
intc=calculatorCore.add(a,b);
returnc;
}
/**
*反射方式
*/
@Override
publicintadd(inta,intb){
returnnewCalculatorCore().add(a,b);
}
}

這里注入CalculatorCore的目的是為了驗證在注解模式下,系統可以完整的構造出bean的依賴體系,并注冊到當前spring容器中。CalculatorCore的代碼如下:

@Service
publicclassCalculatorCore{
publicintadd(inta,intb){
returna+b;
}
}

反射方式熱部署

用戶把jar包上傳到系統的指定目錄下,這里定義上傳jar文件路徑為jarAddress,jar的Url路徑為jarPath。

privatestaticStringjarAddress="E:/zzq/IDEA_WS/CalculatorTest/lib/Calculator.jar";
privatestaticStringjarPath="file:/"+jarAddress;

并且可以要求用戶填寫jar包中接口實現類的完整類名。接下來系統要把上傳的jar包加載到當前線程的類加載器中,然后通過完整類名,加載得到該實現的Class對象。然后反射調用即可,完整代碼:

/**
*熱加載Calculator接口的實現反射方式
*/
publicstaticvoidhotDeployWithReflect()throwsException{
URLClassLoaderurlClassLoader=newURLClassLoader(newURL[]{newURL(jarPath)},Thread.currentThread().getContextClassLoader());
Classclazz=urlClassLoader.loadClass("com.nci.cetc15.calculator.impl.CalculatorImpl");
Calculatorcalculator=(Calculator)clazz.newInstance();
intresult=calculator.add(1,2);
System.out.println(result);
}

注解方式熱部署

如果用戶上傳的jar包含了spring的上下文,那么就需要掃描jar包里的所有需要注入spring容器的bean,注冊到當前系統的spring容器中。其實,這就是一個類的熱加載+動態注冊的過程。

直接上代碼:

/**
*加入jar包后動態注冊bean到spring容器,包括bean的依賴
*/
publicstaticvoidhotDeployWithSpring()throwsException{
SetclassNameSet=DeployUtils.readJarFile(jarAddress);
URLClassLoaderurlClassLoader=newURLClassLoader(newURL[]{newURL(jarPath)},Thread.currentThread().getContextClassLoader());
for(StringclassName:classNameSet){
Classclazz=urlClassLoader.loadClass(className);
if(DeployUtils.isSpringBeanClass(clazz)){
BeanDefinitionBuilderbeanDefinitionBuilder=BeanDefinitionBuilder.genericBeanDefinition(clazz);
defaultListableBeanFactory.registerBeanDefinition(DeployUtils.transformName(className),beanDefinitionBuilder.getBeanDefinition());
}
}
}

在這個過程中,將jar加載到當前線程類加載器的過程和之前反射方式是一樣的。然后掃描jar包下所有的類文件,獲取到完整類名,并使用當前線程類加載器加載出該類名對應的class對象。判斷該class對象是否帶有spring的注解,如果包含,則將該對象注冊到系統的spring容器中。

DeployUtils包含讀取jar包所有類文件的方法、判斷class對象是否包含sping注解的方法、獲取注冊對象對象名的方法。代碼如下:

/**
*讀取jar包中所有類文件
*/
publicstaticSetreadJarFile(StringjarAddress)throwsIOException{
SetclassNameSet=newHashSet<>();
JarFilejarFile=newJarFile(jarAddress);
Enumerationentries=jarFile.entries();//遍歷整個jar文件
while(entries.hasMoreElements()){
JarEntryjarEntry=entries.nextElement();
Stringname=jarEntry.getName();
if(name.endsWith(".class")){
StringclassName=name.replace(".class","").replaceAll("/",".");
classNameSet.add(className);
}
}
returnclassNameSet;
}
/**
*方法描述判斷class對象是否帶有spring的注解
*/
publicstaticbooleanisSpringBeanClass(Classcla){
if(cla==null){
returnfalse;
}
//是否是接口
if(cla.isInterface()){
returnfalse;
}
//是否是抽象類
if(Modifier.isAbstract(cla.getModifiers())){
returnfalse;
}
if(cla.getAnnotation(Component.class)!=null){
returntrue;
}
if(cla.getAnnotation(Repository.class)!=null){
returntrue;
}
if(cla.getAnnotation(Service.class)!=null){
returntrue;
}
returnfalse;
}
/**
*類名首字母小寫作為spring容器beanMap的key
*/
publicstaticStringtransformName(StringclassName){
Stringtmpstr=className.substring(className.lastIndexOf(".")+1);
returntmpstr.substring(0,1).toLowerCase()+tmpstr.substring(1);
}

刪除jar時,需要同時刪除spring容器中注冊的bean

在jar包切換或刪除時,需要將之前注冊到spring容器的bean刪除。spring容器的bean的刪除操作和注冊操作是相逆的過程,這里要注意使用同一個spring上下文。

代碼如下:

/**
*刪除jar包時需要在spring容器刪除注入
*/
publicstaticvoiddelete()throwsException{
SetclassNameSet=DeployUtils.readJarFile(jarAddress);
URLClassLoaderurlClassLoader=newURLClassLoader(newURL[]{newURL(jarPath)},Thread.currentThread().getContextClassLoader());
for(StringclassName:classNameSet){
Classclazz=urlClassLoader.loadClass(className);
if(DeployUtils.isSpringBeanClass(clazz)){
defaultListableBeanFactory.removeBeanDefinition(DeployUtils.transformName(className));
}
}
}

測試

測試類手動模擬用戶上傳jar的功能。測試函數寫了個死循環,一開始沒有找到jar會拋出異常,捕獲該異常并睡眠10秒。這時候可以把jar手動放到指定的目錄下。

代碼如下:

ApplicationContextapplicationContext=newClassPathXmlApplicationContext("applicationContext.xml");
DefaultListableBeanFactorydefaultListableBeanFactory=(DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
while(true){
try{
hotDeployWithReflect();
//hotDeployWithSpring();
//delete();
}catch(Exceptione){
e.printStackTrace();
Thread.sleep(1000*10);
}
}

-End-

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8932

    瀏覽量

    153183
  • 代碼
    +關注

    關注

    30

    文章

    4886

    瀏覽量

    70239

原文標題:動態上傳jar包熱部署實戰

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    無人職守自動安裝部署操作系統指南

    當組織有服務器需要部署linux系統時,需要通過網絡方式安裝結合自動應答文件,實現無人職守自動安裝部署操作
    的頭像 發表于 05-22 13:38 ?245次閱讀
    無人職守自動安裝<b class='flag-5'>部署</b>操作<b class='flag-5'>系統</b>指南

    POE交換機接口詳解

    實現遠程開關控制與亮度調節,節能高效。 PoE交換機接口與傳統接口的對比 相較于傳統接口,PoE交換機接口在布線、
    發表于 03-27 17:17

    Telkomsel與華為合作完成EasyAAU千站規模部署

    近日,印尼領先的電信運營商Telkomsel與華為合作,在2.3GHz頻段完成千站規模的EasyAAU部署,成功打造巴厘島5G City樣板,逐步向雅加達擴展,為印尼5G網絡建設樹立了新的標桿,也為全球5G發展提供了寶貴經驗。
    的頭像 發表于 03-03 11:46 ?464次閱讀

    行芯完成DeepSeek-R1大模型本地化部署

    近日,行芯正式宣布完成 DeepSeek-R1 大模型本地化部署實現在多場景、多產品中應用。解鎖“芯”玩法,開啟“芯”未來!
    的頭像 發表于 02-24 15:17 ?552次閱讀

    添越智創基于 RK3588 開發板部署測試 DeepSeek 模型全攻略

    RKLLM-Toolkit 是一款專為大語言模型量化與轉換設計的開發套件,提供簡潔易用的 Python 接口,讓開發者能輕松實現以下兩大關鍵功能: 1.模型轉換: 工具支持將部分特定格式的大語言模型,比如
    發表于 02-14 17:42

    ADS1243做一個多通道采集系統,AD前置濾波RC怎么設置?

    我現在要做一個多通道采集系統,需要采集3路K值偶,3路要輪流采集,使用ADS1243,輸出頻率為15hz,使用內部PGA,現在的問題是AD前置濾波RC我怎么設置?設置的依據是什么? 再我對通道
    發表于 02-07 06:56

    功率器件設計基礎(十三)——使用系數Ψth(j-top)獲取結溫信息

    /前言/功率半導體熱設計是實現IGBT、碳化硅SiC高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低
    的頭像 發表于 01-20 17:33 ?1329次閱讀
    功率器件<b class='flag-5'>熱</b>設計基礎(十三)——使用<b class='flag-5'>熱</b>系數Ψth(j-top)獲取結溫信息

    功率器件設計基礎(十一)——功率半導體器件的功率端子

    /前言/功率半導體熱設計是實現IGBT、碳化硅SiC高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低
    的頭像 發表于 01-06 17:05 ?625次閱讀
    功率器件<b class='flag-5'>熱</b>設計基礎(十一)——功率半導體器件的功率端子

    功率器件設計基礎(八)——利用瞬態阻計算二極管浪涌電流

    /前言/功率半導體熱設計是實現IGBT、碳化硅SiC高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低
    的頭像 發表于 12-11 01:03 ?593次閱讀
    功率器件<b class='flag-5'>熱</b>設計基礎(八)——利用瞬態<b class='flag-5'>熱</b>阻計算二極管浪涌電流

    功率器件設計基礎(七)——等效模型

    /前言/功率半導體熱設計是實現IGBT、SiCMOSFET高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低
    的頭像 發表于 12-03 01:03 ?1343次閱讀
    功率器件<b class='flag-5'>熱</b>設計基礎(七)——<b class='flag-5'>熱</b>等效模型

    功率器件設計基礎(六)——瞬態測量

    功率半導體熱設計是實現IGBT、碳化硅SiC高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低系統
    的頭像 發表于 11-26 01:02 ?1356次閱讀
    功率器件<b class='flag-5'>熱</b>設計基礎(六)——瞬態<b class='flag-5'>熱</b>測量

    功率器件的設計基礎(二)——阻的串聯和并聯

    /前言/功率半導體熱設計是實現IGBT、碳化硅SiC高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低
    的頭像 發表于 10-29 08:02 ?809次閱讀
    功率器件的<b class='flag-5'>熱</b>設計基礎(二)——<b class='flag-5'>熱</b>阻的串聯和并聯

    功率器件設計基礎(一)——功率半導體的

    功率半導體熱設計是實現IGBT、碳化硅SiC高功率密度的基礎,只有掌握功率半導體的設計基礎知識,才能完成精確設計,提高功率器件的利用率,降低系統
    的頭像 發表于 10-22 08:01 ?1585次閱讀
    功率器件<b class='flag-5'>熱</b>設計基礎(一)——功率半導體的<b class='flag-5'>熱</b>阻

    kvm切換器怎么實現鍵盤熱鍵切換

    器的工作原理 KVM切換器的核心功能是將一組鍵盤、鼠標和顯示器與多臺計算機連接,通過某種方式實現對這些計算機的控制。KVM切換器的工作原理可以分為以下幾個步驟: 1.1 輸入設備連接
    的頭像 發表于 10-17 09:36 ?2478次閱讀

    PLC冗余系統的相互切換機制

    在工業自動化控制系統中,PLC(可編程邏輯控制器)的冗余設計是確保系統高可靠性和穩定性的重要手段。PLC冗余系統通過配置兩個或多個功能相同的PLC控制器,實現主備用的自動
    的頭像 發表于 06-19 10:42 ?3332次閱讀