mockito mock void方法_一文让你快速上手 Mockito 单元测试框架

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

生成 Mock 对象方式

要使用 Mockito,首先需要在我们的项目中引入 Mockito 测试框架依赖,基于 Maven 构建的项目引入如下依赖即可:

org.mockito    mockito-core    3.3.3test

如果是基于 Gradle 构建的项目,则引入如下依赖:

testCompile group: 'org.mockito', name: 'mockito-core', version: '3.3.3'

使用 Mockito 通常有两种常见的方式来创建 Mock 对象。

1、使用 Mockito.mock(clazz) 方式

通过 Mockito 类的静态方法 mock 来创建 Mock 对象,例如以下创建了一个 List 类型的 Mock 对象:

List mockList = Mockito.mock(ArrayList.class);

由于 mock 方法是一个静态方法,所以通常会写成静态导入方法的方式,即 List mockList = mock(ArrayList.class)。

2、使用 @Mock 注解方式

第二种方式就是使用 @Mock 注解方式来创建 Mock 对象,使用该方式创需要注意的是要在运行测试方法前使用 MockitoAnnotations.initMocks(this) 或者单元测试类上加上 @ExtendWith(MockitoExtension.class) 注解,如下所示代码创建了一个 List 类型的 Mock 对象(PS: @BeforeEach 是 Junit 5 的注解,功能类似于 Junit 4 的 @Before 注解。):

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 *///@ExtendWith(MockitoExtension.class)public class MockitoTest {  @Mock  private List mockList;  @BeforeEach  public void beforeEach() {    MockitoAnnotations.initMocks(this);  }}

验证性测试

Mockito 测试框架中提供了 Mockito.verify 静态方法让我们可以方便的进行验证性测试,比如方法调用验证、方法调用次数验证、方法调用顺序验证等,下面看看具体的代码。

验证方法单次调用

验证方法单次调用的话直接 verify 方法后加上待验证调用方法即可,以下代码的功能就是验证 mockList 对象的 size 方法被调用一次。

/** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {  @Mock  List mockList;  @Test  void verify_SimpleInvocationOnMock() {    mockList.size();    verify(mockList).size();  }}
验证方法调用指定次数

除了验证单次调用,我们有时候还需要验证一些方法被调用多次或者指定的次数,那么此时就可以使用 verify + times 方法来验证方法调用指定次数,同时还可以结合 atLeast + atMost 方法来提供调用次数范围,同时还有 never 等方法验证不被调用等。

/** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {  @Mock  List mockList;  @Test  void verify_NumberOfInteractionsWithMock() {    mockList.size();    mockList.size();    verify(mockList, times(2)).size();    verify(mockList, atLeast(1)).size();    verify(mockList, atMost(10)).size();  }}
验证方法调用顺序

同时还可以使用 inOrder 方法来验证方法的调用顺序,下面示例验证 mockList 对象的 size、add 和 clear 方法的调用顺序。

/** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {  @Mock  List mockList;  @Test  void verify_OrderedInvocationsOnMock() {    mockList.size();    mockList.add("add a parameter");    mockList.clear();    InOrder inOrder = inOrder(mockList);    inOrder.verify(mockList).size();    inOrder.verify(mockList).add("add a parameter");    inOrder.verify(mockList).clear();  }}

以上只是列举了一些简单的验证性测试,还有验证测试方法调用超时以及更多的验证测试可以通过相关官方文档探索学习。

验证方法异常

异常测试我们需要使用 Mockito 框架提供的一些调用行为定义,Mockito 提供了 when(...).thenXXX(...) 来让我们定义方法调用行为,以下代码定义了当调用 mockMap 的 get 方法无论传入任何参数都会抛出一个空指针 NullPointerException 异常,然后通过 Assertions.assertThrows 来验证调用结果。

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoExceptionTest {  @Mock  public Map mockMap;  @Test  public void whenConfigNonVoidReturnMethodToThrowEx_thenExIsThrown() {    when(mockMap.get(anyString())).thenThrow(NullPointerException.class);    assertThrows(NullPointerException.class, () -> mockMap.get("mghio"));  }}

同时 when(...).thenXXX(...) 不仅可以定义方法调用抛出异常,还可以定义调用方法后的返回结果,比如 when(mockMap.get("mghio")).thenReturn(21); 定义了当我们调用 mockMap 的 get 方法并传入参数 mghio 时的返回结果是 21。这里有一点需要注意,使用以上这种方式定义的 mock 对象测试实际并不会影响到对象的内部状态,如下图所示:

e73aa54cdfc361d4c607da8fc700e503.png

虽然我们已经在 mockList 对象上调用了 add 方法,但是实际上 mockList 集合中并没有加入 mghio,这时候如果需要对 mock 对象有影响,那么需要使用 spy 方式来生成 mock 对象。

public class MockitoTest {  private List mockList = spy(ArrayList.class);  @Test  public void add_spyMockList_thenAffect() {    mockList.add("mghio");    assertEquals(0, mockList.size());  }}

端点后可以发现当使用 spy 方法创建出来的 mock 对象调用 add 方法后,mghio 被成功的加入到 mockList 集合当中。

e26b1b2b5a6c84bcf1b51cf0fadbaf35.png

与 Spring 框架集成

Mockito 框架提供了 @MockBean 注解用来将 mock 对象注入到 Spring 容器中,该对象会替换容器中任何现有的相同类型的 bean,该注解在需要模拟特定bean(例如外部服务)的测试场景中很有用。如果使用的是 Spring Boot 2.0+ 并且当前容器中已有相同类型的 bean 的时候,需要设置 spring.main.allow-bean-definition-overriding 为 true(默认为 false)允许 bean 定义覆盖。下面假设要测试通过用户编码查询用户的信息,有一个数据库操作层的 UserRepository,也就是我们等下要 mock 的对象,定义如下:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@Repositorypublic interface UserRepository {  User findUserById(Long id);}

还有用户操作的相关服务 UserService 类,其定义如下所示:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@Servicepublic class UserService {  private UserRepository userRepository;  public UserService(UserRepository userRepository) {    this.userRepository = userRepository;  }  public User findUserById(Long id) {    return userRepository.findUserById(id);  }}

在测试类中使用 @MockBean 来标注 UserRepository 属性表示这个类型的 bean 使用的是 mock 对象,使用 @Autowired 标注表示 UserService 属性使用的是 Spring 容器中的对象,然后使用 @SpringBootTest 启用 Spring 环境即可。

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@SpringBootTestpublic class UserServiceUnitTest {  @Autowired  private UserService userService;  @MockBean  private UserRepository userRepository;  @Test  public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {    User expectedUser = new User(9527L, "mghio", "18288888880");    when(userRepository.findUserById(9527L)).thenReturn(expectedUser);    User actualUser = userService.findUserById(9527L);    assertEquals(expectedUser, actualUser);  }}

Mockito 框架的工作原理

通过以上介绍可以发现, Mockito 非常容易使用并且可以方便的验证一些方法的行为,相信你已经看出来了,使用的步骤是先创建一个需要 mock 的对象 Target ,该对象如下:

public class Target {  public String foo(String name) {    return String.format("Hello, %s", name);  }}

然后我们直接使用 Mockito.mock 方法和 when(...).thenReturn(...) 来生成 mock 对象并指定方法调用时的行为,代码如下:

@Testpublic void test_foo() {  String expectedResult = "Mocked mghio";  when(mockTarget.foo("mghio")).thenReturn(expectedResult);  String actualResult = mockTarget.foo("mghio");  assertEquals(expectedResult, actualResult);}

仔细观察以上 when(mockTarget.foo("mghio")).thenReturn(expectedResult) 这行代码,首次使用我也觉得很奇怪,when 方法的入参竟然是方法的返回值 mockTarget.foo("mghio"),觉得正确的代码应该是这样 when(mockTarget).foo("mghio"),但是这个写法实际上无法进行编译。既然 Target.foo 方法的返回值是 String 类型,那是不是可以使用如下方式呢?

Mockito.when("Hello, I am mghio").thenReturn("Mocked mghio");

结果是编译通过,但是在运行时报错:

bb49ae7a84772f61f57177d75bd9d666.png

从错误提示可以看出,when 方法需要一个方法调用的参数,实际上它只需要 more 对象方法调用在 when 方法之前就行,我们看看下面这个测试代码:

@Testpublic void test_mockitoWhenMethod() {  String expectedResult = "Mocked mghio";  mockTarget.foo("mghio");  when("Hello, I am mghio").thenReturn(expectedResult);  String actualResult = mockTarget.foo("mghio");  assertEquals(expectedResult, actualResult);}

以上代码可以正常测试通过,结果如下:

5155dfc0b33856db400909a946b0e713.png

为什么这样就可以正常测试通过?是因为当我们调用 mock 对象的 foo 方法时,Mockito 会拦截方法的调用然后将方法调用的详细信息保存到 mock 对象的上下文中,当调用到 Mockito.when 方法时,实际上是从该上下文中获取最后一个注册的方法调用,然后把 thenReturn 的参数作为其返回值保存,然后当我们的再次调用 mock 对象的该方法时,之前已经记录的方法行为将被再次回放,该方法触发拦截器重新调用并且返回我们在 thenReturn 方法指定的返回值。以下是 Mockito.when 方法的源码:

bb3c661b2f777bdc7764cfdf5150ebfb.png

该方法里面直接使用了 MockitoCore.when 方法,继续跟进,该方法源码如下:

43284b163a2017dc764c069d4499de8b.png

仔细观察可以发现,在源码中并没有用到参数 methodCall,而是从 MockingProgress 实例中获取 OngoingStubbing 对象,这个 OngoingStubbing 对象就是前文所提到的上下文对象。个人感觉是 Mockito 为了提供简洁易用的 API 然后才制造了 when 方法调用的这种“幻象”,简而言之,Mockito 框架通过方法拦截在上下文中存储和检索方法调用详细信息来工作的。

如何实现一个微型的 Mock 框架

知道了 Mockito 的运行原理之后,接下来看看要如何自己去实现一个类似功能的 mock 框架出来,看到方法拦截这里我相信你已经知道了,其实这就是 AOP 啊,但是通过阅读其源码发现 Mockito 其实并没有使用我们熟悉的 Spring AOP 或者 AspectJ 做的方法拦截,而是通过运行时增强库 Byte Buddy 和反射工具库 Objenesis 生成和初始化 mock 对象的。现在,通过以上分析和源码阅读可以定义出一个简单版本的 mock 框架了,将自定义的 mock 框架命名为 imock。这里有一点需要注意的是,Mockito 有一个好处是,它不需要进行初始化,可以直接通过其提供的静态方法来立即使用它。在这里我们也使用相同名称的静态方法,通过 Mockito 源码:

3316fb17a8746bbbf5faed1a8dbb93be.png

很容易看出 Mockito 类最终都是委托给 MockitoCore 去实现的功能,而其只提供了一些面向使用者易用的静态方法,在这里我们也定义一个这样的代理对象 IMockCore,这个类中需要一个创建 mock 对象的方法 mock 和一个给方法设定返回值的 thenReturn 方法,同时该类中持有一个方法调用详情 InvocationDetail 集合列表,这个类是用来记录方法调用详细信息的,然后 when 方法仅返回列表中的最后一个 InvocationDetail,这里列表可以直接使用 Java 中常用的 ArrayList 即可,这里的 ArrayList 集合列表就实现了 Mockito 中的 OngoingStubbing 的功能。根据方法的三要素方法名、方法参数和方法返回值很容易就可以写出 InvocationDetail 类的代码,为了对方法在不同类有同名的情况区分,还需要加上类全称字段和重写该类的 equals 和 hashCode 方法(判断是否在调用方法集合列表时需要根据该方法判断),代码如下所示:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public class InvocationDetail {  private String attachedClassName;  private String methodName;  private Object[] arguments;  private T result;  public InvocationDetail(String attachedClassName, String methodName, Object[] arguments) {    this.attachedClassName = attachedClassName;    this.methodName = methodName;    this.arguments = arguments;  }  public void thenReturn(T t) {    this.result = t;  }  public T getResult() {    return result;  }  @Override  public boolean equals(Object o) {    if (this == o) return true;    if (o == null || getClass() != o.getClass()) return false;    InvocationDetail> behaviour = (InvocationDetail>) o;    return Objects.equals(attachedClassName, behaviour.attachedClassName) &&        Objects.equals(methodName, behaviour.methodName) &&        Arrays.equals(arguments, behaviour.arguments);  }  @Override  public int hashCode() {    int result = Objects.hash(attachedClassName, methodName);    result = 31 * result + Arrays.hashCode(arguments);    return result;  }}

接下来就是如何去创建我们的 mock 对象了,在这里我们也使用 Byte Buddy 和 Objenesis 库来创建 mock 对象,IMockCreator 接口定义如下:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public interface IMockCreator {   T createMock(Class mockTargetClass, List behaviorList);}

实现类 ByteBuddyIMockCreator 使用 Byte Buddy 库在运行时动态生成 mock 类对象代码然后使用 Objenesis 去实例化该对象。代码如下:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public class ByteBuddyIMockCreator implements IMockCreator {  private final ObjenesisStd objenesisStd = new ObjenesisStd();  @Override  public  T createMock(Class mockTargetClass, List behaviorList) {    ByteBuddy byteBuddy = new ByteBuddy();    Class extends T> classWithInterceptor = byteBuddy.subclass(mockTargetClass)        .method(ElementMatchers.any())        .intercept(MethodDelegation.to(InterceptorDelegate.class))        .defineField("interceptor", IMockInterceptor.class, Modifier.PRIVATE)        .implement(IMockIntercepable.class)        .intercept(FieldAccessor.ofBeanProperty())        .make()        .load(getClass().getClassLoader(), Default.WRAPPER).getLoaded();    T mockTargetInstance = objenesisStd.newInstance(classWithInterceptor);    ((IMockIntercepable) mockTargetInstance).setInterceptor(new IMockInterceptor(behaviorList));    return mockTargetInstance;  }}

基于以上分析我们可以很容易写出创建 mock 对象的 IMockCore 类的代码如下:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public class IMockCore {  private final List invocationDetailList = new ArrayList<>(8);  private final IMockCreator mockCreator = new ByteBuddyIMockCreator();  public  T mock(Class mockTargetClass) {    T result = mockCreator.createMock(mockTargetClass, invocationDetailList);    return result;  }  @SuppressWarnings("unchecked")  public  InvocationDetail when(T methodCall) {    int currentSize = invocationDetailList.size();    return (InvocationDetail) invocationDetailList.get(currentSize - 1);  }}

提供给使用者的类 IMock 只是对 IMockCore 进行的简单调用而已,代码如下:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public class IMock {  private static final IMockCore IMOCK_CORE = new IMockCore();  public static  T mock(Class clazz) {    return IMOCK_CORE.mock(clazz);  }  public static  InvocationDetail when(T methodCall) {    return IMOCK_CORE.when(methodCall);  }}

通过以上步骤,我们就已经实现了一个微型的 mock 框架了,下面来个实际例子测试一下,首先创建一个 Target 对象:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public class Target {  public String foo(String name) {    return String.format("Hello, %s", name);  }}

然后编写其对应的测试类 IMockTest 类如下:

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public class IMockTest {  @Test  public void test_foo_method() {    String exceptedResult = "Mocked mghio";    Target mockTarget = IMock.mock(Target.class);    IMock.when(mockTarget.foo("mghio")).thenReturn(exceptedResult);    String actualResult = mockTarget.foo("mghio");    assertEquals(exceptedResult, actualResult);  }}

以上测试的可以正常运行,达到了和 Mockito 测试框架一样的效果,运行结果如下:

6cfeac132a55456af7eff7e6ad15e6e2.png

上面只是列出了一些关键类的源码,自定义 IMock 框架的所有代码已上传至 Github 仓库 imock,感兴趣的朋友可以去看看。

总结

本文只是介绍了 Mockito 的一些使用方法,这只是该框架提供的最基础功能,更多高级的用法可以去官网阅读相关的文档,然后介绍了框架中 when(...).thenReturn(...) 定义行为方法的实现方式并按照其源码思路实现了一个相同功能的简易版的 imock 。虽然进行单元测试有很多优点,但是也不可盲目的进行单元测试,在大部分情况下只要做好对项目中逻辑比较复杂、不容易理解的核心业务模块以及项目中公共依赖的模块的单元测试就可以了。

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

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

相关文章

vs winform常用函数_使用.net core3.0 正式版创建Winform程序

前阵子一直期待.net core3.0正式版本的出来&#xff0c;以为这个版本出来&#xff0c;Winform程序又迎来一次新生了&#xff0c;不过9.23日出来的马上下载更新VS&#xff0c;创建新的.net core Winform项目&#xff0c;发现并没有Winform窗体设计器。而微软目前则是通过插件的方…

VScode中编写运行C/html文件

VScode运行C程序的所需配置 VScode只是一个编辑器&#xff0c;并不自带C编译器&#xff0c;所以需要 下载mingw 下载安装版本或者压缩文件&#xff0c;解压缩后&#xff0c;配置系统的环境变量。 path中添加mingw/bin的路径 新建include变量&#xff0c;添加mingw/include的路径…

linq结果转换object_你知道Object.entries(),但你还知道有Object.fromEntries()吗?

我们得到 object.entries()&#xff0c;它转换一个object → array。但是&#xff0c;如果您想做相反的事情怎么办&#xff1f;不用再想了&#xff01; 使用 Object.fromEntries() 来array → object 。const keyValuePair [ [cow, ], [pig, ],];Object.fromEntries(keyValu…

C语言中数组越界访问造成死循环现象

大家请看这样一段代码&#xff08;工具&#xff1a;VC6.0&#xff09;&#xff1a; #include <stdio.h> int main(int argc, char *argv[]) { int i; int arr[10];/* 这里注意循环变量i与数组arr的定义顺序 */ for(i 0; i < 10; i)/* 这里越界了 */ …

