java八股文面试[JVM]——如何打破双亲委派模型

news2024/11/23 20:11:47
  1. 双亲委派模型的第一次“被破坏”是重写自定义加载器的loadClass(),jdk不推荐。一般都只是重写findClass(),这样可以保持双亲委派机制.而loadClass方法加载规则由自己定义,就可以随心所欲的加载类,典型的打破双亲委派模型的框架和中间件tomcatosgi

  2. 双亲委派模型的第二次“被破坏”是ServiceLoader和Thread.setContextClassLoader()。即线程上下文类加载器(contextClassLoader)。双亲委派模型很好地解决了各个类加载器的基础类统一问题(越基础的类由越上层的加载器进行加载),基础类之所以被称为“基础”,是因为它们总是作为被调用代码调用的API。但是,如果基础类又要调用用户的代码,那该怎么办呢?线程上下文类加载器就出现了。

    1. SPI。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个;如果在应用程序的全局范围内都没有设置过,那么这个类加载器默认就是应用程序类加载器。了有线程上下文类加载器,JNDI服务使用这个线程上下文类加载器去加载所需要的SPI代码,也就是父类加载器请求子类加载器去完成类加载动作,这种行为实际上就是打通了双亲委派模型的层次结构来逆向使用类加载器,已经违背了双亲委派模型,但这也是无可奈何的事情。Java中所有涉及SPI的加载动作基本上都采用这种方式,例如JNDI,JDBC,JCE,JAXB和JBI等。

    2. 线程上下文类加载器默认情况下就是AppClassLoader,那为什么不直接通过getSystemClassLoader()获取类加载器来加载classpath路径下的类的呢?其实是可行的,但这种直接使用getSystemClassLoader()方法获取AppClassLoader加载类有一个缺点,那就是代码部署到不同服务时会出现问题,如把代码部署到Java Web应用服务或者EJB之类的服务将会出问题,因为这些服务使用的线程上下文类加载器并非AppClassLoader,而是Java Web应用服自家的类加载器,类加载器不同。,所以我们应用该少用getSystemClassLoader()。总之不同的服务使用的可能默认ClassLoader是不同的,但使用线程上下文类加载器总能获取到与当前程序执行相同的ClassLoader,从而避免不必要的问题

  3. 双亲委派模型的第三次“被破坏”是由于用户对程序动态性的追求导致的,这里所说的“动态性”指的是当前一些非常“热门”的名词:代码热替换、模块热部署等,简答的说就是机器不用重启,只要部署上就能用

前言
比较两个类是否“相等”,前提是这两个类由同一个类加载器加载,
否则,即使这两个类来源于同一个Class 文件,被同一个虚拟机加载,
只要加载它们的类加载器不同,那么这两个类就必定不相等。
打破双亲委派

 如下是一个自定义的类加载器TestClassLoader,并重写了findClass和loadClass:

public class TestClassLoader extends ClassLoader {
    public TestClassLoader(ClassLoader parent) {
        super(parent);
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 1、获取class文件二进制字节数组
        byte[] data = null;
        try {
            System.out.println(name);
            String namePath = name.replaceAll("\\.", "\\\\");
            String classFile = "C:\\study\\myStudy\\ZooKeeperLearning\\zkops\\target\\classes\\" + namePath + ".class";
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            FileInputStream fis = new FileInputStream(new File(classFile));
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = fis.read(bytes)) != -1) {
                baos.write(bytes, 0, len);
            }
            data = baos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 2、字节码加载到 JVM 的方法区,
        // 并在 JVM 的堆区建立一个java.lang.Class对象的实例
        // 用来封装 Java 类相关的数据和方法
        return this.defineClass(name, data, 0, data.length);
    }
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException{
        Class<?> clazz = null;
        // 直接自己加载
        clazz = this.findClass(name);
        if (clazz != null) {
            return clazz;
        }

        // 自己加载不了,再调用父类loadClass,保持双亲委托模式
        return super.loadClass(name);
    }
}

