杨校老师课堂之Spring框架面试题【开发工程师面试前必看】

news2024/11/24 7:05:28

1.spring 中都用到了哪些设计模式?
2.spring 中有哪些核心模块?
3.说一下你理解的 IOC 是什么?
4.spring 中的 IOC 容器有哪些?有什么区别?
5.那 BeanFactory 和 FactoryBean 又有什么区别?
6.@Repository、@Service、@Compent、@Controller它们有什么区别?
7.那么 DI 又是什么?
8.说说 AOP 是什么?
9.动态代理和静态代理有什么区别?
10.JDK 动态代理和 CGLIB 代理有什么区别?
11.Spring AOP 和 AspectJ AOP 有什么区别?
12.spring 中 Bean 的生命周期是怎样的?
13.spring 是怎么解决循环依赖的?
14.为什么要使用三级缓存,二级缓存不能解决吗?
15.@Autowired 和 @Resource 有什么区别?
16.spring 事务隔离级别有哪些?
17.spring 事务的传播机制有哪些?
18.springBoot 自动装配原理?
19.简述Spring Boot的主要执行流程?
20.结合实际开发情况,简述@ConfigurationProperties和@Value两种注解的使用选择?
21.@PathVariable、@RequestParam和@RequestBody三种注解区别是什么?
22.@Configuration、@Component、@Bean 三种注解分别用在哪里,有什么区别?


1.spring 中都用到了哪些设计模式?

 

  • 「1.工厂设计模式」: 比如通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象

  • 「2.代理设计模式」:  AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理

  • 「3.单例设计模式」: Spring 中的 Bean 默认都是单例的

  • 「4.模板方法模式」: Spring 中 jdbcTemplate 等以 Template 结尾的对数据库操作的类,都会使用到模板方法设计模式,一些通用的功能

  • 「5.包装器设计模式」: 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源

  • 「6.观察者模式」: Spring 事件驱动模型观察者模式的

  • 「7.适配器模式」:Spring AOP 的增强或通知(Advice)使用到了适配器模式

2.spring 中有哪些核心模块?

 

  • 1.「Spring Core」:Spring核心,它是框架最基础的部分,提供IOC和依赖注入DI特性

  • 2.「Spring Context」:Spring上下文容器,它是 BeanFactory 功能加强的一个子接口

  • 3.「Spring Web」:它提供Web应用开发的支持

  • 4.「Spring MVC」:它针对Web应用中MVC思想的实现

  • 5.「Spring DAO」:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性

  • 6.「Spring ORM」:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等

  • 7.「Spring AOP」:即面向切面编程,它提供了与AOP联盟兼容的编程实现

3.说一下你理解的 IOC 是什么?

 

首先 IOC 是一个「容器」,是用来装载对象的,它的核心思想就是「控制反转」

那么究竟「什么是控制反转」?

控制反转就是说,「把对象的控制权交给了 spring,由 spring 容器进行管理」,我们不进行任何操作

那么为「什么需要控制反转」?

我们想象一下,没有控制反转的时候,我们需要「自己去创建对象,配置对象」,还要「人工去处理对象与对象之间的各种复杂的依赖关系」,当一个工程的量起来之后,这种关系的维护是非常令人头痛的,所以就有了控制反转这个概念,将对象的创建、配置等一系列操作交给 spring 去管理,我们在使用的时候只要去取就好了

4.spring 中的 IOC 容器有哪些?有什么区别?

spring 主要提供了「两种 IOC 容器」,一种是 「BeanFactory」,还有一种是 「ApplicationContext」

它们的区别就在于,BeanFactory 「只提供了最基本的实例化对象和拿对象的功能」,而 ApplicationContext 是继承了 BeanFactory 所派生出来的产物,是其子类,它的作用更加的强大,比如支持注解注入、国际化等功能

5.那 BeanFactory 和 FactoryBean 又有什么区别?

这两个是「不同的产物」

「BeanFactory 是 IOC 容器」,是用来承载对象的

「FactoryBean 是一个接口」,为 Bean 提供了更加灵活的方式,通过代理一个Bean对象,对方法前后做一些操作。

6.@Repository、@Service、@Compent、@Controller它们有什么区别?

这四个注解的「本质都是一样的,都是将被该注解标识的对象放入 spring 容器当中,只是为了在使用上区分不同的应用分层」

  • @Repository:dao层

  • @Service:service层

  • @Controller:controller层

  • @Compent:其他不属于以上三层的统一使用该注解

