当前位置: 首页 > news >正文

Spring依赖注入的魔法:深入DI的实现原理【beans 五】

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

Spring依赖注入的魔法:深入DI的实现原理【beans 五】

    • 前言
    • DI的基本概念
      • 基本概念:
      • 为什么使用依赖注入:
    • 构造器注入
      • 构造器注入的基本概念:
      • 示例:
      • 多个构造函数的处理:
    • Setter方法注入
      • Setter方法注入的基本概念:
      • 示例:
      • 可选性的Setter方法:
    • 接口注入
      • 1. 定义接口:
      • 2. 实现接口:
      • 3. 使用注入后的依赖:
    • 自动装配
      • 1. 根据类型进行自动装配:
      • 2. 根据名称进行自动装配:
      • 3. 字段和方法参数的自动装配:
    • Qualifier注解
      • 示例:
    • Primary注解
      • 示例:
    • 使用java配置进行DI
      • 1. 创建一个接口和两个实现类:
      • 2. 创建一个Java配置类:
      • 3. 使用配置类进行依赖注入:

前言

在软件开发的舞台上,依赖注入是一个强大的设计模式,而Spring框架以其优雅的实现而脱颖而出。你可能已经使用了DI,但你是否真正了解它的实现原理呢?在这篇文章中,我们将打开DI的黑盒,揭开Spring DI的神秘面纱,让你更深刻地理解这一关键的框架特性。

DI的基本概念

依赖注入(Dependency Injection,简称DI)是一种软件设计模式,它用于解耦组件之间的依赖关系。在依赖注入中,组件不再负责自己依赖的对象的创建和管理,而是由外部容器(通常是一个框架或容器)负责注入依赖的对象。这种注入通常通过构造函数、方法或属性进行。

基本概念:

  1. 依赖(Dependency): 表示一个对象需要另一个对象来完成特定的功能。例如,一个类可能依赖于一个数据库连接、一个服务类或其他组件。

  2. 注入(Injection): 表示将依赖关系注入到类中。这可以通过构造函数、方法参数或属性来实现。

为什么使用依赖注入:

  1. 解耦: 依赖注入有助于降低组件之间的耦合度。组件不再直接创建或管理它们的依赖关系,而是由外部容器负责。这样,组件之间的关系更加灵活,更容易修改和维护。

  2. 可测试性: 依赖注入使得组件更容易进行单元测试。因为依赖关系被注入,测试时可以使用模拟对象或桩对象替代真实的依赖,从而更容易进行单元测试。

  3. 可维护性: 通过将依赖关系的创建和管理移到外部容器中,代码变得更加清晰、简洁,并且更容易理解和维护。每个组件只需要关注自己的功能,而不必关心如何创建和管理依赖关系。

  4. 灵活性: 依赖注入提供了更大的灵活性,可以轻松更改组件之间的关系,而无需修改组件本身的代码。这使得系统更容易适应变化和演进。

  5. 可重用性: 通过将依赖关系解耦,依赖注入可以促使更多的组件变得可重用。一个组件可以在不同的上下文中使用,而不必担心它的依赖关系。

总体而言,依赖注入是一种有助于提高代码质量、可维护性和可测试性的设计模式,特别是在大型项目和团队中。它有助于创建更灵活、可扩展且易于维护的应用程序。

构造器注入

构造器注入是一种依赖注入的方式,通过构造函数来注入一个类的依赖。在Spring中,构造器注入是一种推荐的注入方式,因为它能够确保依赖在对象创建时就被满足,从而提高对象的不可变性和一致性。以下是构造器注入的基本概念和多个构造函数的处理方法。

构造器注入的基本概念:

  1. 构造函数(Constructor): 一个类的构造函数是用于创建对象的方法。在构造函数中,可以接受依赖关系所需的参数。

  2. 构造器注入(Constructor Injection): 将依赖关系通过构造函数的参数进行注入。这意味着对象在被创建时,其依赖关系必须通过构造函数提供。

示例:

public class MyService {private final MyDependency myDependency;// 构造函数注入public MyService(MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,MyService通过构造函数接受一个MyDependency的实例,从而实现了构造器注入。

多个构造函数的处理:

如果一个类有多个构造函数,Spring会尽量通过匹配参数类型和数量的方式选择合适的构造函数。但是,在有多个构造函数的情况下,可能会出现歧义,需要通过@Autowired@Qualifier注解来明确指定使用哪个构造函数。

public class MyService {private final MyDependency myDependency;// 主要的构造函数@Autowiredpublic MyService(MyDependency myDependency) {this.myDependency = myDependency;}// 辅助的构造函数@Autowiredpublic MyService(MyDependency myDependency, OtherDependency otherDependency) {this.myDependency = myDependency;// 处理其他依赖}// 其他业务逻辑
}

在上述例子中,通过@Autowired注解标注了两个构造函数,Spring会选择匹配的构造函数来注入依赖。如果需要明确指定使用哪个构造函数,可以使用@Qualifier注解。

public class MyService {private final MyDependency myDependency;// 主要的构造函数@Autowiredpublic MyService(@Qualifier("primaryMyDependency") MyDependency myDependency) {this.myDependency = myDependency;}// 辅助的构造函数@Autowiredpublic MyService(@Qualifier("secondaryMyDependency") MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在这个例子中,@Qualifier注解用于指定使用哪个具体的MyDependency的实例。

总的来说,构造器注入是一种简单、直观、推荐的依赖注入方式,通过构造函数接受依赖关系,使得对象的创建和初始化更加清晰和可控。在有多个构造函数的情况下,通过@Autowired@Qualifier来进行注解可以更好地处理依赖关系。

Setter方法注入

Setter方法注入是一种通过Setter方法将依赖关系注入到类中的方式。在Spring中,这是另一种常见的依赖注入方式,特别适用于那些希望在对象创建后灵活设置依赖关系的情况。以下是Setter方法注入的基本概念和可选性的Setter方法的处理方法。

Setter方法注入的基本概念:

  1. Setter方法: 一个类中的Setter方法用于设置对象的属性或依赖关系。