测试:初始化自定义的类加载器,需要传入一个parent,指定其父类加载器,那就先指定为加载TestClassLoader的类加载器为TestClassLoader的父类加载器吧:

public static void main(String[] args) throws Exception {
    // 初始化TestClassLoader,被将加载TestClassLoader类的类加载器设置为TestClassLoader的parent
    TestClassLoader testClassLoader = new TestClassLoader(TestClassLoader.class.getClassLoader());
    System.out.println("TestClassLoader的父类加载器:" + testClassLoader.getParent());
    // 加载 Demo
    Class clazz = testClassLoader.loadClass("study.stefan.classLoader.Demo");
    System.out.println("Demo的类加载器:" + clazz.getClassLoader());
}

运行如下测试代码,发现报错了:
找不到java\lang\Object.class,我加载study.stefan.classLoader.Demo类和Object有什么关系呢?

转瞬想到java中所有的类都隐含继承了超类Object,加载study.stefan.classLoader.Demo,也会加载父类Object。Object和study.stefan.classLoader.Demo并不在同个目录,那就找到Object.class的目录(将jre/lib/rt.jar解压),修改TestClassLoader#findClass如下:
遇到前缀为java.的就去找官方的class文件。

运行测试代码:
还是报错了!!! 报错信息为:Prohibited package name: java.lang

看意思是java禁止用户用自定义的类加载器加载java.开头的官方类,也就是说只有启动类加载器BootstrapClassLoader才能加载java.开头的官方类。

得出结论,因为java中所有类都继承了Object,而加载自定义类study.stefan.classLoader.Demo,之后还会加载其父类,而最顶级的父类Object是java官方的类,只能由BootstrapClassLoader加载

跳过AppClassLoaderExtClassLoader
既然如此,先将study.stefan.classLoader.Demo交由BootstrapClassLoader加载即可
由于java中无法直接引用BootstrapClassLoader,所以在初始化TestClassLoader时,传入parent为null,也就是TestClassLoader的父类加载器设置为BootstrapClassLoader:

package com.stefan.DailyTest.classLoader;

public class Test {
    public static void main(String[] args) throws Exception {
        // 初始化TestClassLoader,并将加载TestClassLoader类的类加载器
        // 设置为TestClassLoader的parent
        TestClassLoader testClassLoader = new TestClassLoader(null);
        System.out.println("TestClassLoader的父类加载器:" + testClassLoader.getParent());
        // 加载 Demo
        Class clazz = testClassLoader.loadClass("com.stefan.DailyTest.classLoader.Demo");
        System.out.println("Demo的类加载器:" + clazz.getClassLoader());
    }
}

双亲委派的逻辑在 loadClass,由于现在的类加载器的关系为TestClassLoader —>BootstrapClassLoader,所以TestClassLoader中无需重写loadClass。
运行测试代码:

成功了,Demo类由自定义的类加载器TestClassLoader加载的,双亲委派模型被破坏了。

如果不破坏双亲委派,那么Demo类处于classpath下,就应该是AppClassLoader加载的,所以真正破坏的是AppClassLoader这一层的双亲委派

一个比较完整的自定义类加载器

一般情况下,自定义类加载器都是继承URLClassLoader,具有如下类关系图:

tomcat是如何打破双亲委派的

Tomcat中可以部署多个web项目,为了保证每个web项目互相独立,所以不能都由AppClassLoader加载,所以自定义了类加载器WebappClassLoader,WebappClassLoader继承自URLClassLoader,重写了findClass和loadClass,并且WebappClassLoader的父类加载器设置为AppClassLoader。
WebappClassLoader.loadClass中会先在缓存中查看类是否加载过,没有加载,就交给ExtClassLoader,ExtClassLoader再交给BootstrapClassLoader加载;都加载不了,才自己加载;自己也加载不了,就遵循原始的双亲委派,交由AppClassLoader递归加载。

