主頁 >  其他 > java虛擬機系列:深入理解Java類加載機制

java虛擬機系列:深入理解Java類加載機制

2021-11-03 07:28:52 其他

大綱

  • 前言
  • 類加載機制
  • 類加載器
    • 雙親委派機制
    • 為什么要使用雙親委派機制?
  • 分析ClassLoader
    • loadClass()
    • findClass()
      • defineClass(String name, byte[] b, int off, int len)
    • resolveClass(Class<?> c)
  • 自定義類加載器
    • 通過繼承URLClassLoader來實作自定義類加載器
  • URLClassLoader
    • findClass()
  • Launcher類
    • getExtClassLoader()
    • createExtClassLoader()

前言

在我上一篇 類檔案結構(java虛擬機系列:一文明解 .class 檔案)博客中詳細介紹了類檔案(.class)如何為java語言的跨平臺性發揮作用和它的內部結構,而類檔案需要加載到虛擬機中,才能被運行,這篇文章將會詳細解說虛擬機的類加載機制

類加載機制

所謂的類加載,就是把.class的二進制檔案(不一定是檔案,也可以通過網路二進制位元組流)加載到記憶體中,形成一個可以直接使用的java型別(Class物件),虛擬機的類加載程序通常包括以下七個階段

  • 加載:在加載階段,JVM通過一個類的全限定名稱來獲取二進制位元組流,最后在記憶體里生成一個代表該類的Class物件,加載階段是程式員最能掌控的一個階段,因為并沒有限定要通過何種途徑來獲取二進制流,所以我們可以通過自定義的類加載器,通過網路位元組流傳輸等多種途徑去獲取二進制流,

  • 驗證: 加載與連接是交叉進行的,比如某些驗證位元組碼檔案格式的操作,驗證階段主要是確保Class檔案里面的資訊符合規范,不會影響到虛擬機自身的安全

  • 準備: 這個階段主要為類變數(靜態變數)分配記憶體并初始化賦值,注意,這些類變數使用的記憶體在方法取,而方法區只是一個邏輯上的說法,在jdk7的方法區表現為永久代,而在jdk8使用了元空間的概念,所以類變數是隨著Class物件放在堆里面,

    public static int a = 199;
    //在準備階段,賦給a的初始值是0而不是199
    //只有當存放在<clinit>()的putstatic指令被執行后才會被賦值為199,而<clinit>類構造方法被執行是在初始化階段才被執行
    
     public static final int b = 199;
    //而類變數b是由final修飾的,所以它的值199被存放于ConstantValue屬性(被其對應的欄位表參考)中,而ConstantValue會指向它對應的常量池之中的字面量,所以在準備階段就直接對b賦值
    
  • 決議:決議階段就是把符號參考轉換為直接參考,符號就是用任意的字面量來描述參考的目標,而直接參考是可以直接指向目標的指標、相對偏移量或者是能間接定位到目標的句柄,直接參考直接對應著虛擬機的真實記憶體布局,《java虛擬機規范》中只說明在執行 checkcast、getfield、getstatic、instanceof、invokedynamic方法等17個用于運算子號參考的位元組碼之前,先對符號參考進行決議,所以虛擬機既可以在類加載階段就對常量池里面的符號參考進行決議,也可以等到一個符號參考將要被使用之前就對其決議,

  • **初始化:**初始化階段就是執行類構造器()的程序,而()是javac編譯是自動生成的,它搜集了類中對類變數賦值的動作和static{}靜態代碼塊的陳述句,如果一個普通的類沒有靜態變數賦值動作也沒有靜態代碼塊,()是不存在的,java虛擬機會保證在子類的()方法執行前先執行父類的()方法,而無需顯式呼叫,

類加載器

? 類加載器的任務是把二進制的位元組流轉換為記憶體中的Class物件,每個Class物件都包含著對它的類加載器的參考,對于任意一個類,都必須由它的類和加載它的類加載器共同確立在java虛擬機中的唯一性,

