Spring框架精髓:帶你手寫IoC

在這里插入圖片描述


在這里插入圖片描述


個人名片:

在這里插入圖片描述


🐼作者簡介:一名大三在校生,喜歡AI編程🎋
🐻???個人主頁🥇:落798.
🐼個人WeChat:hmmwx53
🕊?系列專欄:🖼?

  • 零基礎學Java——小白入門必備🔥
  • 重識C語言——復習回顧🔥
  • 計算機網絡體系———深度詳講
  • HCIP數通工程師-刷題與實戰🔥🔥🔥
  • 微信小程序開發——實戰開發🔥
  • HarmonyOS 4.0 應用開發實戰——實戰開發🔥🔥🔥
  • Redis快速入門到精通——實戰開發🔥🔥🔥
  • RabbitMQ快速入門🔥
    🐓每日一句:🍭我很忙,但我要忙的有意義!
    歡迎評論 💬點贊👍🏻 收藏 📂加關注+


文章目錄

  • 原理-手寫IoC
      • 4.1、回顧Java反射
      • 4.2、實現Spring的IoC
    • 寫在后面🔥🔥🔥:
    • 歡迎添加微信,加入我的核心小隊,請備注來意


原理-手寫IoC

IoC(Inversion of Control,控制反轉)是一種設計原則,它的核心思想是將組件之間的依賴關系從組件內部轉移到外部。在傳統的程序設計中,組件(如類或模塊)通常在內部創建或查找其依賴的其他組件。而在IoC中,這些依賴關系由外部容器或框架在運行時注入,從而實現了解耦。

手寫一個簡單的IoC容器的基本步驟如下:

  • 定義組件接口:首先,你需要定義一個或多個接口,這些接口將被組件實現,以便容器可以管理它們。

  • 創建容器類:容器類負責管理組件的實例化、配置和依賴注入。

  • 注冊組件:允許用戶向容器中注冊組件,指定它們的類型和實現。

  • 解析依賴:當請求某個組件時,容器將解析并注入所有必要的依賴。

  • 實例化組件:容器負責根據注冊的信息實例化組件。

Spring框架的IOC是基于Java反射機制實現的,下面我們先回顧一下java反射。

4.1、回顧Java反射

Java反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為Java語言的反射機制。簡單來說,反射機制指的是程序在運行時能夠獲取自身的信息。

要想解剖一個類,必須先要獲取到該類的Class對象。而剖析一個類或用反射解決具體的問題就是使用相關API**(1)java.lang.Class(2)java.lang.reflect**,所以,Class對象是反射的根源

自定義類

package com.atguigu.reflect;public class Car {//屬性private String name;private int age;private String color;//無參數構造public Car() {}//有參數構造public Car(String name, int age, String color) {this.name = name;this.age = age;this.color = color;}//普通方法private void run() {System.out.println("私有方法-run.....");}//get和set方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}@Overridepublic String toString() {return "Car{" +"name='" + name + '\'' +", age=" + age +", color='" + color + '\'' +'}';}
}

編寫測試類

package com.atguigu.reflect;import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class TestCar {//1、獲取Class對象多種方式@Testpublic void test01() throws Exception {//1 類名.classClass clazz1 = Car.class;//2 對象.getClass()Class clazz2 = new Car().getClass();//3 Class.forName("全路徑")Class clazz3 = Class.forName("com.atguigu.reflect.Car");//實例化Car car = (Car)clazz3.getConstructor().newInstance();System.out.println(car);}//2、獲取構造方法@Testpublic void test02() throws Exception {Class clazz = Car.class;//獲取所有構造// getConstructors()獲取所有public的構造方法
//        Constructor[] constructors = clazz.getConstructors();// getDeclaredConstructors()獲取所有的構造方法public  privateConstructor[] constructors = clazz.getDeclaredConstructors();for (Constructor c:constructors) {System.out.println("方法名稱:"+c.getName()+" 參數個數:"+c.getParameterCount());}//指定有參數構造創建對象//1 構造public
//        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
//        Car car1 = (Car)c1.newInstance("夏利", 10, "紅色");
//        System.out.println(car1);//2 構造privateConstructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);c2.setAccessible(true);Car car2 = (Car)c2.newInstance("捷達", 15, "白色");System.out.println(car2);}//3、獲取屬性@Testpublic void test03() throws Exception {Class clazz = Car.class;Car car = (Car)clazz.getDeclaredConstructor().newInstance();//獲取所有public屬性//Field[] fields = clazz.getFields();//獲取所有屬性(包含私有屬性)Field[] fields = clazz.getDeclaredFields();for (Field field:fields) {if(field.getName().equals("name")) {//設置允許訪問field.setAccessible(true);field.set(car,"五菱宏光");System.out.println(car);}System.out.println(field.getName());}}//4、獲取方法@Testpublic void test04() throws Exception {Car car = new Car("奔馳",10,"黑色");Class clazz = car.getClass();//1 public方法Method[] methods = clazz.getMethods();for (Method m1:methods) {//System.out.println(m1.getName());//執行方法 toStringif(m1.getName().equals("toString")) {String invoke = (String)m1.invoke(car);//System.out.println("toString執行了:"+invoke);}}//2 private方法Method[] methodsAll = clazz.getDeclaredMethods();for (Method m:methodsAll) {//執行方法 runif(m.getName().equals("run")) {m.setAccessible(true);m.invoke(car);}}}
}