7.那么 DI 又是什么?

DI 就是依赖注入,其实和 IOC 大致相同,只不过是「同一个概念使用了不同的角度去阐述」

DI 所描述的「重点是在于依赖」,我们说了 「IOC 的核心功能就是在于在程序运行时动态的向某个对象提供其他的依赖对象」,而这个功能就是依靠 DI 去完成的,比如我们需要注入一个对象 A,而这个对象 A 依赖一个对象 B,那么我们就需要把这个对象 B 注入到对象 A 中,这就是依赖注入

spring 中有三种注入方式

  • 接口注入

  • 构造器注入

  • set注入

8.说说 AOP 是什么?

AOP 意为:「面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术」

AOP 是 「OOP(面向对象编程) 的延续」,是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

「AOP 实现主要分为两类:」

  • 「静态 AOP 实现」, AOP 框架「在编译阶段」对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ

  • 「动态 AOP 实现」, AOP 框架「在运行阶段」动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP

spring 中 AOP 的实现是「通过动态代理实现的」,如果是实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。

 

「有 5 种通知类型:」

  • 「@Before」:在目标方法调用前去通知

  • 「@AfterReturning」:在目标方法返回或异常后调用

  • 「@AfterThrowing」:在目标方法返回后调用

  • 「@After」:在目标方法异常后调用

  • 「@Around」:将目标方法封装起来,自己确定调用时机

9.动态代理和静态代理有什么区别?

「静态代理」

  • 由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了

  • 静态代理通常只代理一个类

  • 静态代理事先知道要代理的是什么

「动态代理」

  • 在程序运行时,运用反射机制动态创建而成

  • 动态代理是代理一个接口下的多个实现类

  • 动态代理不知道要代理什么东西,只有在运行时才知道

10.JDK 动态代理和 CGLIB 代理有什么区别?

JDK 动态代理时业务类「必须要实现某个接口」,它是「基于反射的机制实现的」,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。

CGLIB 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类「创建子类,然后重写父类的方法」,实现对代码的增强。

11.Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 是运行时增强,是通过「动态代理实现」

AspectJ AOP 是编译时增强,需要特殊的编译器才可以完成,是通过「修改代码来实现」的,支持「三种织入方式」

  • 「编译时织入」:就是在编译字节码的时候织入相关代理类

  • 「编译后织入」:编译完初始类后发现需要 AOP 增强,然后织入相关代码

  • 「类加载时织入」:指在加载器加载类的时候织入

主要区别Spring AOPAspecjtJ AOP
增强方式运行时增强编译时增强
实现方式动态代理修改代码
编译器javac特殊的编译器 ajc
效率较低(运行时反射损耗性能)较高
织入方式运行时编译时、编译后、类加载时

12.spring 中 Bean 的生命周期是怎样的?

SpringBean 生命周期大致分为4个阶段:

  • 1.「实例化」,实例化该 Bean 对象

  • 2.「填充属性」,给该 Bean 赋值

  • 3.「初始化」

    • 如果实现了 Aware 接口,会通过其接口获取容器资源

    • 如果实现了 BeanPostProcessor 接口,则会回调该接口的前置和后置处理增强

    • 如果配置了 init-method 方法,]会执行该方法

  • 4.「销毁」

    • 如果实现了 DisposableBean 接口,则会回调该接口的 destroy 方法

    • 如果配置了 destroy-method 方法,则会执行 destroy-method 配置的方法

13.spring 是怎么解决循环依赖的?

 

循环依赖就是说两个对象相互依赖,形成了一个环形的调用链路

spring 使用三级缓存去解决循环依赖的,其「核心逻辑就是把实例化和初始化的步骤分开,然后放入缓存中」,供另一个对象调用

  • 「第一级缓存」:用来保存实例化、初始化都完成的对象

  • 「第二级缓存」:用来保存实例化完成,但是未初始化完成的对象

  • 「第三级缓存」:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象


