主頁 > 作業系統 > 從封裝變化的角度看設計模式——介面隔離

從封裝變化的角度看設計模式——介面隔離

2020-09-14 20:18:04 作業系統

封裝變化之介面隔離

在組件的構建程序當中,某些介面之間直接的依賴常常會帶來很多問題、甚至根本無法實作,采用添加一層間接(穩定)的介面,來隔離本來互相緊密關聯的介面是一種常見的解決方案,

這里的介面隔離不同于介面隔離原則,介面隔離原則是對介面職責隔離,也就是盡量減少介面職責,使得一個類對另一個類的依賴應該建立在最小的介面上,

而這里所講到的介面隔離是對依賴或者通信關系的隔離,通過在原有系統中加入一個層次,使得整個系統的依賴關系大大的降低,而這樣的模式主要有外觀模式、代理模式、中介者模式和配接器模式,

外觀模式 - Facade

Facade模式其主要目的在于為子系統中的一組介面提供一個一致的界面(介面),Facade模式定義了一個高層介面,這個介面使得更加容易使用,

在我們對系統進行研究的時候,往往會采用抽象與分解的思路去簡化系統的復雜度,因此在這個程序當中就將一個復雜的系統劃分成為若干個子系統,也正是因為如此,子系統之間的通信與相互依賴也就增加了,為了使得這種依賴達到最小,Facade模式正好可以解決這種問題,

Facade模式體現的更多的是一種介面隔離的思想,它體現在很多方面上,最常見的比如說用戶圖形界面、作業系統等,這都可以體現這樣一個思想,

facade.png

Facade模式從結構上可以簡化為上面這樣一種形式,但其形式并不固定,尤其是體現在其內部子系統的關系上,因為其內部的子系統關系肯定是復雜多樣的,并且SubSystem不一定是類或者物件,也有可能是一個模塊,這里只是用類圖來表現Facade模式與其子系統之間的關系,

從代碼體現上來看,可以這樣表現:

public class SubSystem1 {
    public void operation1(){
        //完成子系統1的功能
        ......
    }
}
public class SubSystem2 {
    public void operation2(){
        //完成子系統2的功能
        ......
    }
}
public class SubSystem3 {
    public void operation3(){
        //完成子系統3的功能
        ......
    }
}
public class SubSystem21 extends SubSystem2{
    //對子系統2的擴展
    ......
}
public class SubSystem22 extends SubSystem2 {
    //對子系統2的擴展
    ......
}

上面子系統內部各部分的一個體現,如何結合Facade來對外隔離它的系統內部復雜依賴呢?看下面:

public class Facade {
    private SubSystem1 subSystem1;
    private SubSystem2 subSystem2;
    private SubSystem3 subSystem3;
    public Facade(){
        subSystem1 = new SubSystem1();
        subSystem2 = new SubSystem21();
        subSystem3 = new SubSystem3();
    }
    public void useSystem1(){
        subSystem1.operation1();
    }
    public void useSystem2(){
        subSystem2.operation2();
    }
    public void useSystem3(){
        subSystem3.operation3();
    }
}

當然,這只是Facade模式的一種簡單實作,可能在真正的實作系統中,會有著更加復雜的實作,比如各子系統之間可能存在依賴關系、又或者呼叫各子系統時需要傳遞引數等等,這些都會給Facade模式的實作帶來很大的影響,

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.useSystem1();
        facade.useSystem2();
        facade.useSystem3();
    }
}

當存在Facade之后,客戶對子系統的訪問就只需要面對Facade,而不需要再去理解各子系統之間的復雜依賴關系,當然對于普通客戶而言,使用Facade所提供的介面自然是足夠的;對于更加高級的客戶而言,Facade模式并未屏蔽高級客戶對子系統的訪問,也就是說,如果有客戶需要根據子系統定制自己的功能也是可以的,

對Facade的理解很簡單,但是在具體使用時,又需要注意些什么呢?

  • 進一步地降低客戶與子系統之間的耦合度,具體實作是,使用抽象類來實作Facade而通過它的具體子類來應對不同子系統的實作,并且可以滿足客戶根據要求自己定制Facade,

    除了使用子類的方式之外,通過其他的子系統來配置Facade也是一個方法,并且這種方法的靈活性更好,

  • 在層次化結構中,可以使用外觀模式定義系統中每一層的入口,剛才我們就提到過,SubSystem不一定只表示一個類,它包含的可能是一些類,并且是一些具有協作關系的類,那么對于這些類,自然也是使用外觀模式來為其定義一個統一的介面,

  • Facade模式自身也有缺點,雖然它減少系統的相互依賴,提高靈活性,提高了安全性;但是其本身就是不符合開閉原則的,如果子系統發生變化或者客戶需求變化,就會涉及到Facade的修改,這種修改是很麻煩的,因為無論是通過擴展或是繼承都可能無法解決,只能以修改原始碼的方式,