4.2、實現Spring的IoC

我們知道,IoC(控制反轉)和DI(依賴注入)是Spring里面核心的東西,那么,我們如何自己手寫出這樣的代碼呢?下面我們就一步一步寫出Spring框架最核心的部分。

①搭建子模塊

搭建模塊:guigu-spring,搭建方式如其他spring子模塊

②準備測試需要的bean

添加依賴

<dependencies><!--junit5測試--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.3.1</version></dependency>
</dependencies>

創建UserDao接口

package com.atguigu.spring6.test.dao;public interface UserDao {public void print();
}

創建UserDaoImpl實現

package com.atguigu.spring6.test.dao.impl;import com.atguigu.spring.dao.UserDao;public class UserDaoImpl implements UserDao {@Overridepublic void print() {System.out.println("Dao層執行結束");}
}

創建UserService接口

package com.atguigu.spring6.test.service;public interface UserService {public void out();
}

創建UserServiceImpl實現類

package com.atguigu.spring.test.service.impl;import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.service.UserService;@Bean
public class UserServiceImpl implements UserService {//    private UserDao userDao;@Overridepublic void out() {//userDao.print();System.out.println("Service層執行結束");}
}

③定義注解

我們通過注解的形式加載bean與實現依賴注入

bean注解

package com.atguigu.spring.core.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}

依賴注入注解

package com.atguigu.spring.core.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}

說明:上面兩個注解可以隨意取名

④定義bean容器接口

package com.atguigu.spring.core;public interface ApplicationContext {Object getBean(Class clazz);
}

⑤編寫注解bean容器接口實現

AnnotationApplicationContext基于注解掃描bean

package com.atguigu.spring.core;import java.util.HashMap;public class AnnotationApplicationContext implements ApplicationContext {//存儲bean的容器private HashMap<Class, Object> beanFactory = new HashMap<>();@Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}/*** 根據包掃描加載bean* @param basePackage*/public AnnotationApplicationContext(String basePackage) {}
}

⑥編寫掃描bean邏輯

我們通過構造方法傳入包的base路徑,掃描被@Bean注解的java對象,完整代碼如下:

package com.atguigu.spring.core;import com.atguigu.spring.core.annotation.Bean;import java.io.File;
import java.util.HashMap;public class AnnotationApplicationContext implements ApplicationContext {//存儲bean的容器private HashMap<Class, Object> beanFactory = new HashMap<>();private static String rootPath;@Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}/*** 根據包掃描加載bean* @param basePackage*/public AnnotationApplicationContext(String basePackage) {try {String packageDirName = basePackage.replaceAll("\\.", "\\\\");Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url = dirs.nextElement();String filePath = URLDecoder.decode(url.getFile(),"utf-8");rootPath = filePath.substring(0, filePath.length()-packageDirName.length());loadBean(new File(filePath));}} catch (Exception e) {throw new RuntimeException(e);}}private  void loadBean(File fileParent) {if (fileParent.isDirectory()) {File[] childrenFiles = fileParent.listFiles();if(childrenFiles == null || childrenFiles.length == 0){return;}for (File child : childrenFiles) {if (child.isDirectory()) {//如果是個文件夾就繼續調用該方法,使用了遞歸loadBean(child);} else {//通過文件路徑轉變成全類名,第一步把絕對路徑部分去掉String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);//選中class文件if (pathWithClass.contains(".class")) {//    com.xinzhi.dao.UserDao//去掉.class后綴,并且把 \ 替換成 .String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");try {Class<?> aClass = Class.forName(fullName);//把非接口的類實例化放在map中if(!aClass.isInterface()){Bean annotation = aClass.getAnnotation(Bean.class);if(annotation != null){Object instance = aClass.newInstance();//判斷一下有沒有接口if(aClass.getInterfaces().length > 0) {//如果有接口把接口的class當成key,實例對象當成valueSystem.out.println("正在加載【"+ aClass.getInterfaces()[0] +"】,實例對象是:" + instance.getClass().getName());beanFactory.put(aClass.getInterfaces()[0], instance);}else{//如果有接口把自己的class當成key,實例對象當成valueSystem.out.println("正在加載【"+ aClass.getName() +"】,實例對象是:" + instance.getClass().getName());beanFactory.put(aClass, instance);}}}} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {e.printStackTrace();}}}}}}}

⑦java類標識Bean注解

@Bean
public class UserServiceImpl implements UserService
@Bean
public class UserDaoImpl implements UserDao 

⑧測試Bean加載

package com.atguigu.spring;import com.atguigu.spring.core.AnnotationApplicationContext;
import com.atguigu.spring.core.ApplicationContext;
import com.atguigu.spring.test.service.UserService;
import org.junit.jupiter.api.Test;public class SpringIocTest {@Testpublic void testIoc() {ApplicationContext applicationContext = new AnnotationApplicationContext("com.atguigu.spring.test");UserService userService = (UserService)applicationContext.getBean(UserService.class);userService.out();System.out.println("run success");}
}

控制臺打印測試

⑨依賴注入

只要userDao.print();調用成功,說明就注入成功

package com.atguigu.spring.test.service.impl;import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.core.annotation.Di;
import com.atguigu.spring.dao.UserDao;
import com.atguigu.spring.service.UserService;@Bean
public class UserServiceImpl implements UserService {@Diprivate UserDao userDao;@Overridepublic void out() {userDao.print();System.out.println("Service層執行結束");}
}

執行第八步:報錯了,說明當前userDao是個空對象

⑩依賴注入實現

package com.atguigu.spring.core;import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.core.annotation.Di;import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class AnnotationApplicationContext implements ApplicationContext {//存儲bean的容器private HashMap<Class, Object> beanFactory = new HashMap<>();private static String rootPath;@Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}/*** 根據包掃描加載bean* @param basePackage*/public AnnotationApplicationContext(String basePackage) {try {String packageDirName = basePackage.replaceAll("\\.", "\\\\");Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url = dirs.nextElement();String filePath = URLDecoder.decode(url.getFile(),"utf-8");rootPath = filePath.substring(0, filePath.length()-packageDirName.length());loadBean(new File(filePath));}} catch (Exception e) {throw new RuntimeException(e);}//依賴注入loadDi();}private  void loadBean(File fileParent) {if (fileParent.isDirectory()) {File[] childrenFiles = fileParent.listFiles();if(childrenFiles == null || childrenFiles.length == 0){return;}for (File child : childrenFiles) {if (child.isDirectory()) {//如果是個文件夾就繼續調用該方法,使用了遞歸loadBean(child);} else {//通過文件路徑轉變成全類名,第一步把絕對路徑部分去掉String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);//選中class文件if (pathWithClass.contains(".class")) {//    com.xinzhi.dao.UserDao//去掉.class后綴,并且把 \ 替換成 .String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");try {Class<?> aClass = Class.forName(fullName);//把非接口的類實例化放在map中if(!aClass.isInterface()){Bean annotation = aClass.getAnnotation(Bean.class);if(annotation != null){Object instance = aClass.newInstance();//判斷一下有沒有接口if(aClass.getInterfaces().length > 0) {//如果有接口把接口的class當成key,實例對象當成valueSystem.out.println("正在加載【"+ aClass.getInterfaces()[0] +"】,實例對象是:" + instance.getClass().getName());beanFactory.put(aClass.getInterfaces()[0], instance);}else{//如果有接口把自己的class當成key,實例對象當成valueSystem.out.println("正在加載【"+ aClass.getName() +"】,實例對象是:" + instance.getClass().getName());beanFactory.put(aClass, instance);}}}} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {e.printStackTrace();}}}}}}private void loadDi() {for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){//就是咱們放在容器的對象Object obj = entry.getValue();Class<?> aClass = obj.getClass();Field[] declaredFields = aClass.getDeclaredFields();for (Field field : declaredFields){Di annotation = field.getAnnotation(Di.class);if( annotation != null ){field.setAccessible(true);try {System.out.println("正在給【"+obj.getClass().getName()+"】屬性【" + field.getName() + "】注入值【"+ beanFactory.get(field.getType()).getClass().getName() +"】");field.set(obj,beanFactory.get(field.getType()));} catch (IllegalAccessException e) {e.printStackTrace();}}}}}}

執行第八步:執行成功,依賴注入成功


寫在后面🔥🔥🔥:

林納斯·托瓦茲(Linus Torvalds)說:“我從心底認為,優秀的程序員與平庸的程序員之間的區別,是在于認為自己的代碼重要還是數據結構更加重要。平庸的程序員眼里只有代碼,優秀的程序員則關注數據結構及之前的關系。”

《spring技術內幕:深入解析spring架構與計原理(第2版)》是國內一本系統分析spring源代碼的經典著作,也是spring領域的問鼎之作,由業界擁有10余年開發經驗的資深java專家親自執筆,java開發者社區和spring開發者社區聯袂推薦。本書第1版不僅在內容上獲得了讀者的廣泛好評,而且在銷量上也摘取了同類書的桂冠,曾經一度掀起java類圖書的銷售熱潮。第2版不僅繼承了第1版在內容組織和寫作方式上的優點,而且還根據廣大讀者的反饋改進了若干細節上的不足。更為重要的是,結合spring的最新版本對過時的內容進行了更新,并增加了大量新內容,使本書更趨近于完美。

本專欄是自己深入學習并結合Spring技術內幕一經典圖書內容做出的的心得與總結,將其精簡編寫成一篇專欄供大家學習,希望對新學習Spring框架技術的小伙伴有所幫助。

圖書推薦
在這里插入圖片描述


在這里插入圖片描述

歡迎添加微信,加入我的核心小隊,請備注來意

👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718101.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718101.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718101.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

足球青訓俱樂部|基于Springboot的足球青訓俱樂部管理系統設計與實現(源碼+數據庫+文檔)

足球青訓俱樂部管理系統目錄 目錄 基于Springboot的足球青訓俱樂部管理系統設計與實現 一、前言 二、系統設計 1、系統架構設計 三、系統功能設計 1、管理員登錄界面 2、公告信息管理界面 3、學員管理界面 4、商品信息管理界面 5、課程安排管理界面 四、數據庫設計…

ArcGIS Runtime For Android開發之符號化和圖層渲染

一、用Symbol對要素進行符號化 首先我們看一下Symbol 接口關系&#xff1a; 1、SimpleFillSymbol 他是用來進行簡單的Graphic面要素填充符號化的&#xff0c;它可以設置要素的填充顏色&#xff0c;邊線顏色、線寬&#xff0c;其用法如下&#xff1a; Polygon polygonnew Po…

常用的電阻、電容的種類和應用場合?

電阻的 a.按阻值特性:固定電阻、可調電阻、特種電阻(敏感電阻)&#xff0c;不能調節的,我們稱之為固定電阻,而可以調節的,我們稱之為可調電阻.常見的例如收音機音量調節的,主要應用于電壓分配的,我們稱之為電位器. b.按制造材料:碳膜電阻、金屬膜電阻、線繞電阻&#xff0c;捷…

Go切片特點筆記

特點 1.只有append操作2.支持子切片3.內存共享問題 1.只有append操作 不支持隨機增刪 2.支持子切片 數組和切片都可以通過[start:end] 的形式 來獲取子切片: 1.arr[start:end],獲得[start,end)之間的元素。 2.arr[:end],獲得[0,end)之間的元素。 3.arr[start:],獲得[start,l…

二叉樹葉節點個數,根節點個數,樹的深度,查找數據為x的節點

文章目錄 一、計算二叉樹葉節點個數二、葉節點的個數 引言&#xff1a;補充樹的概念 節點的度&#xff1a;一個節點含有的子樹的個數稱為節點的度 葉節點或終端節點&#xff1a;度為0的節點稱為葉節點 節點的層次&#xff1a;從根開始為第一層&#xff0c;以此類推 樹的度&…

Leetcode150二刷總結

滑動窗口&#xff08;ok&#xff09; 題號&#xff1a;3、209、76 定義好窗口的左邊界left和右邊界right一般是只需要遍歷right&#xff0c;滿足條件后調整left 鏈表 題號&#xff1a;206、92、146、25、21 反轉鏈表主要是設置好pre&#xff08;初始為null&#xff09;和c…

【Godot 4.2】Tree控件與TreeItem完全解析

概述 本篇是控件完全解析系列之一&#xff0c;主要總結一下Tree控件與TreeItem的使用。 Tree控件是一個非常強大的控件&#xff0c;尤其是在編寫一些相關的程序或編輯器插件時&#xff0c;非常適合展示樹形組織的節點型數據。 本篇將從簡單的添加根節點&#xff0c;根節點子…

uniapp和vue項目配置多語言,實現前端切換語言

在uniapp中配置多語言功能&#xff0c;實現前端切換語言&#xff0c;可以按照以下步驟進行&#xff1a; 1. 創建語言包 首先&#xff0c;創建一個名為 lang 的目錄&#xff0c;并在該目錄下為每種支持的語言創建對應的JSON或JS文件。例如&#xff1a; lang/en.js&#xff08…

Threejs之場景標注標簽信息CSS2DRenderer

參考資料 CSS2DRenderer(HTML標簽)…單擊按鈕關閉HTML標簽 知識點 注&#xff1a;基于Three.jsv0.155.0 CSS2DRenderer(HTML標簽) HTML標簽遮擋Canvas畫布事件Canvas尺寸變化(HTML標簽)標簽位置不同設置方式標簽位置(標注工廠設備)標簽指示線或箭頭指向標注點鼠標選中模型…

Microsoft PyRIT能自動化完成AI紅隊的任務

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

兩數相加的問題

題目是&#xff1a;給兩個非空的鏈表&#xff0c;表示兩個非負整數。它們每位數都是按照逆序的方式存儲&#xff0c;并且每一個節點只能存儲一位數字。現在兩個數相加&#xff0c;并且以相同的形式返回一個表示和的鏈表。 首先回顧一下&#xff0c;什么是鏈表&#xff1f;鏈表…

《異常檢測——從經典算法到深度學習》26 Time-LLM:基于大語言模型的時間序列預測

《異常檢測——從經典算法到深度學習》 0 概論1 基于隔離森林的異常檢測算法 2 基于LOF的異常檢測算法3 基于One-Class SVM的異常檢測算法4 基于高斯概率密度異常檢測算法5 Opprentice——異常檢測經典算法最終篇6 基于重構概率的 VAE 異常檢測7 基于條件VAE異常檢測8 Donut: …

使用遞歸方法和類數組兩種方法計算斐波那契數列

菲波納契數列又稱"菲波納契神奇數列"&#xff0c;是由13世紀的意大利數學家菲波納契提出的&#xff0c;當時是和兔子的繁殖問題有關的&#xff0c;它是一個很重要的數學模型。這個問題是:有小兔一對&#xff0c;若第二個月它們成年&#xff0c;第三個月生下小兔一對&…

3333666777

? 通用計算機啟動過程 1??一個基礎固件&#xff1a;BIOS 一個基礎固件&#xff1a;BIOS→基本IO系統&#xff0c;它提供以下功能&#xff1a; 上電后自檢功能 Power-On Self-Test&#xff0c;即POST&#xff1a;上電后&#xff0c;識別硬件配置并對其進行自檢&#xff0c…

阿里云倉庫

倉庫服務 (aliyun.com) maven中央倉庫&#xff1a; Central Repository: (maven.org)

Windows10 安裝Neo4j流程

1、下載并安裝ava運行環境 官網鏈接&#xff08;需要注冊Oracle賬號&#xff09;&#xff1a;https://www.oracle.com/java/technologies/downloads/ 根據自己Neo4j版本確認需要的JDK版本 百度網盤鏈接&#xff1a; 鏈接&#xff1a;鏈接&#xff1a;https://pan.baidu.com/s/…

靜態網頁和動態網頁的異同

靜態網頁和動態網頁是兩種不同類型的網頁。它們之間的主要異同點如下&#xff1a; 1. 靜態網頁&#xff1a; - 靜態網頁是指在服務器上預先準備好的網頁&#xff0c;內容固定不變。 - 靜態網頁通常由HTML、CSS和JavaScript等靜態文件組成。 - 用戶訪問靜態網頁時&#xff0c…

Sodinokibi勒索病毒最新變種,解密工具更新到2.0版本

Sodinokibi勒索病毒 Sodinokibi勒索病毒又稱REvil&#xff0c;自從2019年6月1日&#xff0c;GandCrab勒索病毒運營團伙宣布停止運營之后&#xff0c;Sodinokibi勒索病毒馬上接管了GandCrab的大部分傳播渠道&#xff0c;同時它也被稱為是GandCrab勒索病毒的“接班人”&#xff…

VMware 虛擬機安裝windows 10操作系統

先提前準備好鏡像文件 1.創建新的虛擬機 2.選擇自定義&#xff0c;然后下一步 v Windows 建議選擇2G以上&#xff0c;下一步 選擇網絡地址轉換&#xff08;NAT&#xff09;&#xff0c;下一步 這里可按自己的需求來分區&#xff0c;也可以安裝好后再分區 選擇立即重啟&#xff…