  2. Setter方法注入: 将依赖关系通过Setter方法进行注入。这意味着对象在创建后,通过调用相应的Setter方法来提供依赖。

示例:

public class MyService {private MyDependency myDependency;// Setter方法注入public void setMyDependency(MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,MyService通过一个名为setMyDependency的Setter方法接受一个MyDependency的实例,从而实现了Setter方法注入。

可选性的Setter方法:

有时候,某个依赖关系可能是可选的,这时你可以通过使用@Autowired注解的required属性为Setter方法设置可选性。如果required属性设置为false,则该依赖关系是可选的,如果找不到匹配的Bean,Spring容器不会报错,而是跳过这个Setter方法的注入。

public class MyService {private MyDependency myDependency;// 可选性的Setter方法注入@Autowired(required = false)public void setMyDependency(MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,setMyDependency方法被标注为可选的,如果找不到匹配的MyDependency的Bean,Spring容器不会报错。

Setter方法注入的优势在于它提供了更灵活的方式来设置依赖关系,特别适用于那些依赖关系不是必需的情况。然而,在某些情况下,Setter方法注入可能导致对象处于不完全初始化的状态,因此需要谨慎使用。

接口注入

在Spring中,你可以通过在接口中定义依赖注入的方法,然后在实现这个接口的类中实现该方法,来实现接口注入。这种方式通常用于在接口中定义一些默认的行为或配置,然后在实现类中进行具体的依赖注入。以下是一个简单的示例:

1. 定义接口:

public interface DependencyInjectable {void injectDependency(MyDependency myDependency);
}

在上述例子中,DependencyInjectable接口定义了一个名为injectDependency的方法,用于依赖注入。

2. 实现接口:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class MyService implements DependencyInjectable {private MyDependency myDependency;// 实现接口的依赖注入方法@Override@Autowiredpublic void injectDependency(MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,MyService类实现了DependencyInjectable接口,并在该类中使用@Autowired注解实现了injectDependency方法的依赖注入。

3. 使用注入后的依赖:

public class AnotherService {private final DependencyInjectable dependencyInjectable;public AnotherService(DependencyInjectable dependencyInjectable) {this.dependencyInjectable = dependencyInjectable;}public void performOperation() {// 使用注入后的依赖dependencyInjectable.injectDependency(new MyDependency());// 其他操作}
}

在上述例子中,AnotherService类通过构造函数注入了一个实现了DependencyInjectable接口的实例,并在performOperation方法中调用了injectDependency方法。

接口注入的主要优势在于它可以在接口中定义一些默认的行为或配置,然后在实现类中选择性地实现或覆盖这些方法。这使得接口可以在不同的实现类中具有不同的依赖注入逻辑,提供更大的灵活性。但需要注意的是,这种方式可能导致实现类对Spring的依赖,因此在使用时需要谨慎。

自动装配

在Spring中,@Autowired注解用于实现自动装配(Autowired),它可以自动将匹配类型的Bean注入到目标类的字段、构造函数或方法参数中。自动装配可以根据类型和名称进行匹配。以下是关于@Autowired注解的使用示例:

1. 根据类型进行自动装配:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class MyService {private final MyDependency myDependency;// 根据类型进行自动装配@Autowiredpublic MyService(MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,MyService类通过构造函数使用@Autowired注解自动注入了一个MyDependency类型的Bean。

2. 根据名称进行自动装配:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;@Component
public class AnotherService {private final MyDependency myDependency;// 根据名称进行自动装配@Autowiredpublic AnotherService(@Qualifier("specificDependency") MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,AnotherService类通过构造函数使用@Autowired注解自动注入了一个名为specificDependencyMyDependency类型的Bean。使用了@Qualifier注解来指定具体的Bean名称。

3. 字段和方法参数的自动装配:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;@Component
public class YetAnotherService {private MyDependency myDependency;// 字段自动装配@Autowired@Qualifier("specificDependency")private AnotherDependency anotherDependency;// 方法参数自动装配@Autowiredpublic void setMyDependency(@Qualifier("specificDependency") MyDependency myDependency) {this.myDependency = myDependency;}// 其他业务逻辑
}

在上述例子中,YetAnotherService类通过字段和方法参数分别使用@Autowired注解实现了字段和方法参数的自动注入。同样使用了@Qualifier注解来指定具体的Bean名称。

@Autowired注解是Spring中最常用的自动装配注解之一,它简化了依赖注入的过程,提高了代码的可读性和可维护性。通过@Qualifier注解,你可以更精确地控制自动装配的具体Bean。

Qualifier注解

@Qualifier注解是Spring框架提供的一种用于解决多个同类型Bean自动装配问题的机制。当有多个相同类型的Bean存在于容器中,@Qualifier注解可以与@Autowired注解一起使用,通过指定Bean的名称来明确指定要注入的具体Bean。以下是一个简单的示例:

示例:

假设有两个实现了同一个接口的Bean:

public interface MyInterface {// 接口定义
}
import org.springframework.stereotype.Component;@Component("beanA")
public class BeanA implements MyInterface {// 实现
}
import org.springframework.stereotype.Component;@Component("beanB")
public class BeanB implements MyInterface {// 实现
}

然后在另一个类中进行自动装配:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;@Component
public class MyService {private final MyInterface myInterface;// 使用@Qualifier指定具体Bean的名称@Autowiredpublic MyService(@Qualifier("beanB") MyInterface myInterface) {this.myInterface = myInterface;}// 其他业务逻辑
}

在上述例子中,MyService类通过构造函数使用@Autowired注解进行自动装配,而通过@Qualifier("beanB")注解明确指定了要注入的Bean的名称为"beanB"。这样,在存在多个实现了MyInterface接口的Bean时,Spring就能够根据@Qualifier注解找到特定的Bean来进行注入。

总体而言,@Qualifier注解是一个有效的工具,用于解决多个同类型Bean的自动装配问题。在使用时,需要确保指定的Bean名称与实际的Bean定义名称一致。

Primary注解

@Primary注解是Spring框架提供的一种机制,用于标记一个Bean作为首选的Bean。当有多个同类型的Bean存在于容器中,并且没有使用@Qualifier注解指定具体要注入的Bean时,Spring容器会优先选择标记了@Primary注解的Bean进行注入。这有助于解决多个同类型Bean的歧义性。

以下是一个简单的示例:

示例:

假设有两个实现了同一个接口的Bean:

public interface MyInterface {// 接口定义
}
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;@Component
@Primary
public class PrimaryBean implements MyInterface {// 实现
}
import org.springframework.stereotype.Component;@Component
public class SecondaryBean implements MyInterface {// 实现
}

在上述例子中,PrimaryBean类使用了@Primary注解,标记为首选的Bean。

然后在另一个类中进行自动装配:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class MyService {private final MyInterface myInterface;// 由于PrimaryBean标记了@Primary,它会被首选注入@Autowiredpublic MyService(MyInterface myInterface) {this.myInterface = myInterface;}// 其他业务逻辑
}

在上述例子中,MyService类通过构造函数使用@Autowired注解进行自动装配,由于PrimaryBean标记了@Primary注解,它会被首选注入到myInterface字段中。

总体而言,@Primary注解是一种方便的机制,用于解决多个同类型Bean的自动装配问题,使得Spring容器能够明确知道首选的Bean是哪个。需要注意的是,使用@Primary注解时,确保只在必要的情况下使用,以避免引入歧义。****

使用java配置进行DI

在Spring中,可以使用Java配置类(通过@Configuration注解标记的类)和@Bean注解来实现依赖注入。以下是一个简单的示例,演示了如何使用Java配置进行依赖注入:

1. 创建一个接口和两个实现类:

// MyInterface.java
public interface MyInterface {void myMethod();
}
// MyImplementationA.java
public class MyImplementationA implements MyInterface {@Overridepublic void myMethod() {System.out.println("MyImplementationA");}
}
// MyImplementationB.java
public class MyImplementationB implements MyInterface {@Overridepublic void myMethod() {System.out.println("MyImplementationB");}
}

2. 创建一个Java配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic MyInterface myImplementationA() {return new MyImplementationA();}@Beanpublic MyInterface myImplementationB() {return new MyImplementationB();}
}

在上述例子中,AppConfig类使用了@Configuration注解标记为Java配置类,并通过@Bean注解定义了两个Bean,分别是myImplementationAmyImplementationB

3. 使用配置类进行依赖注入:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;@Component
public class MyService {private final MyInterface myInterface;@Autowiredpublic MyService(MyInterface myInterface) {this.myInterface = myInterface;}public void performOperation() {myInterface.myMethod();}public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);MyService myService = context.getBean(MyService.class);myService.performOperation();context.close();}
}

在上述例子中,MyService类通过构造函数注入了一个MyInterface类型的Bean,而这个Bean的具体实现是通过AppConfig配置类定义的。在main方法中,通过AnnotationConfigApplicationContext加载配置类,然后获取MyService的Bean并调用performOperation方法。

这样,就实现了通过Java配置进行依赖注入。这种方式使得依赖关系更清晰,同时能够充分利用Java的编程能力进行灵活的配置。

相关文章:

Spring依赖注入的魔法:深入DI的实现原理【beans 五】

欢迎来到我的博客,代码的世界里,每一行都是一个故事 Spring依赖注入的魔法:深入DI的实现原理【beans 五】 前言DI的基本概念基本概念:为什么使用依赖注入: 构造器注入构造器注入的基本概念:示例&#xff1a…...

【学习笔记】1、数字逻辑概论

1.1 数字信号 数字信号,在时间和数值上均是离散的。数字信号的表达方式:二值数字逻辑和逻辑电平描述的数字波形。 (1) 数字波形的两种类型 数值信号又称为“二值信号”。数字波形又称为“二值位形图”。 什么是一拍 一定的时…...

设置代理IP地址对网络有什么影响?爬虫代理IP主要有哪些作用?

在互联网的广泛应用下,代理IP地址成为了一种常见的网络技术。代理IP地址可以改变用户的上网行为,进而影响网络访问的速度和安全性。本篇文章将探讨设置代理IP地址对网络的影响,以及爬虫代理IP的主要作用。 首先,让我们来了解一下代…...

聊聊jvm的mapped buffer的统计

序 本文主要研究一下jvm的mapped buffer的统计 示例 private void writeDirectBuffer() {// 分配一个256MB的直接缓冲区ByteBuffer buffer ByteBuffer.allocateDirect(256 * 1024 * 1024);// 填充数据Random random new Random();while (buffer.remaining() > 4) {buff…...

matrix-breakout-2-morpheus 靶场 练习思路

arp-scan -l 获取目标机器的IP nmap -sV -A IP 查看目标机器开放的端口 gobuster dir -u http://192.168.29.130 -x php,txt,jsp,asp -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt 爆破目标机器的文件目录,找到可以访问的文件路径 http://192.168…...

【Flutter 开发实战】Dart 基础篇:从了解背景开始

想要学会用 Flutter 开发 App,就不可避免的要学习另一门很有意思的编程语言 —— Dart。很多小伙伴可能在学习 Flutter 之前可能都没听说过这门编程语言,我也是一样,还以为 Dart 是为了 Flutter 而诞生的;然而,当我们去…...

西电期末1017.有序序列插值

一.题目 二.分析与思路 简单题。主要考察简单的排序&#xff0c;最后的插入数据同样不用具体实现&#xff0c;只需在输出时多输出一下即可&#xff0c;注意顺序&#xff01;&#xff01; 三.代码实现 #include<bits/stdc.h>//万能头 int main() {int n;scanf("%d…...

day10 用栈实现队列 用队列实现栈

题目1&#xff1a;232 用栈实现队列 题目链接&#xff1a;232 用栈实现队列 题意 用两个栈实现先入先出队列&#xff08;一个入栈&#xff0c;一个出栈&#xff09;&#xff0c;实现如下功能&#xff1a; 1&#xff09;push&#xff1a;将元素x推到队列末尾 2&#xff09;…...

解决跨域问题(SpringBoot)

“什么是跨域&#xff1f;” 跨域 &#xff08;Cross-Origin&#xff09; 是指在浏览器的同源策略&#xff08;Same-Origin Policy&#xff09;下&#xff0c;一个网页的源&#xff08;指协议、域名、端口号的组合&#xff09;与另一个网页的源不同。因此&#xff0c;不同源的…...

LeetCode——2487. 从链表中移除节点

通过万岁&#xff01;&#xff01;&#xff01; 题目&#xff1a;给你一个链表&#xff0c;然后让你从链表中移除一些节点&#xff0c;移除的规则就是我们选择的这个节点在原链表中往右不能有比这个节点大的值。思路&#xff1a;这个题我最开始以为是双指针&#xff0c;然后找…...

云原生和Kubernetes如何简化应用程序开发

在谈论当前技术时,“云计算”正变得非常普遍,作为开发人员,将会继续体验使用云计算应用程序的优势;在云计算中,另一个正在出现的术语是云原生。在进入实际话题之前,首先了解一下云原生到底是什么。 深入了解云原生应用 现在,世界各地的公司都了解云计算应用程序可以带来…...

点云从入门到精通技术详解100篇-基于深度学习的室内场景三维点云语义分割(续)

目录 CSegNet 语义分割模型构建 3.1 引言 3.2 偏移注意机制 3.3 网络主干 3.4 边缘卷积模块...

RabbitMQ消息可靠性保证机制3--消费端ACK机制

消费端ACK机制 ​ 在这之前已经完成了发送端的确认机制。可以保证数据成功的发送到RabbitMQ&#xff0c;以及持久化机制&#xff0c;然尔这依然无法完全保证整个过程的可靠性&#xff0c;因为如果消息被消费过程中业务处理失败了&#xff0c;但是消息却已经被标记为消费了&…...

Copilot在Pycharm的应用和示例

Copilot 是 Github 在 2021 年发布的 AI 代码助手工具&#xff0c;它可以根据你提供的上下文信息&#xff0c;自动生成代码建议&#xff0c;帮助提高代码编写效率和准确性。在 Pycharm 中使用 Copilot&#xff0c;可以进一步提升 Python 开发效率&#xff0c;本文将分享如何在 …...

搜维尔科技:【简报】第九届元宇宙数字人设计大赛,报名已经进入白热化阶段!

随着元宇宙时代的来临&#xff0c;数字人设计成为了创新前沿领域之一。为了提高大学生元宇宙虚拟人角色策划与美术设计的专业核心能力&#xff0c;我们特别举办了这场元宇宙数字人设计赛道&#xff0c;赛道主题为「AI人工智能科技」 &#xff0c;只要与「AI人工智能科技」相关的…...

性能检测自动化(含内存泄露检测)

一、平台侧实现方案 1、UI case重复执行N次:进入页面,sleep 5s,记录start_time,sleep 30s,记录end_time,性能采集工具全程采集性能数据 2、根据采集到的性能数据,按照N次卡点性能数据:去掉最大的10%、最小的10%,求取平均值,作为单次性能数据结果f(n)…...

iec104和iec61850

iec104和iec61850 IEC104 规约详细解读(一) 协议结构 IEC104 规约详细解读(二)交互流程以及协议解析 61850开发知识总结与分享【1】 Get the necesarry projects next to each other in the same directory; $ git clone https://github.com/robidev/iec61850_open_server.g…...

redis 面试问题 (更新中 ing)

目录 reids 是做什么的为什么那么快有哪些使用场景redis有哪些 数据结构redis 有哪些底层数据结构为什么设计 sds一个 字符串 存储多大容量 stream为什么设计 streamstream 消费者消息丢失stream 消息私信问题 持久化机制redis 持久化机制&#xff0c;优缺点&#xff0c;怎么用…...

力扣(leetcode)第389题找不同(Python)

389.找不同 题目链接&#xff1a;389.找不同 给定两个字符串 s 和 t &#xff0c;它们只包含小写字母。 字符串 t 由字符串 s 随机重排&#xff0c;然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。 示例 1&#xff1a; 输入&#xff1a;s “abcd”, t “abcde…...

Linux_源码编译安装LAMP

1. 安装httpd服务 在配置 Apache 网站服务之前&#xff0c;需要正确安装好 httpd 服务器软件。httpd 服务器的安装可以选用 RPM 安装、源码编译安装这两种方式&#xff0c;前者相对比较简单、快速&#xff0c;但是在功能上存在一定的局限性。在实际的生产环境中&#xff0c;使…...

静态网页设计——清雅古筝网(HTML+CSS+JavaScript)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a; https://www.bilibili.com/video/BV1T64y1K7Zn/?vd_source5f425e0074a7f92921f53ab87712357b 使用技术&#xff1a;HTMLCSSJS&#xff08;…...

实战Flink Java api消费kafka实时数据落盘HDFS

文章目录 1 需求分析2 实验过程2.1 启动服务程序2.2 启动kafka生产 3 Java API 开发3.1 依赖3.2 代码部分 4 实验验证STEP1STEP2STEP3 5 时间窗口 1 需求分析 在Java api中&#xff0c;使用flink本地模式&#xff0c;消费kafka主题&#xff0c;并直接将数据存入hdfs中。 flin…...

爬虫与反爬-localStorage指纹(某易某盾滑块指纹检测)(Hook案例)

概述&#xff1a;本文将用于了解爬虫中localStorage的检测原理以及讲述一个用于检测localStorage的反爬虫案例&#xff0c;最后对该参数进行Hook断点定位 目录&#xff1a; 一、LocalStorage 二、爬虫中localStorage的案例&#xff08;以某盾滑块为例&#xff09; 三、如何…...

聊一聊 webpack 和 vite 的开发服务代理的问题

webpack 和 vite webpackVite重新编辑的问题 changOrigin: true如何定义 /api ? webPack And Vite 都是两个比较好用的打包工具&#xff0c;尤其是 Vite, 几几年流行忘记了&#xff0c;特色就是服务启动极快&#xff0c;实现预加载&#xff0c;感觉 webPack 要比 Vite 要复杂一…...

【鸿蒙4.0】安装DevEcoStudio

1.下载安装包 HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者华为鸿蒙DevEco Studio是面向全场景的一站式集成开发环境,&#xff0c;在鸿蒙官网下载或升级操作系统开发工具DevEco Studio最新版本&#xff0c;SDK配置和下载&#xff0c;2.1支持Mac、Windows操作系统。…...

[概率论]四小时不挂猴博士

贝叶斯公式是什么 贝叶斯公式是概率论中的一个重要定理&#xff0c;用于计算在已知一些先验信息的情况下&#xff0c;更新对事件发生概率的估计。贝叶斯公式的表达式如下&#xff1a; P(A|B) P(B|A) * P(A) / P(B) 其中&#xff0c;P(A|B)表示在事件B发生的条件下事件A发生的概…...

算法通关村第二十关-黄金挑战图的常见算法

大家好我是苏麟 , 今天聊聊图的常见算法 . 图里的算法是很多的&#xff0c;这里我们介绍一些常见的图算法。这些算法一般都比较复杂&#xff0c;我们这里介绍这些算法的基本含义&#xff0c;适合面试的时候装*&#xff0c;如果手写&#xff0c;那就不用啦。 图分析算法&#xf…...

服务器内存不足怎么办?会有什么影响?

服务器内存&#xff0c;也被称为RAM&#xff08;Random Access Memory&#xff09;&#xff0c;是一种临时存储设备&#xff0c;用于临时存放正在运行的程序和数据。它是服务器上的超高速存储介质&#xff0c;可以快速读取和写入数据&#xff0c;提供给CPU进行实时计算和操作。…...

GPT实战系列-简单聊聊LangChain

GPT实战系列-简单聊聊LangChain LLM大模型相关文章&#xff1a; GPT实战系列-ChatGLM3本地部署CUDA111080Ti显卡24G实战方案 GPT实战系列-Baichuan2本地化部署实战方案 GPT实战系列-大话LLM大模型训练 GPT实战系列-探究GPT等大模型的文本生成 GPT实战系列-Baichuan2等大模…...

【读书笔记】《白帽子讲web安全》浏览器安全

目录 第二篇 客户端脚本安全 第2章 浏览器安全 2.1同源策略 2.2浏览器沙箱 2.3恶意网址拦截 2.4高速发展的浏览器安全 第二篇 客户端脚本安全 第2章 浏览器安全 近年来随着互联网的发展&#xff0c;人们发现浏览器才是互联网最大的入口&#xff0c;绝大多数用户使用互联…...

网站底部特效/长沙正规seo优化价格

自定义 ASP.NET UpdatePanel 控件的错误处理.NET Framework 4 其他版本 此主题尚未评级 - 评价此主题 如果在 UpdatePanel 控件中更新部分页时发生错误&#xff0c;则默认行为是显示带有错误消息的浏览器消息框。 本教程将向您演示如何自定义向用户显示错误的方式以及如何自定义…...

工信部网站备案要求/免费推广方法有哪些

“Spring有多快&#xff1f;” 这是 2018 Spring One Platform 中的一场会议。看完会议视频&#xff0c;我自己动手试了一下。下面是我做出的测试结果。 还没有观看视频的朋友推荐看一下&#xff0c;非常有意思。 https://springoneplatform.io/2018/sessions/how-fast-is-s…...

学网站建设好吗/武汉seo网站

javascript里的这两个定时器函数&#xff0c;大家一定耳熟能详&#xff1a; setTimeout("函数()",毫秒)就是开启一个计时器&#xff0c;指定毫秒后执行该函数一次。 有关定时器&#xff0c;javascript还有另一个类似的函数&#xff0c;setInterval("函数()&quo…...

网站建设中gif/网站推广教程

字体是任何设计当中的一个非常重要的一部分&#xff0c;他帮助你传授用户的属于自己的一种特权外观和感觉。轮廓字体就是一种独特的字体&#xff0c;这些字体都拥有一个非常漂亮的透明感。他们是不很常见的或被广泛使用的&#xff0c;这些字体看起来非常完美&#xff0c;可以帮…...

建设官方网站请示/广告设计自学教程

本篇博客主要包括&#xff1a;限流方式、微服务容灾技术选型、Sentinel的使用、Sentinel动态规则持久化Zookeeper 等。 Sentinel动态规则持久化到Zookeeper的代码实现我已经共享到本人的github&#xff0c;有需要的可以下载使用。 github地址:https://github.com/Force-King/…...

企业网站维护怎么做/网络推广页面

相关历史文章&#xff08;阅读本文之前&#xff0c;您可能需要先看下之前的系列 &#xff09;分布式事务「2020年」必学&#xff0c;升职加薪你准备好了吗&#xff1f;事务的基本概念事务的四大特性ACID分布式事务产生的场景前言CAP理论告诉我们分布式系统最多只能满足CAP中的两…...