当 A、B 两个类发生循环引用时 大致流程

  • 1.A 完成实例化后,去「创建一个对象工厂,并放入三级缓存」当中

    • 如果 A 被 AOP 代理,那么通过这个工厂获取到的就是 A 代理后的对象

    • 如果 A 没有被 AOP 代理,那么这个工厂获取到的就是 A 实例化的对象

  • 2.A 进行属性注入时,去「创建 B」

  • 3.B 进行属性注入,需要 A ,则「从三级缓存中去取 A 工厂代理对象」并注入,然后删除三级缓存中的 A 工厂,将 A 对象放入二级缓存

  • 4.B 完成后续属性注入,直到初始化结束,将 B 放入一级缓存

  • 5.「A 从一级缓存中取到 B 并且注入 B」, 直到完成后续操作,将 A 从二级缓存删除并且放入一级缓存,循环依赖结束


spring 解决循环依赖有两个前提条件:

  • 1.「不全是构造器方式」的循环依赖(否则无法分离初始化和实例化的操作)

  • 2.「必须是单例」(否则无法保证是同一对象)

14.为什么要使用三级缓存,二级缓存不能解决吗?

可以,三级缓存的功能是只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会「创建一个工厂并将其放入到三级缓存」中,但是不会去通过这个工厂去真正创建对象。

如果使用二级缓存解决循环依赖,意味着所有 Bean 在实例化后就要完成 AOP 代理,这样「违背了 Spring 设计的原则」,Spring 在设计之初就是在 Bean 生命周期的最后一步来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。

15.@Autowired 和 @Resource 有什么区别?

  • 「@Resource 是 Java 自己的注解」,@Resource 有两个属性是比较重要的,分是 name 和 type;Spring 将 @Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。

  • 「@Autowired 是spring 的注解」,是 spring2.5 版本引入的,Autowired 只根据 type 进行注入,「不会去匹配 name」。如果涉及到 type 无法辨别注入对象时,那需要依赖 @Qualifier 或 @Primary 注解一起来修饰。

16.spring 事务隔离级别有哪些?

 

  • DEFAULT:采用 DB 默认的事务隔离级别

  • READ_UNCOMMITTED:读未提交

  • READ_COMMITTED:读已提交

  • REPEATABLE_READ:可重复读

  • SERIALIZABLE:串行化

17.spring 事务的传播机制有哪些?

 

  • 1.「propagation_required」

    • 当前方法「必须在一个具有事务的上下文中运行」,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)

  • 2.「propagation_supports」

    • 当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行

  • 3.「propagation_mandatory」

    • 表示当前方法「必须在一个事务中运行」,如果没有事务,将抛出异常

  • 4.「propagation_nested」

    • 如果当前方法正有一个事务在运行中,则该方法应该「运行在一个嵌套事务」中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation_required的一样

  • 5.「propagation_never」

    • 当方法务不应该在一个事务中运行,如果「存在一个事务,则抛出异常」

  • 6.「propagation_requires_new」

    • 当前方法「必须运行在它自己的事务中」。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

  • 7.「propagation_not_supported」

    • 方法不应该在一个事务中运行。「如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行」

18.springBoot 自动装配原理?

 

  • 1.容器在启动的时候会调用 EnableAutoConfigurationImportSelector.class 的 selectImports方法「获取一个全面的常用 BeanConfiguration 列表」

  • 2.之后会读取 spring-boot-autoconfigure.jar 下面的spring.factories,获取到所有的 Spring 相关的 Bean 的全限定名 ClassName」

  • 3.之后继续「调用 filter 来一一筛选」,过滤掉一些我们不需要不符合条件的 Bean

  • 4.最后把符合条件的 BeanConfiguration 注入默认的 EnableConfigurationPropertie 类里面的属性值,并且「注入到 IOC 环境当中」

19.简述Spring Boot的主要执行流程

  • Spring Boot启动过程中执行了SpringApplication实例的初始化创建和调用run()启动项目两个主要阶段。
  • 在SpringApplication实例初始化阶段,判定当前应用类型、进行应用初始化器和监听器设置、设置项目启动类;
  • 在启动阶段,获取并运行前面初始化的监听器、准备运行环境、应用上下文进行装配和启动、运行自定义执行器、持续运行上下文。

20.结合实际开发情况,简述@ConfigurationProperties和@Value两种注解的使用选择

如果只是针对某一个业务需求,要引入配置文件中的个别属性值,推荐使用@Value注解;
如果针对某个JavaBean类,需要批量注入属性值,则推荐使用@ConfigurationProperties注解