java 同步锁_Java多线程:synchronized同步锁的使用和实现原理

作用和用法在多线程对共享资源进行并发访问方面&#xff0c;JDK提供了synchronized关键字来进行线程同步&#xff0c;实现多线程并发访问的线程安全。synchronized的作用主要体现在三个方面&#xff1a;(1)确保线程互斥地访问同步代码&#xff1b;(2)保证共享变量的线程可见性&…

java基础代码实例_基础篇:详解JAVA对象实例化过程

1 对象的实例化过程对象的实例化过程是分成两部分&#xff1a;类的加载初始化&#xff0c;对象的初始化要创建类的对象实例需要先加载并初始化该类&#xff0c;main方法所在的类需要先加载和初始化类初始化就是执行方法&#xff0c;对象实例化是执行方法一个子类要初始化需要先…

搭建webUI自动化及问题解决:Message: ‘chromedriver‘ executable needs to be in PATH.解决办法

搭建webUI自动化环境 1、conda install selenium即可。 若出现&#xff1a;Message: chromedriver executable needs to be in PATH.Please see https://sites.google.com/a/chromium.org/chromedriver/home。 报错原因&#xff1a;没有配置chrome浏览器的chromedriver 解决…

C语言-字符串处理函数strcpy

strcpy 原型&#xff1a;strcpy(char destination[], const char source[]); 功能&#xff1a;将字符串source拷贝到字符串destination中。此处将source中的字符串结束标志符‘\0’也一同复制。所以在输出时&#xff0c;切不可以用‘\0’&#xff0c;puts&#xff0c;printf输…