代理模式 - Proxy

在Proxy模式中,我們創建具有現有物件的代理物件,以便向外界提供功能介面,其目的在于為其他物件提供一種代理以控制對這個物件的訪問,

這是因為一個物件的創建和初始化可能會產生很大的開銷,這也就意味著我們可以在真正需要這個物件時再對其進行相應的創建和初始化,

比如在檔案系統中對一個圖片的訪問,當我們以串列形式查看檔案時,并不需要顯示整個圖片的資訊,只有在選中圖片的時候,才會顯示其預覽資訊,再在雙擊之后可能才會真正打個這個圖片,這時可能才需要從磁盤當中加載整個圖片資訊,

ProxyImage.png

對圖片代理的理解就如同上面的結構圖一樣,在檔案欄中預覽時,只是顯示代理物件當中的fileName等資訊,而代理物件當中的image資訊只會在真正需要Image物件的時候才會建立實線指向的聯系,

通過上面的例子,可以清楚的看到代理模式在訪問物件時,引入了一定程度的間接性,這種間接性根據不同的情況可以附加相應的具體處理,

比如,對于遠程代理物件,可以隱藏一個物件不存在于不同地址空間的事實,對于虛代理物件,可以根據要求創建物件、增強物件功能等等,還有保護代理物件,可以為物件的訪問增加權限控制,

這一系列的代理都體現了代理模式的高擴展性,但同時也會增加代理開銷,由于在客戶端和真實主題之間增加了代理物件,因此有些型別的代理模式可能會造成請求的處理速度變慢,并且實作代理模式需要額外的作業,有些代理模式的實作非常復雜,

對于上面的例子,可以用類圖更加詳細地闡述,

Proxy.png

在這樣一個結構中,jpg圖片與圖片代理類共同實作了一個圖片介面,并且在圖片代理類中存放了一個對于JpgImage的參考,這個參考在未有真正使用到時,是為null的,只有在需要使用時,才對其進行初始化,

//Subject(代理的目標介面)
public interface Image {
    public void show();
    public String getInfo();
}
//RealSubject(被代理的物體)
public class JpgImage implements Image {
    private String imageInfo;
    @Override
    public void show() {
        //顯示完整圖片
        ......
    }

    @Override
    public String getInfo() {
        return imageInfo;
    }
    public Image loadImage(String fileName){
        //從磁盤當中加載圖片資訊
       // ......
        return new JpgImage();
    }
}
//Proxy(代理類)
public class ImageProxy implements Image {
    private String fileName;
    private Image image;
    @Override
    public void show() {
        if (image==null){
           image = loadImage(fileName);
        }
        image.show();
    }

    @Override
    public String getInfo() {
        if (image==null){
            return fileName;
        }else{
            return image.getInfo();
        }
    }

    public Image loadImage(String fileName){
        //從磁盤當中加載圖片資訊
        ......
        return new JpgImage();
    }
}
public class Client {
    public static void main(String[] args) {
       Image imageProxy = new ImageProxy();
       imageProxy.getInfo();
       imageProxy.show();
    }
}

在實際的使用程序上,客戶就可以不再涉及具體的類,而是可以只關注代理類,

代理模式的種類有很多,根據代理的實作形式不同,可以劃分為:

  • 遠程代理:為一個物件在不同的地址空間提供區域代表,
  • 虛代理:為需要創建開銷很大的物件生成代理,(如上面的實體)
  • 保護代理:控制對原始物件的訪問,保護代理主要用于物件應該有不同的保護權限時,
  • 智能指引:在訪問物件時執行一些附加的操作,

以上的代理都是靜態代理的形式,為什么說是靜態呢,這是因為在實作的程序中,它的型別都是事先預定好的,比如ImageProxy這個類,它就只能代理Image的子類,

與靜態相對的自然就產生了動態代理,動態代理中,最主要的兩種方式就是基于JDK的動態代理和基于CGLIB的動態代理,這兩種動態代理也是Spring框架中實作AOP(Aspect Oriented Programming)的兩種動態代理方式,這里,就不深入了,后面有機會再對動態代理做一個詳細的講解,

中介者模式 - Mediator

中介者模式用一個中介物件來封裝一系列的物件互動,中介者使各物件不需要顯示地相互參考,從而使其耦合松散,而且可以獨立地改變它們之間的互動,

中介者模式產生的一個重要原因就在于,面向物件設計鼓勵將行為分頁到各個物件中,而這種分布就可能會導致物件間有許多連接,這些連接就是導致系統復用和修改困難的原因所在,