? 在Java虛擬機的角度來說,類加載器分為兩種,一種是虛擬機自身的啟動類加載器,使用C++撰寫的,而另一種稱為其它類加載器,使用java語言撰寫,都繼承了ClassLoader類

  • Bootstrap Class Loader(引導類加載器),是虛擬機自身的加載器,這個加載器負責加載存放在<JAVA_HOME>\lib目錄或者被-Xbootclasspath引數所指定的路徑存放jar,而且必須是符合的類別庫(如 rt.jar、tools.jar)
  • Extension Class Loader(擴展類加載器),由java語言撰寫,它負責加載<JAVA_HOME>\lib\ext目錄中,或者被java.ext.dirs系統變數所指定的路徑中所有的類別庫
  • Application Class Loader(應用程式類加載器),它負責加載用戶路(ClassPath)上所有的類別庫

雙親委派機制

? 雙親委派機制的其實就是當子類加載器收到了對加載類的請求的時候,它本身先不去加載,而是把加載的請求傳遞給它的父類加載器,因此所有的加載請求都會傳遞到最頂層的啟動類加載器,然后父類加載器會嘗試去加載該類,如果加載不了則再由子類去加載,

在這里插入圖片描述

為什么要使用雙親委派機制?

有一個顯而易見的好處就是java中的類和它的類加載器一起形成了具備優先級層次的關系,比如遵循雙親委派機制,可以確保在任意的加載器的環境中Object都是同一個類,因為它最終是由引導類加載器去加載的,而如果不遵循的話,用戶可以自定義一個 java.lang.Object類在classpath下加載,會造成Object類不唯一,造成應用程式的混亂,

分析ClassLoader

loadClass()

我們可以通過以下這種方式去使一個類進行加載,并獲取到它的Class物件

public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        Class<?> aClass = systemClassLoader.loadClass("com.test.JVM.JVMTest");
    }

