番禺建设网站公司/爱站
为了让大家更容易接受我的一些观点,上一篇很多笔墨都用在了思路引导上,所以导致文章可能比较臃肿。
这一篇来总结一下,会稍微精简一些,但整体趣味性不如第二篇。
(上一篇说过了,目前介绍的2种注入方式的说法其实不够准确,后面源码分析时再详细介绍)
主要内容:
- 如何把对象交给Spring管理
- 依赖注入
- 自动装配
- <bean>、@Component还是@Bean
- 聊一聊@ComponentScan
如何把对象交给Spring管理
首先明确2个概念:Spring Bean和Java Object。
在Spring官方文档中,Bean指的是交给Spring管理、且在Spring中经历完整生命周期(创建、赋值、各种后置处理)的Java对象。
Object指的是我们自己new的、且没有加入Spring容器的Java对象。
笼统地讲,要把对象交给Spring管理大概有3种方式(其他方式以后补充):
- XML配置:<bean>
- 注解开发:@Component
- 配置类:@Configuration+@Bean
这里要稍微强调以下几点:
首先,XML配置方式必须搭配ClassPathXmlApplicationContext,并把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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 在xml中描述类与类的配置信息 --><bean id="person" class="com.bravo.xml.Person"><property name="car" ref="car"></property></bean><bean id="car" class="com.bravo.xml.Car"></bean>
</beans>
public class Test {public static void main(String[] args) {// 由于是XML配置方式,对应的Spring容器是ClassPathXmlApplicationContext,传入配置文件告知Spring去哪读取配置信息ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context.xml");// 从容器中获取PersonPerson person = (Person) applicationContext.getBean("person");System.out.println(person);}
}
其次,所谓的注解开发不是说只要打上@Component注解,Spring就会把这个注解类解析成BeanDefinition然后实例化放入容器,必须配合注解扫描。
开启扫描的方式有2种:
- <context:component-scan>(XML+注解)
- @ComponentScan(@Configuration配置类+注解)
大家可以把注解开发等同于@Component,只不过这个注解的解析必须开启扫描。所以,在我眼中@Component其实只是半吊子,必须依附于XML或者@Configuration配置类。
最后,狭隘的JavaConfig风格可以等同于@Configuration+@Bean。此时,配置类上面的@ComponentScan并不是必须的。这取决于你是否要另外扫描@Component注解。一旦加了@ComponentScan,其实就是JavaConfig+注解了。
@Configuration //表示这个Java类充当XML配置文件
public class AppConfig {@Beanpublic Person person(){Person person = new Person();person.setCar(new Benz());return person;}
}
public class Test {public static void main(String[] args) {// AnnotationConfigApplicationContext专门搭配@Configuration配置类ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取PersonPerson person = (Person) applicationContext.getBean("person");System.out.println(person);}
}
3种编程风格其实指的是把Bean交给Spring管理的3种方式:
- <bean>
- @Component
- @Configuration+@Bean
至此,我们已经知道如何把Bean交给IOC。接下来,我们聊一聊DI。
依赖注入
虽然注入方式不止两种,但我们还是暂时按照两种方式复习
- setter方法注入
- 构造方法注入
setter方法注入
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 在xml中描述类与类的配置信息 --><bean id="person" class="com.bravo.xml.Person"><!-- property标签表示,让Spring通过setter方法注入--><property name="car" ref="car"></property></bean><bean id="car" class="com.bravo.xml.Car"></bean></beans>
Person
public class Person {// Person依赖Carprivate Car car;// setter方法public void setCar(Car car) {this.car = car;System.out.println("通过setter方法注入...");}@Overridepublic String toString() {return "Person{" +"car=" + car +'}';}
}
Car
public class Car {
}
<bean>中配置<property>,则类中必须提供setter方法。因为<property>等于告诉Spring调用setter方法注入。
构造方法注入
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 在xml中描述类与类的配置信息 --><bean id="person" class="com.bravo.xml.Person"><!-- constructor-arg标签表示,让Spring通过构造方法注入--><constructor-arg ref="car"></constructor-arg></bean><bean id="car" class="com.bravo.xml.Car"></bean></beans>
Person
public class Person {// Person依赖Carprivate Car car;// 有参构造public Person(Car car){this.car = car;System.out.println("通过构造方法注入...");}@Overridepublic String toString() {return "Person{" +"car=" + car +'}';}
}
<bean>中配置<constructor-arg>,则类中必须提供对应参数列表的构造方法。因为<constructor-arg>等于告诉Spring调用对应的构造方法注入。
什么叫对应参数列表的构造方法?比如上面配置的
<constructor-arg ref="car"></constructor-arg>
则类中必须提供
public Person(Car benz){this.car = benz;
}
参数多一个、少一个都不行,Spring只会找这个构造方法,找不到就报错!
自动装配
我们发现上面XML的依赖注入有点累赘。比如
Person
public class Person {// Person依赖Carprivate Car car;// setter方法public void setCar(Car car) {this.car = car;System.out.println("通过setter方法注入...");}@Overridepublic String toString() {return "Person{" +"car=" + car +'}';}
}
其实类结构已经很好地描述了依赖关系:Person定义了Car字段,所以Person依赖Car。
此时在<bean>中再写一遍
<!-- 在xml中描述类与类的配置信息 -->
<bean id="person" class="com.bravo.xml.Person"><!-- property标签表示,让Spring通过setter方法注入--><property name="car" ref="car"></property>
</bean>
<bean id="car" class="com.bravo.xml.Car"></bean>
就属于重复操作了。而且后期如果类结构发生改变,比如加了一个shoes字段,我们不仅要维护类结构本身,还要额外维护<bean>标签中的<property>。
针对这种情况,Spring提出了自动装配。我们分三种编程风格讨论。
1.XML的自动装配
在XML中,自动装配可以设置全局和局部,即:对所有bean起效,还是对单个bean起效
- 全局:default-autowire="byName"
- 局部:autowire="byName"
全局(XML文件中每一个bean都遵守byName模式的自动装配)
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName"><!-- 在xml中只定义bean,无需配置依赖关系 --><bean id="person" class="com.bravo.xml.Person"></bean><bean id="car" class="com.bravo.xml.Car"></bean></beans>
局部(只对当前<bean>有效)
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 在xml中只定义bean,无需配置依赖关系 --><bean id="person" class="com.bravo.xml.Person" autowire="byName"></bean><bean id="car" class="com.bravo.xml.Car"></bean></beans
XML的自动装配,与之前的依赖注入相比,只有XML文件不同:
- 去除之前依赖注入时配置的<property>或<constructor-arg>
- 加上全局或局部的自动装配属性
类结构要求还是和之前一样,该提供setter方法或者构造方法的,不能少。
自动装配共4种模式:
- byName
- byType
- constructor
- no
如果你选择byName或者byType,则需要提供setter方法。
如果你选择constructor,则需要提供给构造方法。
总之,对于XML而言,自动装配的作用是:只需写<bean>,不需要写<bean>里面的其他标签。
2.注解开发的自动装配
@Configuration //表示这个Java类充当XML配置文件
@ComponentScan("com.bravo.annotation")//开启注解扫描
public class AppConfig {
}
Person
@Component
public class Person {@Qualifier("benz")@Autowiredprivate Car car;@Overridepublic String toString() {return "Person{" +"car=" + car +'}';}
}
@Configuration配置类要搭配AnnotationConfigApplicationContext
public class Test {public static void main(String[] args) {// AnnotationConfigApplicationContext专门搭配@Configuration配置类ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取PersonPerson person = (Person) applicationContext.getBean("person");System.out.println(person);}
}
@Autowired默认是byType,如果找到多个相同的,会去匹配与当前字段同名的bean。没找到或者找到多个都会报错。
上面演示的是@Autowired作用于成员变量上,其实我们也可以把@Autowired加在构造方法上,它也会自动注入bean。
读完上面这句话两秒后,你意识到自己被骗了,于是反驳我:放你的屁,我从来没在构造方法上加@Autowired,而且即使不加,形参也能注入进来。
是的,确实不加也注入进来了。
在回答这个问题之前,我们先达成共识:不管我们new对象,还是Spring帮我们创建bean,都离不开构造方法。这一点没有异议吧?
当你的类中只有一个默认无参构造方法时,Spring实例化时没得选,只能用无参构造创建bean。但是,如果类中有两个构造方法,比如:
@Component
public class Person {private Car car;private Shoes shoes;public Person(Car benz) {this.car = benz;}public Person(Car benz, Shoes shoes){this.car = benz;this.shoes = shoes;}@Overridepublic String toString() {return "Person{" +"car=" + car +", shoes=" + shoes +'}';}}
此时,Spring会报错,因为它无法替你决定到底用哪个构造器创建bean。你要加上@Autowired,明确告诉Spring用哪个构造方法创建bean。
当然,放在setter方法上也可以注入进来。具体细节,会在分析自动装配底层源码时介绍。
3.JavaConfig的自动装配
其实没必要把JavaConfig再单独分出一类,因为它底层其实也是@Component。所以和在@Component里使用@Autowired是一样的。
AppConfig
@Configuration //表示这个Java类充当XML配置文件
@ComponentScan("com.bravo.javaconfig")//用来扫描Benz组件注入
public class AppConfig {//把benz注入进来,用来设置给person@Autowiredprivate Car benz;@Beanpublic Person person(){Person person = new Person();person.setCar(benz);return person;}
}
Person
public class Person {private Car car;public void setCar(Car car) {this.car = car;}@Overridepublic String toString() {return "Person{" +"car=" + car +'}';}
}
<bean>、@Component还是@Bean
学习了把对象交给Spring管理的3种方式后,我们产生了疑惑:
<bean>、@Component和@Bean该如何取舍呢?
虽然@Bean和@Component都是注解,看起来是一家人,但其实@Bean和<bean>更接近。它俩的共同点是:
类文件和bean定义分开
什么意思呢?
打个比方:
@Component直接写在源码上,而bean标签和@Bean都是另写一个文件描述bean定义
直接写源码上面,有什么不好吗?
有好有坏。
好处是:相对其他两种方式,@Component非常简洁。
坏处是,如果你想要交给Spring管理的对象是第三方提供的,那么你无法改动它的源码,即无法在上面加@Component。更甚者,人家连源码都没有,只给了你jar包,怎么搞?
网上花里胡哨的对比一大堆,但个人觉得就这个是最重要的。以后遇到不好加@Component的,能想到@Bean或者<bean>就行了。
聊一聊@ComponentScan
我们都知道,@ComponentScan和XML中的<context:component-scan>标签功能相同,都是开启注解扫描,而且可以指定扫描路径。
AppConfig
@Configuration //表示这个Java类充当XML配置文件
@ComponentScan("com.bravo.javaconfig")
public class AppConfig {}
Person
@Component
public class Person {@Qualifier("benz")@Autowiredprivate Car car;@Overridepublic String toString() {return "Person{" +"car=" + car +'}';}
}
Benz
@Component
public class Benz implements Car {
}
Test
public class Test {public static void main(String[] args) {// AnnotationConfigApplicationContext专门搭配@Configuration配置类ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取PersonPerson person = (Person) applicationContext.getBean("person");System.out.println(person);}
}
目录结构
测试结果
接下来,我们做几个实验,来探讨一下@ComponentScan。
实验一:不写@ComponentScan
这个别试了,直接报错,因为压根没开启扫描,找不到Person。
报错:找不到Person,说明没扫描到
实验二:不指定路径,同包
AppConfig
@Configuration //表示这个Java类充当XML配置文件
@ComponentScan //删除basePackages,不指定路径
public class AppConfig {}
测试结果
还是能扫描到
实验三:指定路径,不同包
AppConfig
@Configuration //表示这个Java类充当XML配置文件
@ComponentScan("com.bravo.javaconfig")//扫描javaconfig包下的组件
public class AppConfig {}
把AppConfig类移到annotation包下,和Person等组件不同包:
测试结果
还是扫描到了,身在曹营心在汉,虽然配置类在annotation包下,但是路径指定了javaconfig
实验四:不指定路径,不同包
不试了,扫描不到。
总结
其实,背后的原理是下面这句代码:
// AnnotationConfigApplicationContext专门搭配@Configuration配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext吃了AppConfig这个配置类后,会尝试去拿类上面的@ComponentScan注解:
- 有注解(开启扫描)
- 有路径:扫描指定路径
- 没路径:默认扫描当前配置类所在包及其子包下组件
- 没有注解(不开启扫描)
我们回头分析一下四个实验:
- 有注解
- 有路径:扫描指定路径(实验三:指定路径,不同包,但是指定的路径是对的)
- 没路径:默认扫描当前包及其子包下组件(实验二、四,默认扫描配置类所在包)
- 没有注解(不扫描)
- 报错(实验一:不写@ComponentScan)
@ComponentScan在SpringBoot中的应用
用过SpringBoot的朋友都知道,我们必须写一个启动类
@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);}
}
而SpringBoot有一个不成文的规定:
所有的组件必须在启动类所在包及其子包下,出了这个范围,组件就无效了。
为什么会有这个规定呢?
我们来看一下启动类上唯一的注解@SpringBootApplication,发现它其实是一个组合注解:
@ComponentScan没有指定basePackages属性,也就是没有指定扫描路径。那么,按照上面的分析,默认扫描当前包及其子包下组件。
这就是上面不成文规定的背后原因。
相关文章:

Spring基础(3):复习
为了让大家更容易接受我的一些观点,上一篇很多笔墨都用在了思路引导上,所以导致文章可能比较臃肿。 这一篇来总结一下,会稍微精简一些,但整体趣味性不如第二篇。 (上一篇说过了,目前介绍的2种注入方式的说法其实不够…...

Java-Hbase介绍
1.1. 概念 base 是分布式、面向列的开源数据库(其实准确的说是面向列族)。HDFS 为 Hbase 提供可靠的 底层数据存储服务,MapReduce 为 Hbase 提供高性能的计算能力,Zookeeper 为 Hbase 提供 稳定服务和 Failover 机制,…...

【PHP】【Too few arguments to function Firebase\JWT\JWT::encode()。。。。。。。】
1.安装jwt composer require firebase/php-jwtuse Firebase\JWT\JWT;public function hello($name ThinkPHP5){$secret_key "YOUR_SECRET_KEY";$issuer_claim "THE_ISSUER";$audience_claim "THE_AUDIENCE";$issuedat_claim time(); // is…...

Centos系统上安装包(软件)时常用的命令wget、rpm、yum分别是什么意思和作用?
本文以在Centos上安装mysql-5.7.26的前三步为例,说明命令wget、rpm、yum的意思和作用。 安装mysql-5.7.26的步骤如下: 下载MySQL 5.7.26的RPM存储库文件: wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm安装R…...

虹科干货 | 旧电脑别急着扔,手把手教你搭建NAS系统存储照片
一、前期准备 我们的目的是让设备物尽其用,将旧电脑做成NAS存储系统后可以使用新电脑进行访问(Windows / Linux / IOS系统都可以访问)。在开始之前先来看看安装成功效果图吧! 1.设备准备 (1)一台旧电脑&am…...

python基础(Python高级特性(切片、列表生成式)、字符串的正则表达式、函数、模块、Python常用内置函数、错误处理)培训讲义
文章目录 1. Python高级特性(切片、列表生成式)a) 切片的概念、列表/元组/字符串的切片切片的概念列表切片基本索引简单切片超出有效索引范围缺省 扩展切片step为正数step为负数 b) 列表生成式以及使用列表生成式需要注意的地方概念举例说明1. 生成一个列…...

计讯物联高精度GNSS接收机:担当小型水库大坝安全监测解决方案的“护航者”
应用背景 水库大坝作为水利工程建筑物,承担着灌溉、发电、供水、生态等重任。一旦水库大坝发生安全事故,后果将不堪设想。因此,水库大坝的安全监测对保障水利工程顺利运行具有重要意义。 计讯物联作为水利行业专家型企业,多年来…...

信号发送与处理-上
问题 按下 Ctrl C 后,命令行中的前台进程会被终止。为什么??? 什么是信号? 信号是一种 "软件中断",用来处理异步事件 内核发送信号到某个进程,通知进程事件的发送事件可能来自硬件…...

[蓝桥杯 2022 省 A] 推导部分和
[蓝桥杯 2022 省 A] 推导部分和 题目描述 对于一个长度为 N N N 的整数数列 A 1 , A 2 , ⋯ A N A_{1}, A_{2}, \cdots A_{N} A1,A2,⋯AN,小蓝想知道下标 l l l 到 r r r 的部分和 ∑ i l r A i A l A l 1 ⋯ A r \sum\limits_{il}^{r}A_iA_{l}A…...

pytorch复现_UNet
什么是UNet U-Net由收缩路径和扩张路径组成。收缩路径是一系列卷积层和汇集层,其中要素地图的分辨率逐渐降低。扩展路径是一系列上采样层和卷积层,其中特征地图的分辨率逐渐增加。 在扩展路径中的每一步,来自收缩路径的对应特征地图与当前特征…...

定岗定编设计:企业职能部门定岗定编设计项目成功案例
一、客户背景及现状分析 某大型车辆公司隶属于某央企集团,建于20世纪60年代,是中国高速、重载、专用铁路车辆生产经营的优势企业,轨道车辆制动机研发制造的主导企业,是隶属于国内最大的轨道交通设备制造上市企业的骨干二级公司。公…...

鸿蒙原生应用开发-DevEco Studio本地模拟器的使用
使用Local Emulator运行应用/服务 DevEco Studio提供的Local Emulator可以运行和调试Phone、TV和Wearable设备的HarmonyOS应用/服务。在Local Emulator上运行应用/服务兼容签名与不签名两种类型的HAP。 Local Emulator相比于Remote Emulator的区别:Local Emulator是…...

QT blockingFilter blockingMap blockingMapped
blockingFilter 主要作用是筛选出符合条件的项值结果集,并与之替换原有序列列表 blockingMap 可以直接修改容器的每一项 blockingMapped 不直接修改容器的每一项,而是将处理后的结果返回一个新的容器 blockingMappedReduced ResultType QtConcurrent::blockingMappedRed…...

【ARFoundation学习笔记】平面检测
写在前面的话 本系列笔记旨在记录作者在学习Unity中的AR开发过程中需要记录的问题和知识点。难免出现纰漏,更多详细内容请阅读原文。 文章目录 平面检测属性可视化平面平面检测的开关控制显示与隐藏已检测平面 平面检测属性 AR中检测平面的原理:AR Fou…...

Python---ljust()--左对齐、rjust()--右对齐、center()--居中对齐
作用:返回原字符串左对齐、右对齐以及居中对齐,不足的使用 指定字符 进行填充。 ljust 左对齐 rjust 右对齐 center 居中对齐 类似于Excel、Word文档中的对齐。 基本语法: 字符串序列.ljust(长度, 填充字符) 案例: …...

spdk用户态块层详解
先通过回顾内核态的通用块层来详细介绍SPDK通用块层,包括通用块层的架构、核心数据结构、数据流方面的考量等。最后描述基于通用块层之上的两个特性:一是逻辑卷的支持,基于通用块设备的Blobstore和各种逻辑卷的特性,精简配置&…...

双通道 H 桥电机驱动芯片AT8833,软硬件兼容替代DRV8833,应用玩具、打印机等应用
上期小编给大家分享了单通道 H 桥电机驱动芯片,现在来讲一讲双通道的驱动芯片。 双通道 H 桥电机驱动芯片能通过控制电机的正反转、速度和停止等功能,实现对电机的精确控制。下面介绍双通道H桥电机驱动芯片的工作原理和特点。 一、工作原理 双通道 H 桥电…...

WPF布局与控件分类
Refer:WPF从假入门到真的入门 - 知乎 (zhihu.com) Refer:WPF从假入门到真的入门 - 知乎 (zhihu.com) https://www.zhihu.com/column/c_1397867519101755392 https://blog.csdn.net/qq_44034384/article/details/106154954 https://www.cnblogs.com/mq0…...

复杂逻辑的开发利器—Mendix快速实现AQL质量抽检
Mendix低代码开发平台适用于复杂的业务逻辑场景,这句话大家早有耳闻,本期小编就为您打开智慧之光,仅从AQL小侧面,来管窥一二——Mendix如何形成第五代编程语言,来完成数据逻辑与建模、业务算法逻辑与建模的。ÿ…...

RFID系统
目录 在物联网应用中有三项关键技术 读写器 电子标签 工作原理 阅读器的组成及作用: 电子标签的组成及作用: RFID系统的组成 接口方式 在物联网应用中有三项关键技术 在物联网应用中有三项关键技术 1、传感器技术:这也是计算机应用中…...

Markov Chain Fingerprinting to Classify Encrypted Traffic 论文笔记
0.Abstract 在本文中,提出了用于SSL/TLS会话中传输的应用程序流量的随机指纹。这个指纹基于一阶齐次马尔可夫链,模型识别应用程序的准确率,并提供了检测异常对话的可能性。 1.Introduction 通过SSL/TLS会话时的头部信息创建统计指纹ÿ…...

vue 跨标签页的数据共享(即跨标签页通信)
跨标签页通信的常见方案 LocalStorage 或 SessionStorage BroadCast Channel Service Worker Shared Worker Window.postMessage() Cookies IndexedDB 什么是跨标签页通信? 指在同一个浏览器窗口中的多个标签页之间进行数据交流和信息传递的过程。通常情况…...

什么是拉宾-斯科特定理?
拉宾-斯科特定理(Rabin-Scott theorem )是数学上最深刻的数学结果之一。拉宾-斯科特定理是人们最喜欢的计算机科学概念之一。 当正确理解拉宾-斯科特定理时,它会以一种相当基本的方式改变你对现实的看法。然而,它典型的教科书式的呈现方式掩盖了这种深…...

Java并发编程第11讲——AQS设计思想及核心源码分析
Java并发包(JUC)中提供了很多并发工具,比如前面介绍过的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore、FutureTask等锁或者同步部件,它们的实现都用到了一个共同的基类——AbstractQueuedSynchronizer&…...

什么是数据库?数据库有哪些基本分类和主要特点?
数据库是以某种有组织的方式存储的数据集合。本文从数据库的基本概念出发,详细解读了数据库的主要类别和基本特点,并就大模型时代备受瞩目的数据库类型——向量数据库进行了深度剖析,供大家在了解数据库领域的基本概念时起到一点参考作用。 …...

flutter显示出底部控件的引导页
需求:同一个页面的两个不同的入口,同一个控件的位置有变化,显示引导页时对应这个控件的引导内容的位置也需要改变;同时半透明底部显示出真实的页面内容。 这样的需要如果切图然后再往页面上贴位置无法精确的对准。 思路࿱…...

常用设计模式——模板方法模式
什么是模板方法模式 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 主要解决:一些方法通用,却要在每一个子类都重写这些方法…...

idea使用git删除本地提交(未推送)
1、找到reset head 2、打开弹窗,在HEAD后面输入^ 结果为HEAD^ 注释: Reset Type 有三种: Mixed(默认方式),保留本地源码,回退 commit 和 index 信息,最常用的方式Soft 回退到某个版本…...

centos 7部署Mysql8.0主从
Mysql官网中关于部署主从的网址 环境准备: 搭建虚拟机和安装Mysql之前的文章中已经涉及,在此不再赘述。 主从IPMysql账号密码主192.168.213.4root/Root1234!从192.168.213.5root/Root1234! 1、主数据库设置 配置my.cnf 一般存放于/etc/。 主从配…...

asp.net docker-compose添加es search
打开docker-compose.yml添加 es-search:image: docker.elastic.co/elasticsearch/elasticsearch:7.17.14 打开docker-compose.override.yml添加 es-search:volumes:- data01:/usr/share/elasticsearch/dataports:- 9200:9200 docker集群中添加es search成功...