Spring用到了哪些设计模式?

目录

  • Spring 框架中⽤到了哪些设计模式?
  • 工厂模式
  • 单例模式
    • 1.饿汉式,线程安全
    • 2.懒汉式,线程不安全
    • 3.懒汉式,线程安全
    • 4.双重检查锁(DCL, 即 double-checked locking)
    • 5.静态内部类
    • 6.枚举单例
  • 代理模式
  • 模板模式
  • 包装器(装饰器)模式
  • 观察者模式
  • 适配器模式
  • 责任链模式
  • 策略模式

Spring 框架中⽤到了哪些设计模式?

  • ⼯⼚设计模式 : Spring 使⽤⼯⼚模式通过BeanFactory 、ApplicationContext 创建 bean 对象。
  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  • 代理设计模式 : Spring AOP 功能的实现。
  • 模板⽅法模式 : Spring 中 jdbcTemplate 、hibernateTemplate 等以Template 结尾的对数据库操作的类,它们就使⽤到了模板模式。
  • 包装器(装饰器)设计模式 : 我们的项⽬需要连接多个数据库,⽽且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的⼀个应⽤。
  • 适配器模式 :Spring AOP 的增强或通知(Advice)使⽤到了适配器模式。spring MVC 中也是⽤到了适配器模式适配Controller 。
  • 责任链模式:Spring MVC中的HandlerExecutionChain类,就使用到了责任链模式。
  • 策略模式:Spring 中的 InstantiationStrategy 接口,根据创建对象情况的不同,提供了Spring Bean实例化的三种策略︰默认构造方法、指定构造方法或者工厂方法。这是一种典型的策略模式。

下面分别进行介绍



工厂模式

工厂模式(Factory Patterm)封装了对象创建的过程,使用者不需要关心对象创建的细节。工厂模式分为三种:简单工厂模式、工厂方法模式和抽象工厂模式。在编码中该模式通常都是以*Factory 的形式呈现。
Spring 中的 BeanFactory就是简单工厂模式的体现,我们可以根据 beanName 在 BeanFactory中获取 bean对象;而Spring 中的FactoryBean就是工厂方法模式的体现,我们可以通过实现FactoryBean 接口并实现其getObject()方法来自定义bean对象。

请添加图片描述

请添加图片描述

请添加图片描述




单例模式

单例模式(Singleton Pattern)是最常使用的一种设计模式,它可以确保某一个类只有一个实例,构造⽅法必须是私有的、由⾃⼰创建⼀个静态变量存储实例,对外提供⼀个静态公有⽅法获取实例。在Spring 中,bean 的作用域默认就是单例的。它是通过单例池来确保在Spring容器中只会存在一个对象实例。

单例模式的常⻅写法有:

  • 1.饿汉式,线程安全

    • 优点:线程安全,没有加锁,执⾏效率较⾼
      缺点:不是懒加载,类加载时就初始化,浪费内存空间
  • 2.懒汉式,线程不安全

    • 优点:懒加载
      缺点:线程不安全
  • 3.懒汉式,线程安全(使用synchronized)

    • 优点:懒加载,线程安全
      缺点:效率较低
  • 4.双重检查锁(DCL, 即 double-checked locking)

    • 优点:懒加载,线程安全,效率较⾼
      缺点:实现较复杂
  • 5.静态内部类(推荐)

    • 优点:懒加载,线程安全,效率较⾼,实现简单
  • 6.枚举单例

    • 优点:简单,⾼效,线程安全,可以避免通过反射破坏枚举单例

下面对这些常见写法举例,首先是

1.饿汉式,线程安全

public class Singleton {
	// 1、私有化构造⽅法
	private Singleton(){}
	// 2、定义⼀个静态变量指向⾃⼰类型
	private final static Singleton instance = new Singleton();
	// 3、对外提供⼀个公共的⽅法获取实例
	public static Singleton getInstance() {
		return instance;
	}
}

2.懒汉式,线程不安全

有多个线程同时调⽤时,导致⽣成多个实例