Web应用默认的类加载顺序是(打破了双亲委派规则):

先从JVM的BootStrapClassLoader中加载。
加载Web应用下/WEB-INF/classes中的类。
加载Web应用下/WEB-INF/lib/*.jap中的jar包中的类。
加载上面定义的System路径下面的类。
加载上面定义的Common路径下面的类。


如果在配置文件中配置了``,那么就是遵循双亲委派规则,加载顺序如下:

先从JVM的BootStrapClassLoader中加载。
加载上面定义的System路径下面的类。
加载上面定义的Common路径下面的类。
加载Web应用下/WEB-INF/classes中的类。
加载Web应用下/WEB-INF/lib/*.jap中的jar包中的类。


1 Tomcat对用户类库与类加载器的规划
在其目录结构下有三组目录(“/common/”、“/server/”、“/shared/”)可以存放Java类库,另外还可以加上Web应用程序本身的目录“/WEB-INF/”,一共4组,把Java类库放置在这些目录中的含义分别如下:

放置在/commom目录中:类库可被Tomcat和所有的Web应用程序共同使用
放置在/server目录中:类库可被Tomcat使用,对所有的Web应用程序都不可见
放置在/shared目录中:类库可被所有的Web应用程序所共同使用,但对Tomcat自己不可见
放置在/WebApp/WEB-INF目录中:类库仅仅可以被此Web应用程序使用,对Tomcat和其他Web应用程序都不可见
为了支持这套目录结构,并对目录里面的类库进行加载和隔离,Tomcat自定义了多个类加载器,这些类加载器按照经典的双亲委派模型来实现,所下图:

最上面的三个类加载器是JDK默认提供的类加载器,这三个加载器的的作用之前也说过,这里不再赘述了,而CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebAppClassLoader则是Tomcat自己定义的类加载器,他们分别加载/common/、/server/、/shared/和/WebApp/WEB-INF/中的Java类库。其中WebApp类加载器和jsp类加载器通常会存在多个实例每一个Web应用程序对应一个WebApp类加载器,每一个jsp文件对应一个Jsp类加载器

从上图的委派关系可以看出,CommonClassLoader能加载的类都可以被CatalinaClassLoader和SharedClassLoader使用,而CatalinaClassLoader和SharedClassLoader自己能加载的类则与对方相互隔离。WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的哪一个Class,它出现的目的就是为了被丢弃:当服务器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过在建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能

tomcat对于不同应用需要有不同的隔离环境
tomcat给每个应用都创建了一个WebApp ClassLoader类加载器
重写了load方法:不再向上查找,而是在本类查找不到后再向上。对于其他的需要共享的例如Redis,可以在上层Share ClassLoader中共享。

OSGI是如何打破双亲委派的

既然说到OSGI,就要来解释一下OSGi是什么,以及它的作用

OSGi(Open Service Gateway Initiative):是OSGi联盟指定的一个基于Java语言的动态模块化规范,这个规范最初是由Sun、IBM、爱立信等公司联合发起,目的是使服务提供商通过住宅网管为各种家用智能设备提供各种服务,后来这个规范在Java的其他技术领域也有不错的发展,现在已经成为Java世界中的“事实上”的模块化标准,并且已经有了Equinox、Felix等成熟的实现。OSGi在Java程序员中最著名的应用案例就是Eclipse IDE

OSGi中的每一个模块(称为Bundle)与普通的Java类库区别并不大,两者一般都以JAR格式进行封装,并且内部存储的都是Java Package和Class。但是一个Bundle可以声明它所依赖的Java Package(通过Import-Package描述),也可以声明他允许导出发布的Java Package(通过Export-Package描述)。在OSGi里面,Bundle之间的依赖关系从传统的上层模块依赖底层模块转变为平级模块之间的依赖(至少外观上如此),而且类库的可见性能得到精确的控制,一个模块里只有被Export过的Package才可能由外界访问,其他的Package和Class将会隐藏起来。除了更精确的模块划分和可见性控制外,引入OSGi的另外一个重要理由是,基于OSGi的程序很可能可以实现模块级的热插拔功能,当程序升级更新或调试除错时,可以只停用、重新安装然后启动程序的其中一部分,这对企业级程序开发来说是一个非常有诱惑性的特性

OSGi之所以能有上述“诱人”的特点,要归功于它灵活的类加载器架构。OSGi的Bundle类加载器之间只有规则,没有固定的委派关系。例如,某个Bundle声明了一个它依赖的Package,如果有其他的Bundle声明发布了这个Package,那么所有对这个Package的类加载动作都会为派给发布他的Bundle类加载器去完成。不涉及某个具体的Package时,各个Bundle加载器是平级关系,只有具体使用某个Package和Class的时候,才会根据Package导入导出定义来构造Bundle间的委派和依赖

另外,一个Bundle类加载器为其他Bundle提供服务时,会根据Export-Package列表严格控制访问范围。如果一个类存在于Bundle的类库中但是没有被Export,那么这个Bundle的类加载器能找到这个类,但不会提供给其他Bundle使用,而且OSGi平台也不会把其他Bundle的类加载请求分配给这个Bundle来处理

一个例子:假设存在BundleA、BundleB、BundleC三个模块,并且这三个Bundle定义的依赖关系如下:

BundleA:声明发布了packageA,依赖了java.*的包
BundleB:声明依赖了packageA和packageC,同时也依赖了Java.*的包
BundleC:声明发布了packageC,依赖了packageA
那么,这三个Bundle之间的类加载器及父类加载器之间的关系如下图:

由于没有涉及到具体的OSGi实现,所以上图中的类加载器没有指明具体的加载器实现,只是一个体现了加载器之间关系的概念模型,并且只是体现了OSGi中最简单的加载器委派关系。一般来说,在OSGi中,加载一个类可能发生的查找行为委派关系会比上图中显示的复杂,类加载时的查找规则如下:

以java.*开头的类,委派给父类加载器加载
否则,委派列表名单内的类,委派给父类加载器加载
否则,Import列表中的类,委派给Export这个类的Bundle的类加载器加载
否则,查找当前Bundle的ClassPath,使用自己的类加载器加载
否则,查找是否在自己的Fragment Bundle中,如果是,则委派给Fragment bundle的类加载器加载
否则,查找Dynamic Import列表的Bundle,委派给对应Bundle的类加载器加载
否则,查找失败
从之前的图可以看出,在OSGi里面,加载器的关系不再是双亲委派模型的树形架构,而是已经进一步发展成了一种更复杂的、运行时才能确定的网状结构

相关面试题:一个类的静态块是否可能被执行两次

一个自于网易面试官的一个问题,一个类的静态块是否可能被执行两次。

答案:如果一个类,被两个 osgi的bundle加载, 然后又有实例被初始化,其静态块会被执行两次

什么是SPI 机制

Spi 机制加载第三方扩展的jar包类初始化。
mysql, dubbo rpc


SPi机制的原理:
java SPI全称Service Provider Interface 。是java 提供的一套用来被第三方实现的API,他可以用来启用框架扩展和替换组件。实际上是基于接口编程+策略模式+配置文件 组合实现的动态加载机制

JDBC

原本的JDBC: Class.forName(“DriverName”) 是通过调用Driver中静态代码块中的将Driver注册

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

使用SPI的JDBC:
在mysql的jar包中的META-INF/services/java.sql.Driver 文件中指明当前使用的Driver,然后可以直接调用

Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?characterEncoding=GBK", "root", "");

问题是 :一个类的加载器和调用他的加载器相同
这里调用的是 bootstrap类加载器,无法加载到子类厂商中的类


方法:使用线程上下文加载器

public class DriverManager {
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    private static void loadInitialDrivers() {
        //省略代码
        //这里就是查找各个sql厂商在自己的jar包中通过spi注册的驱动
        ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
        Iterator<Driver> driversIterator = loadedDrivers.iterator();
        try{
             while(driversIterator.hasNext()) {
                driversIterator.next();
             }
        } catch(Throwable t) {
                // Do nothing
        }

        //省略代码
    }
}

使用Thread类的 getContextClassLoader

    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }
    public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader){
        return new ServiceLoader<>(service, loader);
    }

整个mysql的驱动加载过程:

第一,获取线程上下文类加载器,从而也就获得了应用程序类加载器(也可能是自定义的类加载器)
第二,从META-INF/services/java.sql.Driver文件中获取具体的实现类名“com.mysql.jdbc.Driver”
第三,通过线程上下文类加载器去加载这个Driver类,从而避开了双亲委派模型的弊端

 SPI参考:39 如何破坏双亲委派机制原则 - 简书

知识来源:

JVM问题(一) -- 如何打破双亲委派模型_如何打破双亲委派机制_leo_messi94的博客-CSDN博客

打破双亲委派的几种办法_破坏双亲委派_hhpub的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/970789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java的ssm高校教学业绩信息管理系统源码和论文

基于Java的ssm高校教学业绩信息管理系统源码和论文122 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存…

如何使用Windows Xshell连接另外一台主机上的虚拟机解决方案

前言 我需要使用我自己的笔记本打开虚拟机服务&#xff0c;如何使用我的台式电脑进行服务访问 环境&#xff1a; 台式&#xff1a;Windows10 笔记本&#xff1a;Windows10 网络是由笔记本开放热点&#xff0c;在同一局域网下 正文 首先我们先要看&#xff0c;我们所需要的虚拟…

Python中重要的条件语句教程

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 一. 了解条件语句 假设一个场景&#xff1a; 同学们这个年龄去过网吧吗&#xff1f; 去网吧进门想要上网必须做的一件事是做什么&#xff1f;&#xff08;考虑重点&#xff09; 为什么要把身份证给工作人员&#xf…

【广州华锐互动】利用AR远程指导系统进行机械故障排查,实现远程虚拟信息互动

随着工业自动化和智能化的不断发展&#xff0c;机械故障诊断已经成为了工业生产中的重要环节。为了提高故障诊断的准确性和效率&#xff0c;近年来&#xff0c;AR&#xff08;增强现实&#xff09;远程协助技术逐渐应用于机械故障诊断领域。本文将探讨AR远程协助技术在机械故障…

【方案】智慧园区:AI与视频融合技术如何助力园区监管智能化升级?

一、行业背景 随着科技的不断发展&#xff0c;人工智能&#xff08;AI&#xff09;技术正在各个领域迅速应用和推广。其中&#xff0c;智慧园区是一个重要的应用场景&#xff0c;它通过AI技术的支持&#xff0c;实现了园区的智能化管理和高效运营。 1、园区管理智慧化升级需求…

大数据成为市场营销利器 ,促进金融贷款企业获客精准化

随着大数据技术的不断普及&#xff0c;中国对尖端技术和云计算技术的投资大幅增加。大数据、云计算技术、物联网等一系列新一代信息技术也加速完善。 目前&#xff0c;大数据技术也非常成熟&#xff0c;大数据的应用领域也多种多样。大数据的重要方面“运营商大数据”已经被政…

Qt+C++自建网页浏览器-Chrome blink最新内核基础上搭建-改进版本

程序示例精选 QtC自建网页浏览器-Chrome blink最新内核基础上搭建-改进版本 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC自建网页浏览器-Chrome blink最新内核基础上搭建-改进版…

MySQL性能分析工具的使用

1. 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该如何思考呢&#xff1f;这里把思考的流程整理成下面这张图。 整个流程划分成了 观察&#xff08; Show status &#xff09; 和 行动&#xff08; Action &#xff09; 两个部分。字母 S 的部分…

Vue框架--Vue中的计算属性

下面&#xff0c;我们来实现一个这样的需求。 实现输入框1和输入框2中文字内容的拼接。

你应该知道的几个大数据平台相关术语

你应该知道的几个大数据平台相关术语 1、大数据平台&#xff1a;一个全面的信息处理和分析系统&#xff0c;它能处理和分析海量、多样性的数据&#xff0c;从而为企业提供决策支持。 2、数据脱敏&#xff1a;是指对某些敏感信息通过脱敏规则进行数据的变形&#xff0c;实现敏…

JavaScript(内置对象)

目录 一&#xff0c;JavaScript内置对象二&#xff0c;Array对象2.1&#xff0c;常用属性和方法2.2&#xff0c;基本方法 三&#xff0c;Date对象3.1&#xff0c;常用方法3.2&#xff0c;小案例 四&#xff0c;Math对象 一&#xff0c;JavaScript内置对象 Array&#xff1a;用于…

ToBeWritten之基于ATTCK的威胁狩猎

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

解决IDEA中java的system.properties乱码问题

在拉了别人的代码到本地后发现system.properties中中文注释都变成了乱码&#xff0c;故记录下解决步骤&#xff0c;供参考&#xff0c;我的系统是mac系统 1、在IDEA中打开设置&#xff0c;IDEA--->Preferences 2、点击Editor-->File Encodings 3、图中三处选择UTF-8&…

【设计模式】我终于读懂了职责链模式。。。

文章目录 &#x1f36a;学校 OA 系统的采购审批项目&#x1f36a;传统方案解决OA 系统审批&#xff0c;传统的设计方案(类图)&#x1f36a;传统方案解决OA 系统审批问题分析&#x1f36a;职责链模式基本介绍&#x1f36a;职责链模式的原理类图&#x1f36a;对原理类图的说明-即…

Python+Requests+Pytest+Excel+Allure 接口自动化测试项目实战【框架之间的对比】

--------UnitTest框架和PyTest框架的简单认识对比与项目实战-------- 定义&#xff1a; Unittest是Python标准库中自带的单元测试框架&#xff0c;Unittest有时候也被称为PyUnit&#xff0c;就像JUnit是Java语言的标准单元测试框架一样&#xff0c;Unittest则是Python语言的标…

华为云 异构数据迁移

数据库和应用迁移 UGO&#xff08;Database and Application Migration UGO&#xff0c;以下简称为UGO&#xff09;是专注于异构数据库结构迁移的专业服务。可将源数据库中的DDL、DML和DCL一键自动转换为华为云GaussDB/RDS的SQL语法&#xff0c;通过数据库评估、对象迁移两大核…

本地电脑搭建Web服务器建立一个属于自己的网页该如何操作呢?

本地电脑搭建Web服务器并用cpolar发布至公网访问 文章目录 本地电脑搭建Web服务器并用cpolar发布至公网访问前言1. 首先在电脑安装PHPStudy、WordPress、cpolar2. 安装cpolar&#xff0c;进入Web-UI界面3. 安装wordpress4. 进入wordpress网页安装程序5. 利用cpolar建立的内网穿…

USB Server适用于哪些场景?

具体什么情况适合使用USB Server呢&#xff1f; 一句话&#xff0c; 只要企业内有多个USB设备&#xff0c;就可以考虑使用USB Server。 目前用USB Server比较多的&#xff0c; 主要还有以下三种情况&#xff0c; 虚拟机中要连接USB 必须使用USB Server 来实现加密狗或者前…

架构设计基础设施保障IaaS之网络

目录 1 DNS运用1.1 DNS功能作用1.2 DNS配置实践 2 DNS生产最佳实践方案2.1 全球加速功能2.2 不同运营商的加速方案2.3 全球业务高可用方案2.4 跨地域负载均衡 3 DNS域名劫持解决方案4 CDN剖析4.1 CDN原理4.2 缓存过期配置处理流程4.3 缓存配置规则 5 CDN运用6 CDN最佳实践方案6…