21.@PathVariable、@RequestParam和@RequestBody三种注解区别是什么?

  • 1. PathVariable
    • 将请求URL中的模板变量映射】到功能处理方法的参数
    • 多用于Get请求方式、Delete请求方式
    • 不适用Post请求
  • 2. RequestParam
    • GET和POST请求传的参数会自动转换赋值到@RequestParam 所注解的变量上
  • 3.RequestBody
    • 可以接收json格式】的数据,并将其转换成对应的数据类型
    • 处理HttpEntity传递过来的数据,一般用来处理非Content-Type: application/x-www-form-urlencoded编码格式的数据。
    • GET请求中,因为没有HttpEntity,@RequestBody并不适用Get请求,所以不能用于get请求】

22.@Configuration、@Component、@Bean 三种注解分别用在哪里,有什么区别?

  • 1. Configuration
    • 声明该类为一个配置类,可以在此类中声明一个或多个 @Bean 方法
    • @Configuration注解的类表示可以在类中申明一个或者多个@Bean方法,然后就可以有spring容器来处理:在运行的时候为这些@Bean方法生成的bean提供bean的定义以及服务请求
  • 2. Component
    • 通用的注解,可标注任意类为 Spring 的组件
    • Sping扫描到了@Component类之后就会将其纳入spring容器进行管理,方便在其他地方使用,如:将@Component类的实例直接注入到另外一个类里
  • 3. Bean
    • @Bean用于注解一个方法表示该方法将会产生一个bean,该bean会被spring容器管理。
    • @Configuration 注解修饰的类,并且该注解中的 proxyBeanMethods 属性的值为 true(默认的),则会使用cglib动态代理,为这个 bean 创建一个代理类,该代理类会拦截所有被 @Bean 修饰的方法,在拦截的方法逻辑中,会从容器中返回所需要的单例对象
    • @Component 注解修饰的类,则不会为这个 bean 创建一个代理类。 那么我们就会直接执行用户的方法,所以每次都会返回一个新的对象

作者: 杨校

出处: https://mryang.blog.csdn.net

分享是快乐的,也见证了个人成长历程,文章大多都是工作经验总结以及平时学习积累,基于自身认知不足之处在所难免,也请大家指正,共同进步。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 如有问题, 可邮件(397583050@qq.com)咨询

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

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

相关文章

C#学习笔记一 委托、事件

C# 委托、事件 1、Action委托、Func委托 namespace DelegateExample {class Program{static void main(string[] args){Calculator calculatornew Calculator();//Action委托Action Calnew Action(calculator.Report);//直接调用函数Calculator.Report();//通过委托调用函数Ca…

艾美捷RPMI-1640培养基含L-谷氨酰胺的功能和研究

Roswell Park Memorial Institute (RPMI) 1640 培养基起初是为了悬浮培养人白血病单层细胞而开发的。RPMI 1640 培养基被发现适用于多种哺乳动物细胞,包括 HeLa 细胞、Jurkat 细胞、MCF-7 细胞、PC12 细胞、PBMC 细胞、星形胶质细胞和癌细胞。针对广泛的细胞培养应用…

阿里影业的稳健业绩来源:科技+内容塑造韧性,应对市场变化

随着《阿凡达:水之道》(简称:《阿凡达2》)预售佳绩的显现,电影业的复苏已然箭在弦上。 12月7日,《阿凡达2》正式开启预售,灯塔专业版数据显示,其预售开启4小时后,总票房…

【工作随笔】验证经验、维度

背景:目前负责模块的验证工作基本进展完毕,包括所有功能验证、场景覆盖、用例编写调试和仿真、功能覆盖率收集、sva检测时序等,在当前的进度上和开发、验证同时对我的工作进行了评审。 问题:在评审中间讨论到一个当前tc实现的问题…

五、卷积神经网络CNN7(图像卷积与反卷积)