public class Singleton {
	// 1、私有化构造⽅法
	private Singleton(){ }
	// 2、定义⼀个静态变量指向⾃⼰类型
	private static Singleton instance;
	// 3、对外提供⼀个公共的⽅法获取实例
	public static Singleton getInstance() {
		// 判断为 null 的时候再创建对象
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

public class Test {
	public static void main(String[] args) {
		for (int i = 0; i < 3; i++) {
			new Thread(() -> {
				System.out.println("多线程创建的单例:" + Singleton.getInstance());
			}).start();
		}
	}
}
/*
输出结果如下:
多线程创建的单例:
com.example.spring.demo.single.Singleton@18396bd5
多线程创建的单例:
com.example.spring.demo.single.Singleton@7f23db98
多线程创建的单例:
com.example.spring.demo.single.Singleton@5000d44
*/

3.懒汉式,线程安全

懒汉式单例如何保证线程安全呢?通过 synchronized 关键字加锁保证线程安全, synchronized 可以添加在⽅法上⾯,也可以添加在代码块上⾯,这⾥演示添加在⽅法上⾯,存在的问题是每⼀次调⽤ getInstance 获取实例时都需要加锁和释放锁,这样是⾮常影响性能的。

public class Singleton {
	// 1、私有化构造⽅法
	private Singleton(){ }
	// 2、定义⼀个静态变量指向⾃⼰类型
	private static Singleton instance;
	// 3、对外提供⼀个公共的⽅法获取实例
	public synchronized static Singleton getInstance() {
		// 判断为 null 的时候再创建对象
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

4.双重检查锁(DCL, 即 double-checked locking)

public class Singleton {
	// 1、私有化构造⽅法
	private Singleton() {
	}
	
	// 2、定义⼀个静态变量指向⾃⼰类型 注意这里使用了volatile关键字!
	private volatile static Singleton instance;
	
	// 3、对外提供⼀个公共的⽅法获取实例
	public static Singleton getInstance() {
		// 第⼀重检查是否为 null
		if (instance == null) {
			// 使⽤ synchronized 加锁
			synchronized (Singleton.class) {
				// 第⼆重检查是否为 null
				if (instance == null) {
					// new 关键字创建对象不是原⼦操作
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

双重检查是指两次⾮空判断,锁指的是synchronized 加锁。为什么要进⾏双重判断,其实很简单,第⼀重判断,如果实例已经存在,那么就不再需要进⾏同步操作,⽽是直接返回这个实例。如果没有创建,才会进⼊同步块,同步块的⽬的与之前相同,⽬的是为了防⽌有多个线程同时调⽤时,导致⽣成多个实例,当第⼀个抢到锁的调⽤获取了实例之后,这个实例就会被创建,之后的所有调⽤都不会进⼊同步块,直接在第⼀重判断就返回了单例。

关于内部的第⼆重空判断的作⽤,当多个线程⼀起到达锁位置时,进⾏锁竞争,其中⼀个线程获取锁,如果是第⼀次进⼊则为 null,会进⾏单例对象的创建,完成后释放锁,其他线程获取锁后就会被空判断拦截,直接返回已创建的单例对象。

其中最关键的⼀个点就是 volatile 关键字的使用,关于这个关键字的介绍可以看这篇博客。

这⾥为什么要使⽤ volatile ?这是因为 new 关键字创建对象不是原⼦操作,创建⼀个对象会经历下⾯的步骤:

  1. 在堆内存开辟内存空间
  2. 调⽤构造⽅法,初始化对象
  3. 引⽤变量指向堆内存空间

在这里插入图片描述

为了提⾼性能,编译器和处理器常常会对既定的代码执⾏顺序进⾏指令重排序。所以经过指令重排序之后,创建对象的执⾏顺序可能为 1 2 3 或者 1 3 2 ,因此当某个线程在乱序运⾏ 1 3 2 指令的时候,引⽤变量指向堆内存空间,这个对象不为 null,但是没有初始化,其他线程有可能这个时候进⼊了 getInstance 的第⼀个 if(instance == null) 判断不为 nulll ,导致错误使⽤了没有初始化的⾮ null 实例,这样的话就会出现异常,这个就是著名的DCL 失效问题

当我们在引⽤变量上⾯添加 volatile 关键字以后,会通过在创建对象指令的前后添加内存屏障来禁⽌指令重排序,就可以避免这个问题,⽽且对volatile 修饰的变量的修改对其他任何线程都是可⻅的。

5.静态内部类

public class Singleton {
	// 1、私有化构造⽅法
	private Singleton() {
	}
	// 2、对外提供获取实例的公共⽅法
	public static Singleton getInstance() {
		return InnerClass.INSTANCE;
	}
	// 定义静态内部类
	private static class InnerClass{
		private final static Singleton INSTANCE = new Singleton();
	}
}

静态内部类单例是如何实现懒加载的呢?⾸先,我们先了解下类的加载时机。

虚拟机规范要求有且只有 5 种情况必须⽴即对类进⾏初始化(加载、验证、准备需要在此之前开始):

  1. 遇到 new 、getstatic 、putstatic 、invokestatic 这 4 条字节码指令时。⽣成这 4 条指令最常⻅的 Java 代码场景是:使⽤ new 关键字实例化对象的时候、读取或设置⼀个类的静态字段(final 修饰除外,被final 修饰的静态字段是常量,已在编译期把结果放⼊常量池)的时候,以及调⽤⼀个类的静态⽅法的时候。
  2. 使⽤ java.lang.reflect 包⽅法对类进⾏反射调⽤的时候。
  3. 当初始化⼀个类的时候,如果发现其⽗类还没有进⾏过初始化,则需要先触发其⽗类的初始化。
  4. 当虚拟机启动时,⽤户需要指定⼀个要执⾏的主类(包含 main()的那个类),虚拟机会先初始化这个主类。
  5. 当使⽤ JDK 1.7 的动态语⾔⽀持时,如果⼀个java.lang.invoke.MethodHandle 实例最后的解析结果是REF_getStatic 、REF_putStatic 、REF_invokeStatic 的⽅法句柄,则需要先触发这个⽅法句柄所对应的类的初始化。

这 5 种情况被称为是类的主动引⽤,那么,除此之外的所有引⽤类都不会对类进⾏初始化,称为被动引⽤。静态内部类就属于被动引⽤的情况。

当 getInstance()⽅法被调⽤时,InnerClass 才在 Singleton 的运⾏时常量池⾥,把符号引⽤替换为直接引⽤,这时静态对象 INSTANCE 也真正被创建,然后再被 getInstance()⽅法返回出去,这点同饿汉模式。那么 INSTANCE 在创建过程中⼜是如何保证线程安全的呢?

虚拟机会保证⼀个类的<clinit/>⽅法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化⼀个类,那么只会有⼀个线程去执⾏这个类的<clinit>()⽅法,其他线程都需要阻塞等待,直到活动线程执⾏<clinit>() ⽅法完毕。如果在⼀个类的 <clinit>() ⽅法中有耗时很⻓的操作,就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,但如果执⾏<clinit>() ⽅法后,其他线程唤醒之后不会再次进⼊<clinit>() ⽅法。同⼀个加载器下,⼀个类型只会初始化⼀次。),在实际应⽤中,这种阻塞往往是很隐蔽的。
从上⾯的分析可以看出 INSTANCE 在创建过程中是线程安全的,所以说静态内部类形式的单例可保证线程安全,也能保证单例的唯⼀性,同时也延迟了单例的实例化。

6.枚举单例

public enum Singleton {
	INSTANCE;
	public void doSomething(String str) {
		System.out.println(str);
	}
}

//可以直接通过如下⽅式调⽤获取实例:
Singleton singleton = Singleton.INSTANCE;

枚举在 java 中与普通类⼀样,都能拥有字段与⽅法,⽽且枚举实例创建是线程安全的,在任何情况下,它都是⼀个单例。
从枚举的反编译结果可以看到,INSTANCE 被 static final 修饰,所以可以通过类名直接调⽤,并且创建对象的实例是在静态代码块中创建的,因为static 类型的属性会在类被加载之后被初始化,当⼀个 Java 类第⼀次被真正使⽤到的时候静态资源被初始化、Java 类的加载和初始化过程都是线程安全的,所以创建⼀个 enum 类型是线程安全的。




代理模式

代理模式(Proxy Pattern)主要是通过创建一个代理对象来实现对目标对象的访问,以达到保护和增强目标对象的目的。代理模式有两种具体的实现:静态代理和动态代理。Spring 中的AOP就是基于JDK和CGlib这两种动态代理实现的。

这里不展开讲,可以参考这篇文章。



模板模式

模板模式(Template Patterm)就是抽象父类提供一套定义好的方法供子类调用,而其中的某些方法子类会根据自己的情况而进行定制。就好像我们平时用模板写一些东西,但是内容却各不相同。在编码中该模式通常都是以*Template 的形式呈现。
Spring JDBC中的JdbcTemplate、Spring事务管理中的TransactionTemplate就是模板模式的体现。



包装器(装饰器)模式

装饰器模式(Decorator Patterm)允许我们向一个现有的对象添加新的功能,同时又不改变其现有的结构。当我们需要为一个类扩展功能时可以考虑使用装饰器模式,但是该模式的缺点就是需要增加额外的代码。
在Spring 中,装饰器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。

许多编程语⾔使⽤ final 最终关键字来限制对某个类的进⼀步扩展。 复⽤最终类已有⾏为的唯⼀⽅法是使⽤装饰模式: ⽤封装器对其进⾏封装。

当你需要在不改变现有对象结构的情况下动态地添加新功能时,装饰器模式就显得很有用了。想象一下你有一个基础的对象,你希望在其上添加一些额外的功能,但是你不想修改这个对象的代码或者继承它来创建一个新的子类。这时候装饰器模式就能派上用场。


比如,假设你有一个 Coffee 类表示一杯咖啡,它有一个方法 cost() 返回咖啡的价格。现在你想给这个咖啡添加额外的功能,比如加糖、加奶等,但是你不想修改 Coffee 类的代码。这时你可以创建装饰器类,比如 SugarDecorator 和 MilkDecorator,它们都实现了与 Coffee 类相同的接口。在这些装饰器类中,你可以修改 cost() 方法来添加额外的费用,并在其中调用原始对象的 cost() 方法。


通过装饰器模式,你可以轻松地在运行时动态地添加或移除功能,而不必改变原始对象的结构。这与代理模式或继承方式不同,因为代理模式是为了控制对对象的访问,而继承方式则是通过创建新的子类来扩展功能,但这两种方式都可能会改变对象的结构或者引入不必要的复杂性。而装饰器模式则保持了对象的简洁性和灵活性。



观察者模式

观察者模式(Observer Pattern)定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
Spring 中的事件监听机制是观察者模式典型的应用,如ApplicationListener。还有Netty中的基于Selector对象实现的I/O多路复用,通过Selector 一个线程可以监听多个连接的Channel事件。

优点:
被观察者和观察者之间是抽象耦合的;
耦合度较低,两者之间的关联仅仅在于消息的通知;
被观察者⽆需关⼼他的观察者;
⽀持⼴播通信;

缺点:
观察者只知道被观察对象发⽣了变化,但不知变化的过程和缘由;
观察者同时也可能是被观察者,消息传递的链路可能会过⻓,完成所有
通知花费时间较多;
如果观察者和被观察者之间产⽣循环依赖,或者消息传递链路形成闭环,会导致⽆限循环;



适配器模式

适配器模式(Adapter Pattern)可以作为两个不兼容的接口之间的桥梁,它可以使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。在编码中该模式通常都是以*Adapter的形式呈现。
Spring AOP中的 AdvisorAdapter类、Spring MVC中的HandlerAdapter接口,就是适配器模式的典型体现。

用一个简单的例子来说明适配器模式在 Java 中的应用。假设我们有一个旧的日志系统,它有一个名为 OldLogger 的类,但我们希望使用一个新的日志系统,它的接口为 Logger,而不想修改现有的代码。这时候就可以使用适配器模式。

// 目标接口
interface Logger {
    void log(String message);
}

// 被适配者
class OldLogger {
    void logMessage(String msg) {
        System.out.println("OldLogger: " + msg);
    }
}

// 适配器
class OldLoggerAdapter implements Logger {
    private OldLogger oldLogger;

    public OldLoggerAdapter(OldLogger oldLogger) {
        this.oldLogger = oldLogger;
    }

    @Override
    public void log(String message) {
        oldLogger.logMessage(message);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建旧日志系统的实例
        OldLogger oldLogger = new OldLogger();

        // 创建适配器,将旧日志系统适配成新接口
        Logger logger = new OldLoggerAdapter(oldLogger);

        // 使用新接口进行日志记录
        logger.log("This is a message.");
    }
}


责任链模式

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链,在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。在编码中该模式通常都是以*Chain的形式呈现。

责任链模式⾮常简单异常好理解,其应⽤也⼏乎⽆所不在,甚⾄可以这么说从你敲代码的第⼀天起你就不知不觉⽤过了它最原始的裸体结构: switch-case 语句。

责任链模式的应⽤场景:

  • 讲讲责任链模式的应⽤场景当程序需要使⽤不同⽅式处理不同种类请求, ⽽且请求类型和顺序预先未知时, 可以使⽤责任链模式。该模式能将多个处理者连接成⼀条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进⾏处理。这样所有处理者都有机会来处理请求。
  • 当必须按顺序执⾏多个处理者时, 可以使⽤该模式。 ⽆论你以何种顺序将处理者连接成⼀条链, 所有请求都会严格按照顺序通过链上的处理者。比如netty里的ChannelHandler被添加到ChannelPipeline 中,形成处理链。


策略模式

策略模式(Strategy Pattern)属于对象的⾏为模式。其⽤意是针对⼀组算法,将每⼀个算法封装到具有共同接⼝的独⽴的类中,从⽽使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发⽣变化。其主要⽬的是通过定义相似的算法,替换 if else 语句写法,并且可以随时相互替换。

举例: Java.util.List 就是定义了⼀个增( add )、删( remove )、改( set )、查( indexOf )策略,⾄于实现这个策略的ArrayList 、LinkedList 等类,只是在具体实现时采⽤了不同的算法。但因为它们策略⼀样,不考虑速度的情况下,使⽤时完全可以互相替换使⽤。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI 文字转语音工具以及它们的官网收集(值得收藏)

目前比较成熟的 AI 文字转语音工具以及它们的官网&#xff1a; 百度语音合成 (https://ai.baidu.com/tech/speech/tts)&#xff1a; 百度语音合成是百度 AI 推出的语音合成服务&#xff0c;支持多种语言和音色&#xff0c;可以用于语音播报、智能客服、有声阅读等场景。 阿里云…

使用Kaggle API快速下载Kaggle数据集

前言 在使用Kaggle网站下载数据集时&#xff0c;直接在网页上点击下载可能会很慢&#xff0c;甚至会出现下载失败的情况。本文将介绍如何使用Kaggle API快速下载数据集。 具体步骤 安装Kaggle API包 在终端中输入以下命令来安装Kaggle API相关的包&#xff1a; pip install…

对 CSS 工程化的理解

CSS 工程化是为了解决以下问题&#xff1a; 宏观设计&#xff1a;CSS 代码如何组织、如何拆分、模块结构怎样设计&#xff1f;编码优化&#xff1a;怎样写出更好的 CSS&#xff1f;构建&#xff1a;如何处理我的 CSS&#xff0c;才能让它的打包结果最优&#xff1f;可维护性&a…

【计算机网络】第 11、12 问:流量控制和可靠传输机制有哪些?

目录 正文流量控制的基本方法停止-等待流量控制基本原理滑动窗口流量控制基本原理 可靠传输机制1. 停止-等待协议2. 后退 N 帧协议&#xff08;GBN&#xff09;3. 选择重传协议&#xff08;SR&#xff09; 正文 流量控制涉及对链路上的帧的发送速率的控制&#xff0c;以使接收…

哪些开放式耳机平价又好用的?五款超平价品牌推荐深度测评分享!

在当今快节奏的生活中&#xff0c;高品质的音频设备已成为放松身心的重要途径之一。开放式耳机&#xff0c;凭借其出色的音频表现和舒适的佩戴体验&#xff0c;正逐渐成为音乐爱好者的新选择。它们特有的开放设计不仅减轻了耳罩带来的压迫感&#xff0c;还使得用户仿佛置身于音…

四种常用限流算法、固定窗口限流算法、滑动窗口限流算法、漏桶限流算法和令牌桶限流算法

什么是限流&#xff1f; 限流可以被视为服务降级的一种形式&#xff0c;其核心目标是通过控制输入和输出流量来保护系统。通常&#xff0c;一个系统的处理能力是可以预估的&#xff0c;为了确保系统的稳定运行&#xff0c;当流量达到预定的阈值时&#xff0c;必须采取措施限制进…

vue中使用jsmind生成脑图

项目部分参数&#xff1a; vue&#xff1a;2.6.10 node:16.20.0 1、使用命令行安装jsmind&#xff1a; npm i jsmind -S 2、在文件中引入jsmind&#xff0c;并编写渲染jsmind的代码&#xff1a;&#xff1a; <template><!-- jsmind容器 --><divid"jsmi…

C#_泛型_委托

文章目录 泛型泛型的使用泛型的约束委托委托的实例化多播委托委托的调用内置委托类型委托练习泛型委托Lambda表达式(进阶)上期习题答案本期习题 泛型 泛型&#xff08;Generic&#xff09; 是一种规范&#xff0c;它允许我们使用占位符来定义类和方法&#xff0c;编译器会在编…

VLAN实验记录---对抗遗忘

sw1的接口6应该调成混杂模式&#xff0c;因为pc2,4,5,6的pvid各不相同而网段相同&#xff0c;所以往上去路由时应该剥离标记&#xff08;VLAN里面是标记而不是标签&#xff09;出去&#xff0c;这样 路由器上的物理接口用来管理不带标记的流量&#xff0c;而vlan2流量的往上打上…

git的使用日常习惯规范与一些特殊操作

git的使用日常习惯规范与一些特殊操作 操作习惯规范创建本地新分支&#xff0c;推送新分支到云端仓库1.创建一个本地的login分支2.创建新分支后切换到新分支3.推送新分支到云端 git的特殊操作撤回commit&#xff08;取消提交到本地版本库的动作&#xff0c;本地工作区写的代码不…

【LVGL-字库应用】

LVGL-中文字库应用 ■ LVGL-内部字库■ LVGL 内部字库的使用流程&#xff1a; ■ LVGL-自定义字库■ 方法一&#xff1a;C 语言数组&#xff08;内部读取&#xff09;-在线转换工具■ 方法二&#xff1a;C 语言数组&#xff08;内部读取&#xff09;-利用离线字体转换软件&…

Java学习记录第十三天

面向对象编程 核心思想就是OOP&#xff08;面向对象编程&#xff09; 面向过程&面向对象 面向过程思想 步骤清晰简单&#xff0c;第一步做什么&#xff0c;第二步做什么... 面对过程适合处理一些较为简单的问题 面向对象思想 物以类聚&#xff0c;分类的思维模式&…

香港服务器与SEO的关系(香港服务器对SEO影响大吗?)

香港服务器与 SEO 的关系是一个备受关注的话题&#xff0c;不少站长在选择了香港服务器后&#xff0c;便会疑问&#xff1a;香港服务器对SEO的影响是否显著?那么&#xff0c;在这里就跟大家聊聊两者的关系以及影响大小。 其实&#xff0c;不少站长对 SEO 的这种担忧和想法是片…

国内IP代理软件电脑版:深入解析与应用指南

随着互联网技术的快速发展&#xff0c;网络活动日益丰富多样&#xff0c;IP代理软件也因其独特的功能和优势&#xff0c;成为许多电脑用户不可或缺的工具。在国内&#xff0c;由于网络环境的复杂性和特殊性&#xff0c;选择一款稳定、高效的IP代理软件电脑版尤为重要。虎观代理…

Can‘t connect to MySQL server on ‘localhost‘ (10061)

问题展示&#xff1a;在安装sqlyog并连接本地数据库的时候出现该问题 问题分析&#xff1a;没有启动mysql服务

FLV流媒体封装格式

1、FLV 简介 FLV(Flash Video) 是 Adobe 公司推出的一种流媒体格式&#xff0c;由于其封装后的音视频文件体积小、封装简单等特点&#xff0c;非常适合于互联网上使用。目前主流的视频网站基本都支持FLV。采用 FLV 格式封装的文件后缀为.flv。直播场景下拉流比较常见的是 http-…

无人车网关案例:记SV900无人清扫车网关的现场应用

​随着无人驾驶技术的不断发展,无人车辆已经开始广泛应用于物流配送、环境保洁、巡逻监控等众多领域,助力城市运营更加高效智能。而要实现无人车辆的安全可靠运行,关键在于选择一款性能卓越的车载网络通信系统.在这一背景下,星创易联推出了SV900无人车网关系列产品。它集5G/4G网…

kubernetes(K8S)学习(九):K8S之日志监控

K8S之日志监控 一、Log and Monitor1.1 Log1.1.1 容器级别1.1.2 Pod级别1.1.3 组件服务级别1.1.4 LogPilot ES Kibana 1.2 Monitor1.2.1 Prometheus简介1.2.2 Prometheus架构1.2.3 Prometheus知识普及1.2.4 数据采集1.2.5 Prometheus Grafana 二、Trouble Shooting&#xff…

重生奇迹mu 弓箭手有什么技能

1、弓箭手职业技能&#xff1a;多重箭&#xff1a;同时射出三发弓箭&#xff0c;给予复数敌人伤害&#xff0c;根据弓的不同&#xff0c;射出的数量也不同。天堂之箭&#xff1a;弓箭垂直射向天际&#xff0c;准确的落在敌人的头顶上&#xff0c;造成严重的伤害。 2、重生奇迹…

【Unity】TextMeshPro富文本

启用富文本 在Unity里&#xff0c;如果需要使用富文本&#xff0c;首先需要开启Rich Text 如果不开启Rich Text&#xff0c;就会在UI上显示富文本代码 1.粗体 <b>Game</b> Over2.斜体 <i>Game</i> Over3.下划线 <u>Game</u> Over4…