SpringBoot相比于Spring的优点(自动配置和依赖管理)

news2024/11/18 16:37:32

自动配置

例子见真章

我们先看一下我们Spring整合Druid的过程,以及我们使用SpringBoot整合Druid的过程我们就知道我们SpringBoot的好处了。

Spring方式

Spring方式分为两种,第一种就是我们使用xml进行整合,第二种就是使用我们注解进行简化

xml方式

(1)导入坐标

 <!--引入druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency

 (2)书写jdbc.properties文件和 applicationContext.xml配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=1998hjy
< context :property-placeholder location ="classpath:jdbc.properties" />
< bean id ="dataSource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" >
< property name ="driverClass" value ="${jdbc.driver}" />
< property name ="jdbcUrl" value ="${jdbc.url}" />
< property name ="user" value ="${jdbc.username}" />
< property name ="password" value ="${jdbc.password}" />
</ bean >

 这样我们的Druid就成功加载到我们的容器中了。可以看到不管是xml方式还是注解方式我们都需要自己写将dataSource放在IOC容器的过程。

注解方式

(1)导入坐标

(2)书写配置类

@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean("dataSource")
    public DataSource getDataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(username);
        dataSource.setPassword(password);
        return dataSource;
    }

}

 (3)启动类代替xml

@Import({DataSourceConfiguration.class})//注意这是一个数组如果还有别的配置文件直接逗号相连就可以
//标志该类是和核心配置文件
@Configurable
//<context:component-scan base-pakeage="com.itheima"
@ComponentScan("com.itheima") //扫描包

public class SpringConfiguration {
//这就是基于注解开发,我们不在需要applicationContext.xml文件了。里面的Bean使用注解代替
    //配置文件使用配置类来代表 里面的关于数据库的配置文件(我们没有自定义实体类) 我们需要自定义实体类进行接收
}

 SpringBoot方式

使用官方starter(引入此 Starter 就不需要引用 Druid 依赖包了,因为已经包含 Druid 的依赖包了):

(1)导入起步依赖

 <!--引入druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>

(2)配置yml

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/springboot_test?characterEncoding=utf8&serverTimezone=UTC
      username: root
      password: root

 这样就结束了

自定义整合方式

如果我们使用SpringBoot导入的依赖不是起步依赖,那么我们就退化成Spring使用注解方式整合Druid了如下

(1)导入坐标

   <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.8</version>
</dependency>

(2)注册bean到ioc容器

        

@Configuration
public class MyDataSourceConfig {