然后我們再來看看loadClass()方法,因為系統類加載器(也就是應用程式類加載器)繼承了ClassLoader,所以也繼承了ClassLoader的loadClass()方法

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
//下面這段簡短的代碼遵循了雙親委派機制
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        //首先確保這個類是否被加載過,一個類只會被加載一次
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    //委托給父類的loadClass()方法
                    c = parent.loadClass(name, false);
                } else {
                    //如果parent為null,則證明它的父類加載器
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                //如果c還是null,則證明父類沒有去加載,所以當前的類加載器就去加載
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        //進行連接
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

findClass()

我們在loadClass()方法看到,如果父類加載不了,那么當前的類加載器就呼叫該findClass()方法去加載,官方建議自定義的類加載器都去重寫這一方法而不是loadClass(),因為loadClass()方法是用來實作雙親委派機制的,而如果重寫它可能會破壞雙親委派機制

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

defineClass(String name, byte[] b, int off, int len)

這個方法通常用在findClass()方法里,用于傳入對應類的全限定名稱加上一個位元組陣列和它的起始位置和長度,就能得到一個Class物件,如果直接呼叫此方法,得到的Class物件是未經過決議的,因為它沒有呼叫resolveClass(),要具體等到一個符號被參考之前才去決議它,

protected final Class<?> defineClass(String name, byte[] b, int off, int len)
    throws ClassFormatError
{
    return defineClass(name, b, off, len, null);
}

resolveClass(Class<?> c)

類加載器可能(也只是可能,因為上面有說到決議階段只要保證符號參考被使用前執行就行,可能在類加載階段就決議,也可能到用的時候才決議)會使用此方法來連接特定的類(決議階段,把符號參考變成虛擬機記憶體中的直接參考),

自定義類加載器

當我們想獲取D盤或者網路中的.class檔案并把它們加載到記憶體中或者需要Class的解密加密器時,可以自定義類加載器來完成,通常,我們需要繼承ClassLoader并重寫findClass()方法即可,如下圖

public class MyClassLoader extends ClassLoader{
    private File classPathFile;

    public MyClassLoader(){
        //為了方便,這里就直接用了classpath的路徑,也可以換成其它盤的路徑
        String path = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(path);
    }


    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = MyClassLoader.class.getPackage().getName()+"."+ name;
        if (classPathFile != null){
            File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
            if (classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    //通過defineClass()加載出了Class物件
                    return defineClass(className,out.toByteArray(),0,out.size());
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if (null != in) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (out != null){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

? 自定義的類加載器的父加載器是AppClassLoader(如下圖),也就是應用程式(系統類)加載器,所以我們自定義的類加載器如果像上面一樣沒有重寫load()方法的話也是會遵循雙親委派機制的

System.out.println(new MyClassLoader().getParent());

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Lv0sukXR-1635834649825)(java虛擬機系列:深入理解Java類加載機制.assets/image-20211102095820220.png)]

通過繼承URLClassLoader來實作自定義類加載器

如果通過去繼承ClassLoader來創造自定義的類加載器的話,需要重寫findClass()方法中去定位資源的代碼或者獲取位元組流的代碼,較為煩雜,所以如果不是有什么復雜的需求,可以通過繼承URLClassLoader來降低編碼量

下面自定義了一個SelfClassLoader然后繼承了URLClassLoader

public class SelfClassLoader extends URLClassLoader {

    public SelfClassLoader(URL[] urls) {
        super(urls);
    }
}

通過下面的方法加載D盤下的類

public static void main(String[] args) throws ClassNotFoundException, MalformedURLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //指定了在哪個檔案下
    File file = new File("D://");
    SelfClassLoader selfClassLoader = new SelfClassLoader(new URL[]{file.toURI().toURL()});
    //這里需要指定類的全限定名稱
    Class<?> aClass = selfClassLoader.loadClass("com.test.Test");
    Object o = aClass.getConstructor().newInstance();
    System.out.println(o);
}

在這里插入圖片描述

URLClassLoader

先看看它的繼承關系

在這里插入圖片描述

首先我們看看自定義的類加載器繼承了URLClassLoader后要怎么用

//像這樣,我們繼承了URLClassLoader并且寫了三個構造方法,并且分別執行了父類的三個構造方法
public class SelfClassLoader extends URLClassLoader {
    public SelfClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public SelfClassLoader(URL[] urls) {
        super(urls);
    }

    public SelfClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }
}

然后我們羅列以下URLClassLoader的三個構造方法

public URLClassLoader(URL[] urls, ClassLoader parent)
public URLClassLoader(URL[] urls)
public URLClassLoader(URL[] urls, ClassLoader parent,URLStreamHandlerFactory factory)
  • urls:指明了要加載的class檔案的路徑,因為是一個陣列,所以可以包含多個路徑
  • parent:指定了該類加載器的父類加載器,AppClassLoader也是通過這個去指定父類加載器的,稍后會說
  • factory:用來指定URLClassPath,這個URLClassPath是用來定位資源的

findClass()

因為URLClassLoader繼承了ClassLoader,而它沒有重寫ClassLoader的loadClass()方法,所以還是遵循雙親委派機制,所以我們重點看一下findClass()方法,因為它是用來加載出Class物件的方法,如下圖

protected Class<?> findClass(final String name)
    throws ClassNotFoundException
{
    final Class<?> result;
    try {
        result = AccessController.doPrivileged(
            new PrivilegedExceptionAction<Class<?>>() {
                public Class<?> run() throws ClassNotFoundException {
                    //把全限定名稱轉為路徑
                    String path = name.replace('.', '/').concat(".class");
                    //通過URLClassPath定位到資源
                    Resource res = ucp.getResource(path, false);
                    if (res != null) {
                        try {
                            //通過多載的defineClass方法來獲得Class實體
                            return defineClass(name, res);
                        } catch (IOException e) {
                            throw new ClassNotFoundException(name, e);
                        }
                    } else {
                        return null;
                    }
                }
            }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        throw (ClassNotFoundException) pae.getException();
    }
    if (result == null) {
        throw new ClassNotFoundException(name);
    }
    return result;
}

至于多載的defineClass原始碼就不去分析了,如果大家有興趣可以去看看

Launcher類

Launcher屬于oracle的閉源代碼,所以只能通過idea反編譯出來,存在了奇怪的變數名,Launcher里封裝了擴展類加載器和應用程式加載器,所以Launcher實作對以上兩個加載器的加載,下面我們來簡單了解以下它,首先來看看Launcher的構造方法

public Launcher() {
    Launcher.ExtClassLoader var1;
    try {
        //獲取了擴展類加載器
        var1 = Launcher.ExtClassLoader.getExtClassLoader();
    } catch (IOException var10) {
        throw new InternalError("Could not create extension class loader", var10);
    }

    try {
        //獲取了應用程式加載器,注意這里把擴展類加載器的參考傳入了
        //可以推測這里是把AppClassLoader的父類加載器設定為ExtClassLoader
        //所以子父類加載器不是通過繼承來決定的,而是通過聚合的方式
        this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
    } catch (IOException var9) {
        throw new InternalError("Could not create application class loader", var9);
    }

    //設定執行緒背景關系加載器為AppClassLoader
    Thread.currentThread().setContextClassLoader(this.loader);
    String var2 = System.getProperty("java.security.manager");
    if (var2 != null) {
        SecurityManager var3 = null;
        if (!"".equals(var2) && !"default".equals(var2)) {
            try {
                var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
            } catch (IllegalAccessException var5) {
            } catch (InstantiationException var6) {
            } catch (ClassNotFoundException var7) {
            } catch (ClassCastException var8) {
            }
        } else {
            var3 = new SecurityManager();
        }

        if (var3 == null) {
            throw new InternalError("Could not create SecurityManager: " + var2);
        }

        System.setSecurityManager(var3);
    }

}

我們再來看看被封裝的AppClassLoader

static class AppClassLoader extends URLClassLoader {
	......
}

我們發現它繼承了URLClassLoader,其實ExtClassLoader也繼承了URLClassLoader,如下繼承圖

在這里插入圖片描述

所以就很好理解了,AppClassLoader是通過URLClassLoader的構造方法傳入parent引數來確定他父類構造器是擴展類加載器的,我們再來看看擴展類或者應用程式類加載器是如何向URLClassLoader注冊它們要加載的包的路徑的

getExtClassLoader()

我們先從擴展類加載器是如何獲取的開始,如下代碼

static class ExtClassLoader extends URLClassLoader {
    private static volatile Launcher.ExtClassLoader instance;

    //使用了單例模式,確保擴展類加載器只能有一個實體
    //這里具體使用了雙重檢查加synchronized,確保了只能有一個執行緒對擴展類加載器實體化
    public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
        if (instance == null) {
            Class var0 = Launcher.ExtClassLoader.class;
            synchronized(Launcher.ExtClassLoader.class) {
                if (instance == null) {
                    instance = createExtClassLoader();
                }
            }
        }

        return instance;
    }
    ......省略其它代碼
}

createExtClassLoader()

然后我們再看看真正實體化的方法,如下

private static Launcher.ExtClassLoader createExtClassLoader() throws IOException {
    try {
        return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
            public Launcher.ExtClassLoader run() throws IOException {
                //得到檔案陣列
                File[] var1 = Launcher.ExtClassLoader.getExtDirs();
                int var2 = var1.length;

                for(int var3 = 0; var3 < var2; ++var3) {
                    MetaIndex.registerDirectory(var1[var3]);
                }
			   //在這里呼叫了ExtClassLoader構造方法
                //這里傳入的var1引數是后來傳給它父類(URLClassLoader)構造方法的urls引數(檔案路徑)
                return new Launcher.ExtClassLoader(var1);
            }
        });
    } catch (PrivilegedActionException var1) {
        throw (IOException)var1.getException();
    }
}

我們再點進getExtDirs()看看它是如何獲取ExtClassLoader要加載類的檔案目錄

private static File[] getExtDirs() {
    String var0 = System.getProperty("java.ext.dirs");
    ...省略代碼
}

然后我們發現它是通過System.getProperty()方法獲取的,我們測驗一下該方法

System.out.println(System.getProperty("java.ext.dirs"));

得到結果

在這里插入圖片描述

這個路徑正是擴展類加載器允許加載的類的所在路徑,然后回到createExtClassLoader(),點進Launcher.ExtClassLoader(var1)方法

public ExtClassLoader(File[] var1) throws IOException {
    //呼叫了擴展類加載器父類構造器(URLClassLoader)方法,指定了要加載的Class的路徑
    super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
    SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}

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

標籤:其他

上一篇:CentOS安裝python3

下一篇:VMware 與戴爾正式“分手”

標籤雲
其他(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)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more