C语言-字符串处理函数strcat

strccat-字符串拼接函数 char*strcat(char* strDestination, const char* strSource); 参数说明&#xff1a; strDestination&#xff1a;目的字符串&#xff1b;strSource&#xff1a;源字符串。 strcat() 函数把 strSource 所指向的字符串追加到 strDestination 所指向的字…

js数组截取前5个_我不能没有的5个Vue.js库

1.Click Off to Close有的时候&#xff0c;我们需要在用户点击元素之外的时候触发一个事件。最常见的用例是当你想通过点击关闭一个下拉框或对话框时。这是一个必不可少的包&#xff0c;几乎在我构建的每个应用中都会用到。首选&#xff1a;vue-clickawayhttps://github.com/si…

this.$router.push如何刷新页面_小程序丨微信小程序如何实现页面下拉刷新

微信小程序蕴含着众多功能&#xff0c;本期将简单介绍实现页面下拉刷新的方法&#xff0c;通过阅读本文&#xff0c;读者们可以自行动手操作&#xff0c;在实践中认识微信小程序。首先&#xff0c;我们需在json配置中写出以下配置&#xff1a;"enablePullDownRefresh"…

C语言-字符串处理函数strcmp

strcmp-字符串比较函数 原型&#xff1a;int strcmp(const char firststring[], const char secondstring); 功能&#xff1a;比较两个字符串firststring和secondstring 如果等于 返回值为0 如果字符串1大于字符串2 函数值返回为1 如果字符串1小于字符串2 函数值返回为-1 …