就比如一個機場調度的實作,在這個功能當中,各個航班就是Colleague,而塔臺就是Mediator;如果沒有塔臺的協調,那么各個航班飛機的起降將只能由航班飛機之間形成一個多對多(一對多)的通信網來控制,這種控制必然是及其復雜的;但是有了塔臺的加入,整個系統就簡化了許多,所有的航班只需要和塔臺進行通信,也只需要接收來自塔臺的控制即可完成所有任務,這就使得多對多(一對多)的關系轉化成了一對一的關系,

mediator.png

看到中介者模式類圖的時候,有沒有發覺好像和哪個模式有點相似,有沒有點像觀察者模式,

之所以如此相似的原因就是觀察者模式和中介者模式都涉及到了物件狀態變化與狀態通知這兩個程序,觀察者模式當中,目標(Subject)的狀態發生變化就會通知其所有的(Observer);同樣,在中介者模式當中,其相應的同事類(一群通過中介者相互協作的類)狀態發生變化,就需要通知中介者,再由中介者來處理狀態資訊并反饋給其他的同事類,

因此,中介者模式的實作方法之一就是使用觀察者模式,將Mediator作為一個Observer,各個Colleague作為Subject,一旦Colleague狀態發生變化就發送通知給Mediator,Mediator作出回應并將狀態改變的結果傳播給其他的Colleague,

另外還有一種方式,是在Mediator中定義一個特殊的介面,各個Colleague直接呼叫這個介面,并將自己作為引數傳入,然后由這個介面來選擇將資訊發送給誰,

//Mediator
public class ControlTower {
    private List<Flight> flights
        				= new ArrayList<>();
    public void addFlight(Flight flight){
        flights.add(flight);
    }
    public void removeFlight(Flight flight){
        flights.remove(flight);
    }
    public void control(Flight flight){
        //對航班進行起降控制
        ......
        //如果航班起飛,則從flights移除
        //如果航班降落,則加入到flights
    }
}
public class Flight {
    private ControlTower cTower;
    public void setcTower(ControlTower cTower) {
        this.cTower = cTower;
    }
    public void changed(){
        cTower.control(this);
    }
}
public class Flight1 extends Flight{
    public void takeOff(){
		//起飛操作
		......
    }
    public void land(){
		//降落操作
		......
    }
}
public class Flight2 extends Flight{
    //起飛 降落 操作
    ......
}
public class Flight3 extends Flight{
  //同樣 起飛 降落 操作
    ......
}

那么客戶怎樣使用這樣一個模式呢?看下面這樣一個操作:

public class Client {
    public static void main(String[] args) {
        ControlTower controlTower = new ControlTower();
        //假設一個飛機入場要么是有跑道空閑要么是另一個飛機起飛
        Flight f1 = new Flight1();
        f1.setcTower(controlTower);
        //此時一號機降落,
        //controlTower呼叫contorl控制飛機起降
        f1.changed(); 

        Flight f2 = new Flight2();
        f2.setcTower(controlTower);
        //此時二號機降落,
        //controlTower呼叫contorl控制1號飛機起飛,二號降落
        f2.changed();
        
        .......
    }
}

中介者模式主要解決的是,如果系統中物件之間存在比較復雜的參考關系,導致它們之間的依賴關系結構混亂而且難以復用該物件,就可以使用中介者來簡化依賴關系,但是這也可能會使得中介者會龐大,變得復雜難以維護,所以在使用中介者模式時,盡量是在保持中介者穩定的情況下使用,

配接器模式 - Adapter

配接器的目的在于將一個類的介面轉換成客戶希望的另外一個介面,從而使得原本由于介面不兼容而不能在一起作業的類可以在一起作業,

首先在使用配接器的時候,需要明確的是,配接器不是在詳細設計時添加的,而是解決正在服役的專案的問題,為什么,因為配接器本身就存在一些問題,比如明明我想呼叫的是一個檔案介面,結果傳輸出來的卻是一張圖片,如果系統當中出現太多這樣的情況,那無異會使得系統的應用變得極其困難,

所以只有在系統正在運用,并且重構困難的情況下,才選擇使用配接器來適配介面,

而配接器模式又根據作用物件可以分為類配接器和物件配接器兩種實作方式,

假設我們現在已經存在一個播放器,這個播放器只能播放mp3格式的音頻,但是現在又出現了一個新的播放器,這個播放器有兩種播放格式mp4和wma,

也就是說,現在的情況可以用下圖來進行描述:

adapter-before .png

這時候,為了右邊的系統Player 融入到右邊中,就可以采用配接器模式,

adapter-object .png

通過增加一個配接器,并將player作為配接器的一個屬性,當傳入具體的播放器時,就在newPlay()中呼叫player.play()

具體實作如下:

//Adaptee (適配者,要求將這個存在的介面適配成目標的介面)
public interface Player {
    public void play();
}
public class Mp3Player implements Player {
    @Override
    public void play() {
        System.out.println("播放mp3格式");
    }
}
//Target(適配目標,需要適配成那個目標的介面)
public interface NewPlayer {
    public void newPlay();
}
public class WmaNewPlayer implements NewPlayer {
    @Override
    public void newPlay() {
        System.out.println("播放wmas格式");
    }
}
public class Mp4NewPlayer implements NewPlayer {
    @Override
    public void newPlay() {
        System.out.println("播放mp4格式");
    }
}

接下來就是配接器的實作了,

//物件配接器
//首先在配接器中,增加一個適配者(Player)的參考
//然后使用適配者(Player)實作適配目標(NewPlayer)的介面
public class PlayerAdapter implements NewPlayer {
    private  Player player;
    public PlayerAdapter(Player player){
        this.player = player;
    }
    @Override
    public void newPlay() {
        player.play();
    }
}

然后整個系統的呼叫變化為:

public class Client {
    public static void main(String[] args) {
        //播放mp4,wma的形式不變
        NewPlayer mp4Player = new Mp4NewPlayer();
        mp4Player.newPlay();
        NewPlayer wmaPlayer = new WmaNewPlayer();
        wmaPlayer.newPlay();

        //如果要播放mp3格式,可以使用配接器來進行
        Player adapter
            = new PlayerAdapter(new Mp3Player());
        adapter.newPlay();
    }
}

這樣的一個適配程序可能存在一點不完善的地方,就在于,雖然對兩都進行了適配,但呼叫方式不統一,為了統一呼叫程序,其實還可以做如下修改:

//物件配接器修改為
//首先在配接器中,增加適配者(newPlayer)和目標(player)的參考
//然后使用適配者(newPlayer)實作適配目標(Player)的介面
public class PlayerAdapter implements NewPlayer {
    private  NewPlayer newPlayer;
    private  Player player;

    public PlayerAdapter(NewPlayer newPlayer){
        this.newPlayer = newPlayer;
    }
    public PlayerAdapter(Player layer){
        this.player = player;
    }
    @Override
    public void newPlay() {
    	if(player!=null){
    		player.play();
    	}else{
        	newPlayer.newPlay();
    	}
    }
}
//這樣修改配接器之后,客戶類的呼叫就變成了都通過配接器來進行
public class Client {
    public static void main(String[] args) {
       //播放mp3
        Player adapter1 
           = new PlayerAdapter(new Mp3Player());
        adapter1.newPlay();
        //播放mp4
        Player adapter2 
            = new PlayerAdapter(new Mp4NewPlayer());
        adapter2.newPlay();
        //播放wma
        Player adapter3 
            = new PlayerAdapter(new WmaNewPlayer());
        adapter3.newPlay();
    }
}

之前說了除了物件配接器之外,還有類配接器,而類配接器如果要實作就需要適配中的適配者是一個已經實作的結構,如果沒有實作還需要適配者自己實作,這種實作方式就導致其靈活性沒有物件配接器那么高,

adapter-class.png其類圖就是上面這樣一種形式,主要區別體現在配接器的實作,而其部分變化不大,

//類配接器
public class PlayerAdapter extends Mp3Player implements NewPlayer {
    @Override
    public void newPlay() {
    	play();
    }
}
//客戶呼叫程序就變化為:
public class Client {
    public static void main(String[] args) {
        //播放mp4,wma的形式不變
        NewPlayer mp4Player = new Mp4NewPlayer();
        mp4Player.newPlay();
        NewPlayer wmaPlayer = new WmaNewPlayer();
        wmaPlayer.newPlay();
        //如果要播放mp3格式,可以使用配接器來進行
        Player adapter = new PlayerAdapter();
        adapter.newPlay();
    }
}

但是如果Player存在不同子類,那明顯使用物件配接器是更好的選擇,

當然也不是說類配接器就不一定沒有物件配接器之外的優勢,兩者的使用有不同的權衡,

類配接器:

  • 用一個具體的Adapater類對Adaptee和Target進行匹配,結果是當我們想要匹配一個類以及所有它的子類時,類配接器就不再適用,
  • 因為Adapter是Adaptee的子類,這就使得Adapter可以重定義Adaptee的部分行為,
  • 不需要再引入物件,不需要引入額外的參考就可以得到adaptee,

物件配接器:

  • 允許一個Adapter與多個Adaptee——即Adaptee本身以及它的所有子類同時作業,并且Adapter也可以一次給所有的Adaptee添加功能,
  • 想要重定義Adaptee的行為比較困難,但對于增強Adaptee的功能卻很容易,如果要自定義Adaptee的行為,就只能生成Adaptee的子類來實作重定義,

公眾號:良許Linux

有識訓?希望老鐵們來個三連擊,給更多的人看到這篇文章

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/38447.html

標籤:Linux

上一篇:007.Nginx虛擬主機

下一篇:(1)Linux系統中到底應該怎么理解系統的平均負載

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more