    /**
     * 配置 Druid 数据源。(Spring Boot 会在 IoC 容器自动读取类型为 DataSource 的对象。故这个 bean 注入后,即与Spring Boot整合好了)
     * @return DruidDataSource 数据源
     * @throws SQLException
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource",ignoreUnknownFields = false) // 读取配置文件中的数据源信息。Druid会以此建立数据库连接
    public DataSource dataSource() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setFilters("stat"); // 开启
        return druidDataSource;
    }

}

 (3)配置yml

server:
  port: 80
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost/abc
    username: root
    password: 12345678

可以看到如果我们不使用starter方式,那么我们就还要想spring一样要注册bean,那么我们springBoot中为什么使用start这种起步依赖就可以不用我们自己注册bean了呢,这就导出了我们今天的主题,自动配置

什么是 SpringBoot 自动装配?

 参考知乎 Spring Boot 自动装配原理与实现 - 知乎 (zhihu.com)

我们现在提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。

引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。

在我看来,自动装配可以简单理解为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。

SpringBoot 是如何实现自动装配

我们先看一下 SpringBoot 的核心注解 SpringBootApplication 。

大概可以把 @SpringBootApplication看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类
  • @ComponentScan:扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilterAutoConfigurationExcludeFilter

@EnableAutoConfiguration 是实现自动装配的重要注解,我们以这个注解入手。

@EnableAutoConfiguration:实现自动装配的核心注解

EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类。

我们现在重点分析下AutoConfigurationImportSelector 类到底做了什么?

AutoConfigurationImportSelector:加载自动装配类

AutoConfigurationImportSelector类的继承体系如下:

可以看出,AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

private static final String[] NO_IMPORTS = new String[0];

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // <1>.判断自动装配开关是否打开
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
          //<2>.获取所有需要装配的bean
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

这里我们需要重点关注一下getAutoConfigurationEntry()方法,这个方法主要负责加载自动配置类的。

该方法调用链如下:

现在我们结合getAutoConfigurationEntry()的源码来详细分析一下:

private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        //<1>.
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //<2>.
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //<3>.
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //<4>.
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

第 1 步:

判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置

第 2 步 :

用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName

第 3 步

获取需要自动装配的所有配置类,读取META-INF/spring.factories

spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

从下图可以看到这个文件的配置内容都被我们读取到了。XXXAutoConfiguration的作用就是按需加载组件。

不光是这个依赖下的META-INF/spring.factories被读取到,所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。

所以,你可以清楚滴看到, druid 数据库连接池的 Spring Boot Starter 就创建了META-INF/spring.factories文件。

如果,我们自己要创建一个 Spring Boot Starter,这一步是必不可少的。

第 4 步 :

到这里可能面试官会问你:“spring.factories中这么多配置,每次启动都要全部加载么?”。

很明显,这是不现实的。我们 debug 到后面你会发现,configurations 的值变小了。

因为,这一步有经历了一遍筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效。

 

@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}

Spring Boot 提供的条件注解

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  • @ConditionalOnClass:当类路径下有指定类的条件下
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web 项 目的条件下

 自己实现一个starter

光说不练假把式,现在就来撸一个 starter,实现自定义线程池

第一步,创建threadpool-spring-boot-starter工程

第二步,引入 Spring Boot 相关依赖

第三步,创建ThreadPoolAutoConfiguration

第四步,在threadpool-spring-boot-starter工程的 resources 包下创建META-INF/spring.factories文件

最后新建工程引入threadpool-spring-boot-starter

测试通过!!!

总结

Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖

SpringBoot的依赖管理

2.1 父项目做依赖管理

每个SpringBoot项目,pom.xml文件都会给我们定义一个parent节点

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

该节点指定了version版本号,所以在pom.xml文件里我们很多引入的jar都没有定义版本号,但这样也不会出错,因为SpringBoot帮我们为一些常用的jar包指定了版本号。

ctrl + 鼠标右键点击进入spring-boot-starter-parent这个jar包,会发现它的父项目是spring-boot-dependencies

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.1.3.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent> 

而在这个jar包里,就声明了很多开发中常用jar的版本号

所以在你pom.xml文件中引入jar的时候,如果该jar在spring-boot-dependencies中定义了版本号,那么你可以不写。如果你想使用其他的版本号,那么也可以在pom.xml中定义version,遵循就近原则。比如你想使用自定义版本号的MySQL驱动,只需在pom.xml中进行定义

<properties>
    <mysql.version>5.1.43</mysql.version>
</properties>

其他 

@Configuration和@Bean注解

@Configuration注解

@Configuration注解表示这个类是个配置类,@Bean注解往容器中注册实例。

@Configuration这个注解可以加在类上,让这个类的功能等同于一个bean xml配置文件,如下:

@Configuration
public class ConfigBean {

}

上面代码类似于下面的xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

</beans>

此时ConfigBean类中没有任何内容,相当于一个空的xml配置文件,此时我们要在ConfigBean类中注册bean,那么我们就要用到@Bean注解了。

@Bean注解

这个注解类似于bean xml配置文件中的bean元素,用来在spring容器中注册一个bean。

@Bean注解用在方法上,表示通过方法来定义一个bean,默认将方法名称作为bean名称,将方法返回值作为bean对象,注册到spring容器中。

@Bean
public User user1() {
    return new User();
}

@Configuration注解 容器中的实例都是单例

@Configuration注解中的proxyBeanMethods属性即代理bean的方法,决定是否是单例模式,默认为true。Full模式(proxyBeanMethods = true)和Lite(proxyBeanMethods = false)模式,Full模式保证每个@Bean方法被调用多少次返回的组件都是单实例的,而Lite模式每个@Bean方法被调用多少次返回的组件都是新创建的。组件依赖必须使用Full模式默认,其他默认是否Lite模式

@Import注解

该注解定义如下,只有一个value属性,你可以传入一个Class数组,在启动过程中,会自动帮你把类注册进容器。

@Configuration
@Import({User.class, DBHelper.class})
public class MyConfig {

}

 @Conditional注解

意思就是满足@Conditional指定的条件,才进行组件注入。

import com.codeliu.entity.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
// 没有名字为test的bean,才进行注册,该注解可以放在类型,也可以放在方法上,作用范围不一样
@ConditionalOnMissingBean(name = "test")
public class MyConfig {
    @Bean
    public User user() {
        User user = new User("秃头哥", 20);
        return user;
    }
}

 @ImportResource注解

@ImportResource注解可以导入Spring的配置文件,让配置文件里的内容生效。因为有些项目bean定义在xml文件里,但你必须知道xml文件的路径,这样在项目启动的时候Spring才会加载配置文件。那对于SpringBoot项目来说,所有的bean都是通过java配置实现,xml没有用武之地了吗?

@Configuration搭配@ImportResource可以实现xml配置的装载。

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource("classpath:beans.xml")
public class MyConfig {

}

 @Component和@ConfigurationProperties

在Java bean上使用这两个注解,可以和配置文件中的属性相关联,不过要注意的是,Java bean必须有setter/getter方法,否则无法赋值,另外就是配置文件中的属性不能有大写字母,否则启动报错。

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "my-user")
public class User {
    private String names;
    private int age;
    ....
}

省略了getter/setter和toString方法。@ConfigurationProperties注解中指定配置文件中相关属性的前缀,在配置文件中

my-user.names=CodeTiger
my-user.age=22

启动类中进行测试获取user对象,输出就会发现属性已经赋值。

@ConfigurationProperties和@EnableConfigurationProperties 

@ConfigurationProperties注解加载java bean上指定前缀,而@EnableConfigurationProperties注解则加在配置类上,该注解有两个作用:开启配置绑定功能、把指定的java bean注册到容器中。因为该注解会把java bean注册到容器中,所以在java bean上就不需要加@Component注解了。

@Configuration
@EnableConfigurationProperties({User.class})
public class MyConfig {

}

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

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

相关文章

ansble

ansble概述 Ansible是一款自动化运维工具&#xff0c;基于Python开发&#xff0c;具有批量系统配置,批量程序部署, 批量运行命令等功能。 Ansible的很多模块在执行时都会先判断目标节点是否要执行任务&#xff0c;所以&#xff0c;可以放心大胆地让Ansible去执行任务&#xf…

汇编的各种指令(数据搬移、移位、位运算、算数、比较、跳转、特殊功能寄存器、单寄存器、多寄存器、栈指针指令)

1.汇编指令的格式 2.数据搬移指令---mov mvn 3.移位操作指令 4.位运算操作指令 5.算数运算操作指令 6.比较指令---cmp 7.跳转指令 例子&#xff1a; 8.特殊功能寄存器指令 内存操作指令 9.单寄存操作指令 10.多寄存操作指令 11.栈指针操作指令 例子&#xff1a; 保存现场&…

线程池是如何实现线程复用的?

线程池里面采用了生产者消费者的模式&#xff0c;来实现线程复用。生产者消费者模型&#xff0c;其实就是通过一个中间容器来解耦生产者和消费者的任务处理过程。 生产者不断生产任务保存到容器&#xff0c;消费者不断从容器中消费任务。在线程池里面&#xff0c;因为需要保证工…

gRPC初体验

一、gRPC简介 1、RPC是远程过程调用的简称&#xff0c;在分布式系统中&#xff0c;客户端可以像调用本地对象一样调用远程机器上服务端对象&#xff0c;用于系统的垂直拆分&#xff0c;常见的JAVA RPC框架有JAVA自带的RMI、基于Http的Hessian、阿里基于TCP的Dubbo、淘宝基于TC…

二叉树题目:路径总和 III

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;路径总和 III 出处&#xff1a;437. 路径总和 III 难度 5 级 题目描述 要求 给你二叉树的根结点 root \textt…

VS2022 打包WPF安装程序最新教程(图文详解)

文章目录 前言一、安装打包Installer插件1、单独安装2、VS中在线安装二、使用步骤1、创建安装项目2、安装项目主界面3、添加项目输出4、添加快捷方式图标5、添加卸载项目a、新建项目b、添加项目输出c、创建快捷方式6、给快捷方式添加图标a、在Resource文件夹中添加图标文件b、选…

通过内网穿透实现在无公网IP下,Windows远程连接MongoDB数据库

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 前言 MongoDB是一个基于分布式文件存储的数…

shopee收货方式有哪些

Shopee 是一家电子商务平台&#xff0c;提供多种不同的收货方式&#xff0c;具体的选项可能会根据您所在的地理位置和商品的类型而有所不同。以下是一些常见的 Shopee 收货方式&#xff1a; 1、快递配送&#xff1a;这是最常见的收货方式&#xff0c;您可以选择让商家使用物流…

开关时的瞬态高电压突变冲击--输入滤波电容可能引起的问题

在开关控制电路中&#xff0c;会出现开关瞬间产生一个高的电压冲击&#xff0c;可能会导致外设的保护机制&#xff0c;甚至损坏。 很多用电装置都由适配器通过一段比较长的电源线供电,在用电装置一端有电源滤波电容。随着产品向小型化,便携化方向发展&#xff0c;陶瓷电容在电源…

服务器安装Pytorch深度学习环境

最近要开始准备毕设啦&#xff0c;决定写一篇关于如何在实验室服务器安装Pytorch深度学习环境的博客&#xff0c;因为我使用的基本是Pytorch所以如果是使用Tensorflow的小伙伴就可以滑走啦~ 服务器统一安装过程 创建文件夹&#xff1a; mkdir miniconda(文件夹名) 转入新建文…

民乐社区关工委举办敬老爱老关爱活动

2023年10月27日&#xff0c;由华润银行支持&#xff0c;民乐社区关工委组织开展的敬老爱老关爱活动走进高乐亦嘉-光明社会福利院和中国文化名人大营救纪念馆&#xff0c;民乐社区关工委主任孙旗开&#xff0c;副主任常满彦、郭娜英、刘昕带领27名中老年人参与了本次活动。 参观…

国家数据局正式揭牌,隐私计算助力数据要素流通共享

2023年10月25日&#xff0c;国家数据局在京正式揭牌。根据中共中央、国务院印发的《党和国家机构改革方案》&#xff0c;国家数据局负责协调推进数据基础制度建设&#xff0c;统筹数据资源整合共享和开发利用&#xff0c;统筹推进数字中国、数字经济、数字社会规划和建设等。 多…

运维监控系统PIGOSS BSM 基础版重磅发布,永久免费

中小企业运维现状 当前多数中小型企业IT运维现状基本分为两部分&#xff1a; 1. 依靠传统的人工运维方式&#xff0c;无有效的监控工具辅助&#xff0c;导致故障发现不及时&#xff0c; 无法实时掌握IT运行状态。 2. 使用开源工具&#xff1a;开源工具因没有专业的售后技术…

如何在 Mac 上切换用户?

如果您想与其他人共享您的 Mac&#xff0c;创建一个独立于您的个人帐户的新用户帐户可能会有所帮助。然而&#xff0c;不利的一面是&#xff0c;时不时地在不同的用户帐户之间切换可能是一件耗时的事情。幸运的是&#xff0c;我创建了本指南&#xff0c;解释如何在 Mac 上快速切…

Android NDK开发详解之将 NDK 与其他构建系统配合使用

Android NDK开发详解之将 NDK 与其他构建系统配合使用 概览Autoconf非 Autoconf make 项目 注意&#xff1a;本页介绍的内容适用于 NDK r19 及更高版本。如果您使用的是旧版 NDK&#xff0c;请考虑进行升级。如果无法升级&#xff0c;请参阅独立工具链指南。 NDK 提供对 ndk-bu…

在安装和配置DVWA渗透测试环境遇到的报错问题

安装环境 前面的安装我参考的这个博主&#xff1a;渗透测试漏洞平台DVWA环境安装搭建及初级SQL注入-CSDN博客 修改bug 1.首先十分感谢提供帮助的博主&#xff0c;搭建DVWA Web渗透测试靶场_dvwa 白屏-CSDN博客&#xff0c;解决了我大多数问题&#xff0c;报错如下&#xff1…

[毕设记录]@开题调研:CAAI资源

发现这里面有些东西还是不错的 https://www.caai.cn/index.php?s/home/article/index/id/53.html其中我主要需要用到大模型技术白皮书

Wi-Fi 6和5G 在应用场景上的区别

在工作领域&#xff0c;我们经常会面临两个选择&#xff0c;场景的解决方案是要用5G还是WiFi 6&#xff0c;其实判断并不困难&#xff0c;但我们仍然还是从理论概念上区分一下。 文章目录 什么是Wi-Fi 6什么是5GWi-Fi 6和5G 的区别区别一&#xff1a;覆盖范围区别二&#xff1…

【Azure】存储服务:Azure 的存储账户

文章目录 一、前提知识&#xff08;建议了解&#xff09;二、介绍 Azure 存储帐户三、使用 Microsoft Azure 门户创建存储帐户 一、前提知识&#xff08;建议了解&#xff09; 在每一个云厂商中&#xff0c;都有自身的云存储&#xff0c;也有根据不同功能进行区分的不同类型的…

IP代理被低估的作用,你知道吗?

IP说简单不简单&#xff0c;说复杂也不复杂&#xff0c;打个比方&#xff0c;IP就好比我们上网的一个门牌号&#xff0c;每家每户都会有一个门牌号&#xff0c;而且是唯一的地址。而代理IP&#xff08;代理服务器&#xff09;是一个位于中间的服务器&#xff0c;充当客户端和目…