导出excel数字前面的0消失_Excel操作中常见的3大坑你遇到过吗?遇到应该这么解决...

在excel中的我们获取数据的方式一是自己录入数据&#xff0c;二是通过网络或其他的途径导出的源数据&#xff0c;不管哪种的方式&#xff0c;对我们处理数据的来说都十分重要&#xff0c;这里我们需要注意这些点并成功跳过这些不按原理只按自己习惯的坑。今天要聊的坑有3个&…

matplot绘制图形入门

一、折线图 """ File: 折线图.py Author: chde_wang Date: 2021-05-23 22&#xff1a;26&#xff1a;04 Description: """ # 绘制折线图 import numpy as np import matplotlib.pyplot as plt x np.linspace(0, 2 * np.pi, 100) y1, y2 np.si…

kafka使用_Kafka介绍与使用

最近在研究kafka&#xff0c;觉得需要输出点东西才能更好的吸收&#xff0c;遂总结与大家分享&#xff0c;话不多说。一、先上思维导图&#xff1a;二、再上kafka整体架构图&#xff1a;2.1、Producer&#xff1a;消息生产者&#xff0c;就是向kafka broker发消息的客户端。2.2…

linux 关闭端口_手把手教你在Linux中快速检测端口的 3 个小技巧

一个执着于技术的公众号前言 无论是要解决网络连接问题还是配置防火墙&#xff0c;第一件事是要检查系统实际打开了哪些端口。本文介绍了几种快速查找 Linux 系统上哪些端口向外部开放的方法。什么是开放端口 监听端口是应用程序监听的网络端口。你要得到的监听端口名单通常可以…