图像卷积 首先给出一个输入输出结果那他是怎样计算的呢? 卷积的时候需要对卷积核进行 180 的旋转,同时卷积核中心与需计算的图像像素对齐,输出结构为中心对齐像素的一个新的像素值,计算例子如下:这样计算出左上角(即第…

基于Dijkstra和A算法的机器人路径规划附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

JAVA SCRIPT设计模式--行为型--设计模式之Observer观察者模式(19)

JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代…

Python图像识别实战(一):实现按比例随机抽取图像移动到另一文件夹

前面我介绍了可视化的一些方法以及机器学习在预测方面的应用,分为分类问题(预测值是离散型)和回归问题(预测值是连续型)(具体见之前的文章)。 从本期开始,我将做一个关于图像识别的…

Nacos集群搭建

1、下载nacos http://t.csdn.cn/ejfu9 2、配置Nacos 进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf: 然后添加内容: 添加的内容是你要启动的多台nacos的IP和端口 127.0.0.1:8845 127.0.0.1:8846…

如何批量注册推特账号

Twitter推特账号怎么注册?相信国内好多朋友都被推特注册卡住,不知怎么注册twitter账号,由于国内限制的问题,推特账号注册比以前更麻烦了,本文将详细讲解Twitter怎么注册,Twitter (推特)是一个广受欢迎的社交…

【C#基础学习】第十五章、结构

目录 结构 1.结构的构造函数 1.1 实例构造函数 1.2 静态构造函数 1.3 总结 2.结构体作为返回值和参数 结构 结构的定义:结构是一种可以由程序员自定义的密封的值类型。 结构与类的区别:结构与类类似,它们都有自己的数据成员和函数成员。…

Nginx篇之实现反向代理和端口转发

一、前言 在正式生产环境中,web服务器、反向代理服务器的选择大都会选择nginx,确实,在常见的高并发场景下,nginx能够支持以万为单位的并发请求量,并且服务性能稳定,应用极为广泛。 二、反向代理含义 反向代…

【LeetCode_字符串_中心扩散 】5. 最长回文子串

目录考察点第一次:2022年12月8日10:29:05解题思路代码展示:中心扩散题目描述5. 最长回文子串 给你一个字符串 s,找到 s 中最长的回文子串。 示例 1: 输入:s "babad" 输出:"bab" 解…

高通平台开发系列讲解(Camera篇)新增GC8034摄像头步骤

文章目录 一、新增配置文件二、配置摄像头三、设置效果文件四、修改设备树五、修改用户空间驱动程序沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要介绍高通平台新增摄像头步骤。 一、新增配置文件 在vendor/qcom/proprietary/common/config/device-vendor.…

一文读懂数据加密

文章目录本文前言一、可逆加密1.1 对称加密(传统加密算法)1.2 非对称加密(现代加密算法)二、不可逆加密三、 混合加密、消息摘要和数字签名四、文章最后本文前言 在计算机信息安全领域,之前软件设计师的网络安全部分了…

解决Elasticsearch Connection reset by peer异常

一、问题现象 随着ES的密集使用,线上环境,不同应用最近几天陆续有报java.io.IOException: Connection reset by peer异常,感觉不太正常。直接影响就是用户查询或者变更ES数据失败。 java.io.IOException: Connection reset by peerat org.e…

大数据:Storm集成HDFS和HBase

一、Storm集成HDFS 1.1 项目结构 1.2 项目主要依赖 项目主要依赖如下&#xff0c;有两个地方需要注意&#xff1a; 这里由于我服务器上安装的是 CDH 版本的 Hadoop&#xff0c;在导入依赖时引入的也是 CDH 版本的依赖&#xff0c;需要使用 <repository> 标签指定 CDH …

自适应且不可删除的水印蒙层

目录 canvas自适应文字长度&#xff0c;旋转角度生成水印背景图 生成蒙层 禁止蒙层的删除和修改 canvas自适应文字长度&#xff0c;旋转角度生成水印背景图 设置canvas字体大小后&#xff0c;通过ctx.measureText(text).width获取两行文字的宽度text1&#xff0c;text2&…

python-(6-5-1)爬虫---xpath解析实战

文章目录一 环境准备二 需求三 分析1 拿到页面源代码2 提取和解析数据四 步骤流程1 拿到页面源代码2 提取和解析数据五 完整代码xpath是在XML文档中搜索内容的一门语言 html是xml的一个子集 一 环境准备 安装lxml模块 二 需求 爬取某网站的数据 三 分析 1 拿到页面源代码 …

计算机领域热知识【2】消息队列与celery

Celery是实现消息队列的一个工具&#xff0c;本篇博客将介绍消息队列的基础知识&#xff0c;以及celery实现消息队列的总体方法。想要实现用Celery实现消息队列实例的朋友&#xff0c;可以从本篇博客中找到我写的另一篇介绍使用Celery和RabbitMQ实现消息队列的博客。 目录消息队…