2020-11-20

ln -s /bis_data/mysql/tmp/mysql.sock /tmp/ find / -name mysql.sock 2>/dev/null

未能找到程序集“platform.winmd_应用程序崩溃后 微软错误报告工具到底是如何联机检查解决方案的?...

在 Windows 应用意外崩溃后&#xff0c;系统似乎会努力地寻找解决方案。但是在绝大多数情况下&#xff0c;这一切都是徒劳的&#xff0c;并不会向用户给出任何结果。即便如此&#xff0c;很多人还是想要知道这个无效的过程期间到底都发生了什么。好消息是&#xff0c;近日微软 …

mysql索引创建和使用注意事项

总结&#xff1a; 1、在使用索引时&#xff0c;一般情况下不建议使用like操作。如果使用&#xff0c;则%放在后面。否则不会使用索引。like ‘%abd%’不会使用索引,而like ‘aaa%’可以使用索引.&#xff08;最左缀原则&#xff09; 2、单列索引的使用&#xff1a; 《1》 只…

不同存储结构的文件磁盘io操作次数_MySQL InnoDB存储引擎

第1章 MySQL体系结构和存储引擎1.1数据库和实例数据库&#xff1a;物理操作系统文件或其他形式文件类型的集合。实例&#xff1a;MySQL数据库由后台线程以及一个共享内存区组成。共享内存可以被运行 的后台线程所共享。数据库实例才是真正用于操作数据库文件的。启动MySQL数据库…