多态

本文深入讲解Java中的核心概念和技术,包括servlet的工作机制、spring框架的单例模式、线程安全问题、spring IOC容器管理机制、springboot自动配置原理、分布式事务处理、Redis缓存一致性策略、以及常用的数据结构与算法等内容。
摘要由CSDN通过智能技术生成

servlet单例模式,多线程下,线程安全和不安全的变量:

每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。

静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全

实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全;如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,故线程安全。

有状态就是有数据存储功能 ,无状态就是不会保存数据,controller、service和dao层本身并不是线程安全的,只是如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。

 

springIOC:控制反转,通过反射,在运行时动态的去创建、调用对象,解决了层与层之间的耦合度,应用程序依赖于IOC容器

spring中的单例与设计模式里面的单例略有不同,设计模式的单例是在整个应用中只有一个实例,而spring中的单例是在一个IoC容器中就只有一个实例。

springIoC容器管理的bean就是单例,因为不同的访问均得到相同的对象【在应用开启的状态下,不重新启动应用下,即在同一次的应用运行中】,那些处理我们提交数据的业务处理类是被多线程共享的,但是他们处理的数据并不是共享的

controller中的xxxService,对象都是单例,会被多个线程共享,可我们访问的是他们里面的方法,这些类里面通常不会含有成员变量,故线程安全。线程安全问题主要是全局变量和静态变量引起的。若每个线程中对全局变量、静态变量读操作,而无写操作,一般来说这个全局变量是线程安全的。spring 使用ThreadLocal 实现高并发下 共享资源的同步。

 

spring创建Bean和new对象的区别

2、Spring实现了对象池,一些对象创建和使用完毕之后不会被销毁,放进对象池(某种集合)以备下次使用,下次再需要这个对象,不new,直接从池里取,节省时间。

3、使用new关键字创建的对象属于强引用对象,所谓强引用,就是jvm垃圾回收机制永远不会回收这类对象,这时候需要手动移除引用。如果没有移除,这个对象将一直存在,久而久之,会引起内存泄露问题。

5、spring之所以不用new对象是因为类的构造方法一旦被修改,new的对象就出错了,如果是用了spring,就不用理会构造方法是否被修改,而拿来用就可以。

springmvc工作流程:

  1. springmvc将所有请求提交到dispatcherServlet控制器,由dispatcherServlet分发请求给对应的模块
  2. DispatcherServlet查询一个或多个HandlerMapping处理器,找到对应的处理请求的Controller
  3. DispatcherServlet将请求提交到目标controller进行业务逻辑处理后,返回一个modelandview对象
  4. DispatcherServlet请求viewResolver视图解析器,找到指定的视图对象,进行渲染,最后返回给客户端
  5. DispatcherServlet前端控制器,主要作用就是接受请求->分发请求->响应结果

 

static:

static保持函数调用后的结果,只有整个程序执行完后才会恢复原状,原理是它和非static的局部变量在内存中的存放区域不同(静态数据区);

非静态变量调用完函数之后被自动释放,再次调用的时候之前函数内用过的局部变量都恢复原状

 

FastJson:

Book 对象转json

String js = JSON.toJSONString(book);

json 转Book对象

Book book = JSON.parseObject("{"id":1,"name":"高数","info":"任课老师 毛耀"}", Book.class);

 

线程:

线程的五种状态

初始状态 new当创建了一个线程时,会进入此状态。
就绪状态 当初始状态调用了start()方法时,会进入此状态。
运行状态 当就绪状态的线程获得cpu时间片,即调度到它,进入运行状态。
堵塞状态 当调用sleep,wait方法或同步锁定,线程进入堵塞,代码不往下执行,堵塞事件结束后重新进入就绪状态,等待cpu调度。
终止状态 线程中断或者执行完所有代码,进入终止状态。

基本概念:

完全二叉树:若二叉树的深度为h,则除第h层外,其他层的节点全部打到最大值 -- 2^(i-1),且h层的节点全部集中在左子树。

满二叉树:   所有层的节点都是最大值 -- 2^(h-1)

红黑树: 为了解决二叉查找树多次插入新节点导致的不平衡问题;根节点是黑色,每个叶子节点都是黑色的空节点,每个红色节点的两个子节点都是黑色,插入时节点都初始为红色,所以有时需要左旋或右旋来进行变色

堆 是一颗完全二叉树。

垃圾回收

Java程序内存主要(这里强调主要二字)分两部分,堆和非堆。大家一般new的对象和数组都是在堆中的,而GC主要回收的内存也是这块堆内存

JVM的内存结构大概分为:

  1. 堆(heap):线程共享,堆的作用是存放对象实例和数组。回收器主要管理的对象。
  2. 方法区(MEATHOD AREA):线程共享,存储类信息、常量、静态变量、即时编译器编译后的代码。很多人愿意把方法区称为“永久代”。
  3. 方法栈(虚拟机栈 JVM Stack):线程私有、存储局部变量表、操作栈、动态链接、方法出口,对象指针。为虚拟机执行Java 方法(也就是字节码)服务
  4. 本地方法栈(NATIVE METHOD STACK):线程私有。为虚拟机使用到的Native 方法服务如Java使用c或者c++编写的接口服务时,代码在此区运行
  5. PC寄存器(PC Register):线程私有。指向下一条要执行的指令,可以看做是当前线程所执行的字节码的行号指示器。。

1、Stop-the-world
Stop-the-world
意味着 JVM由于要执行GC而停止了应用程序的执行,并且这种情形会在任何一种GC算法中发生。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态直到GC任务完成。事实上,GC优化很多时候就是指减少Stop-the-world发生的时间,从而使系统具有 高吞吐 、低停顿 的特点。

2、一般情况下,所有新生成的对象首先都是放在新生代的。新生代内存按照 8:1:1 的比例分为一个eden区和两个survivor(survivor0,survivor1)区,将eden区存活对象复制到survivor0区,然后清空eden区,当这个survivor0区也满了时,则将eden区和survivor0区存活对象复制到survivor1区清空eden和这个survivor0区,此时survivor0区是空的,然后交换survivor0区和survivor1区的角色,即保持survivor0区为空,当survivor1区也不足以存放eden区和survivor0区的存活对象时,就将存活对象直接存放到老年代

3、老年代存放的都是一些生命周期较长的对象,就像上面所叙述的那样,在新生代中经历了N(15)次垃圾回收后仍然存活的对象就会被放到老年代中。老年代的内存也比新生代大很多(大概比例是1:2),老年代对象存活时间比较长,因此FullGC发生的频率比较低。

4、永久代(元空间)主要用于存放静态文件,如Java类、方法等。永久代对垃圾回收没有显著影响。

调优:

修改 VM options 参数: -Xms1024m (调节初始内存)  -Xmx1024m (调节总内存)  -XX: +PrintGcDetails (输出gc描述信息)

jvm :

双亲委派机制:

       指的是                        字节码文件加载到jvm时,不考虑自定义类加载器情况下,会向上委托给父类加载器完成,一直向上委托,直到启动类加载器;如果能启动则使用当前加载器,否则在到达(app- ect - bootstrap)Bootstrap classLoader根加载器都无法加载时,下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出异常 ClassNotFoundException

      为什么这样设计?        如果有人想替换系统级别的类,这种机制下系统类已经被bootstrap classloader 加载过了,所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

沙箱机制:

 

接口和抽象类的区别是什么?

  • 接口必须使用 implements 来实现接口;抽象类的子类使用 extends 来继承
  • 接口不能有构造函数;抽象类可以有构造函数
  • 一个类只能继承一个抽象类,但可以实现多个接口
  • 抽象类中成员变量默认 default,可在子类中被重新定义,也可被重新赋值,抽象方法被 abstract 修饰,不能被 private、static、synchronized 和 native 等修饰;接口中成员变量默认为 public static final 修饰,必须赋初值,不能被修改,其所有的成员方法默认使用 public abstract 修饰的

你对我在这个项目中做的事情有没有想要了解的?

帮助团队分担一些压力,让自己的价值达到最大。

list和set的区别:

list是有序可重复,按对象进入的顺序存取,可插入多个null,可以通过下标随机访问

ArrayList : 基于动态数组,是连续的存储空间,(扩容 1.5 倍)

创建一个集合时,集合的初始容量为0,在第一次添加元素的时候,会对集合进行扩容,扩容之后,集合容量为10;之后,当向集合中添加元素达到集合的上限(也就是minCapacity大于elementData.length)时,会对集合再次扩容,扩容为原来的3/2。

LinkedList : 基于链表,可以是分散的存储空间,适合做插入及删除操作,当ArrayList向尾部插入元素时优于linkedList;

set是无序不重复,至多插入一个null,只能逐一遍历(迭代器遍历) 初始容量16 , 扩容 2 的幂次方

集合为什么有迭代器:

为了简化和更加适用集合的遍历

不用关心集合内部数据结构

不暴露内部数据,提高安全性

删除元素操作时, 不要用foreach 因为运行过程中还是会转换成迭代器导致操作的对象并非原集合对象,可以使用迭代器和普通for循环

Map接口和Collection接口是所有集合框架的父接口:

Collection接口的子接口包括:Set接口和List接口
Map接口的实现类主要有:HashMap(数组+链表,JDK1.8之后 数组+红黑树链;表长度为8变红黑树)、TreeMap(红黑树)、Hashtable(数组+链表 线程安全)、ConcurrentHashMap以及Properties等
Set接口的实现类主要有:HashSet(基于HashMap)、TreeSet(红黑树)、LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList以及Vector(动态数组 线程安全 效率低)等
 

 

IOC容器、控制反转、依赖注入:

1、配置指定需要扫描的包路径,加上注解,通过反射创建对象放进集合中

2、将对象的控制权(创建或是使用)交给容器处理,不再由对象主动创建

3、依赖注入是实现IOC控制反转的方法

索引:

索引用来快速的寻找那些含有特定值的记录

springboot 自动配置原理:

1、@SpringBootApplication (核心)是一个复合注解

      @SpringBootConfiguration  相当于spring @configuration ,用来标注一个类是配置类,

      @ComponentScan 相当于spring中,定义扫描包路径 , 将需要装配的组件注册到容器里面

      @EnableAutoConfiguration  自动装配

          ① 将类的全路径全部加载到spring的ioc容器中,最终变成spring中一个个bean(配置文件里的<bean>)

         ② 注册扫描路径到全局变量中,提供查询

分布式:在同一个系统同中,把不同的业务拆分成单独的服务,交给独立的团队独立的技术选型,独立的部署,独立的运维,这是我的理解

springCloud: 微服务全家桶

① 服务注册中心 (eureka、zookeeper等):提供服务注册与发现,监控系统中各个微服务是否正常运行。一方面,提供注册的地址,微服务(服务提供者与消费者)在eureka中注册,使得eureka服务端能在界面中直观的看到所有可用的微服务节点(通讯地址IP+端口、别名);另一方面,管理服务与服务间的依赖调用关系,维护服务实例。 对比其他注册中心优点,高可用,分区容错性,(ap,c 一致性)与springcloud集成。主要作用,把各种服务注册进去,供其他的服务调用,服务随时会增加,所以需要eureka

② 服务调用与负载均衡(Ribbon、openfeign) : Nginx 是服务端负载均衡,所有请求进来交由Nginx负责请求转发,将请求通过某种策略转发至可提供服务的服务方;ribbon 是客户端负载均衡,在调用微服务接口时,从注册中心上获取注册列表缓存到本地,从而实现远程调用(轮询、随机、hash、按权等)。微服务间的调用。主要作用,既然有服务,同一个服务集群配置可能注册多个,从注册中心拿到一堆的服务后,比如一个用户列表,可能拿到两个或三个,这时候需要按照一定的负载均衡策略完成调用

  Feign(OpenFeign) 它集成了ribbon,使得微服务间调用更容易,通过注解@FeignClient 让实现更加简单,更好的面向接口编程(定义接口!接口!,在接口上打上注解@FeignClient (提供服务那方的name),定义服务提供controller层方包含的方法)

③ 服务降级(Hystrix等) : 处理分布式系统的延迟和容错,增加分布式系统的弹性。当某个服务单元发生异常后,向调用方返回可预期的、可处理的响应,而不是长时间的等待或直接抛出客户端无法处理的异常。主要作用,可能调用服务的时候,这个服务异常挂掉了,为了保证系统的健壮性,Hystrix主要就是做降级熔断限流。默认阀值。远程调用处理分布式事务时最好不加熔断,只有报错了事务才会回滚,远程查询可以加熔断

        服务降级(fallback): 程序发生异常不可用时,给用户返回友好提示。默认超时时长3000毫秒

        服务熔断(break): 当达到最大访问量时,直接拒绝访问,调用服务降级返回友好提示,待容量回复后恢复使用

        服务限流(flowlimit): 当流量猛地增加时,限制流量通过的数量

Hystrix 有一对一的降级方法,由@HystrixCommand(fallbackMethod="")注解加属性完成;

Hystrix 有全局的降级方法,在类上由@DefaultProperties(fallbackMethod="")定义该类指定的全局的降级方法,在需要服务降级的方法上加上注解 @HystrixCommand 不带属性即可

Hystrix 对feign访问的接口进行实现,覆写方法提供服务降级;

④ 服务网关(gateway、zuul等) : 进行端口适配,不暴露真实的服务端口。主要作用,众多的服务,一个服务一个地址,不便于前端调用,对于要访问的微服务统一地址,统一鉴权。

⑤ 消息中间件 : 实现服务的差异化管理

@Autowired 与 @Resource 区别

 @Autowired 是spring的注解 ,在无法辨别注入对象时,通过@Qualifier或@Primary注解一起来修饰。@Resource 是Java的注解,当接口仅有单一实现类时,两者无区别,当无法辨别对象时可通过name 或type 属性指定,或结合@Qualifier注解使用

包装类和基本类的区别:

① 包装类可以为null。更好的应用于pojo中,因为数据库的查询结果可能为null,避免了拆箱时的空指针异常。

② 包装类可用于泛型。泛型在编译时期会进行类型擦除,只保留Object和它的子类。

③ 但是基本类型比包装类高效。基本类型将数值存于栈中,包装类型存储的是堆中的引用,占用更多的内存。

没有十全十美的解决方案,能做到的只能是针对业务提供尽量好的方案

一些springboot springcloud比较会用的

单张表最多对 16 个字段建立索引 ,索引是牺牲插入删除的性能, 需要对不经常修改的字段,对唯一性较高的 ,经常作为过滤和查询条件的字段建立索引 ,or连接, isnull等会导致索引失效

jpa:一对多

https : 安全认证 , ssl安全证书 ,又受信任的数字证书办法机构,验证服务器身份后颁发,  具有公钥和私钥,公钥用于加密 ,私钥用于解密

 

@Autowired 与 @Resource 区别

 @Autowired 是spring的注解 ,在无法辨别注入对象时,通过@Qualifier或@Primary注解一起来修饰。@Resource 是Java的注解,当接口仅有单一实现类时,两者无区别,当无法辨别对象时可通过name 或type 属性指定,或结合@Qualifier注解使用

 

servlet生命周期

类加载 -> 实例化(为对象分配内存空间) -> 初始化(为对象的属性赋值) -> 执行 -> 销毁

服务器启动或第一次请求servlet时,会执行初始化方法init()初始化一个servlet对象,处理客户端请求执行service()方法,最终服务器关闭执行destroy()方法

 

线程生命周期

新建 -> 就绪 -> 运行 -> 阻塞 -> 终止

启动线程是调用start()方法,而不是直接调用run()方法,start()方法启动一个新线程,它将进入“就绪/可运行状态( Runnable)”,等待操作系统为线程分配CPU时间后,将转变为“运行状态(Running)”, 现在系统将会自动调用run()方法开始运行,而不是程序本身

 

SQL执行顺序:

from , where , 聚合函数在 group by 之后 having 之前 , 然后执行 select 选出要查询的字段或全字段 , 最后执行 order by

 

高并发下的接口幂等 f(f(x)) = f(x) 性:(用户 积分 活动)

幂等性指的是,一个操作无论执行多少次与一次执行结果或影响相同,不用担心重复执行对系统造成影响(如 发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱; 审核消息 ,网络重发时 ,审核状态的记录应该只改变一次)

一种是通过代码逻辑判断实现,判断某一个状态是否达成从而返回相应的结果或执行相应的操作

一种是token加Redis

 

分布式事务:

产生场景:

① 多个微服务连接不同的数据库(跨jvm进程)

②多个微服务连接同一数据库(跨jvm进程)

③单体项目连接多个数据库(数据库实例不同)

CAP理论:(满足p时,ca不能同时)

一致性(任何时刻主从数据库都能查到最新数据,同步过程中加锁,从数据库可返回超时或报错信息,但一定返回最新数据),可用性(任何时刻保证有响应返回,可返回旧数据),分区容错性(一个结点挂了,不影响其他结点)

seata开启全局事务 , 主事务中开启 @GlobalTransactional 和 @Transactional 

尽可能使用本地事务单数据源,如果一个系统分布式事务特别多,频繁的使用,要考虑系统是否拆分合理,尽量减少网络交互带来的性能损耗,避免事务弱一致性带来的问题

 

Redis 做缓存,保持数据一致的问题

当数据更新时采用双删策略,比如当执行写操作时,先删除缓存,再写数据库,延时一段时间后再写一遍缓存。

 

linux:

cd 目录  :    切换到指定目录

ll  ls        :    前者展示每层目录每个文件夹,后者只展示当前层文件夹

ps -ef|grep 进程名 : 查询进程信息    windows: netstat -an|find ""

ping ip地址 : ping不通考虑防火墙问题

防火墙  :     ①firewall-cmd --state                            查看防火墙状态

                  ②systemctl stop firewalld.service          停止(重启linux重新启动)

                  ③systemctl disable firewalld.service      禁用

装jdk      :    一般第三方软件装在 /usr/opt 下 ,jdk建议新建local/Java 目录然后解压文件到此   

                   mdikr /usr/local/java ;

                   tar -zxvf jdk-8u291-linux-x64.tar.gz -C /usr/local/java ;

                   vim /etc/profile ;  修改环境变量,对所有用户起作用

                   source /etc/profile ; 让配置生效

装tomcat : 解压tomcat压缩包

                ./startup.sh

                在浏览器中输入URL:“http://云服务器公网IP地址:8080”

                如果以上URL不能访问,请检查云主机安全组是否放开8080端口。

 

shiro: 

组件: subject             主体

         securityManager(shiro的核心,管理着所有subject,且负责进行认证、授权、会话管理、缓存等)

         authenticator   认证器

         authorizer         授权器

         realm  securityManage要验证身份,需要从realm中获取安全数据,即它是一个安全数据源

         sessionManager   会话管理器

认证  授权

① shiro 核心过滤器

    loginUrl                 认证失败跳转的页面或接口                     

    successUrl           登录成功跳转

    unauthorizedUrl   无权限时跳转

 

mybatis-plus:

service CRUD :get 、remove、list、page 、saveOrUpdateBatch(TableId存在时进行更新)

mapper CRUD:insert、delete、update、list

区别: service虽然加入了数据库的操作,但是还是以业务为主,而更复杂的SQL还是要靠mapper对应的xml实现,service是对BaseMapper的扩充,不仅包含了基本方法,还有很多批量处理功能

 

maven项目结构:

src : 源文件

target : 编译后的.class文件,和配置文件 (工作空间下的 target/classes)

对于eclipse来说  src/main/java 和 src/mian/resources  都是属于classpath,也就是项目的根路径。idea将src/main/java定义为.java的文件目录而src/main/resources定义为资源文件目录(存放配置文件的地方)

 

一个类只能继承一个父类,存在局限;一个类可以实现多个接口。在实现Runnable接口的时候调用Thread的Thread(Runnable run)或者Thread(Runnablerun,String name)构造方法创建进程时,使用同一个Runnable实例,建立的多线程的实例变量也是共享的;但是通过继承Thread类是不能用一个实例建立多个线程,故而实现Runnable接口适合于资源共享;

 

抽象类和接口的区别,做个总结吧:

(1)接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。

(2)abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface,实现多重继承。接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。

(3)在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是 static final的,不过在 interface中一般不定义数据成员),所有的成员方法默认都是 public abstract 类型的。

(4)abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"has-a"关系。

(5)实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。抽象类中可以有非抽象方法。接口中则不能有实现方法。

(6)接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以在子类中重新赋值。

 

分布式事务:

如 两个系统操作一个数据库,①如a系统写操作成功了,调用b系统失败了,或者调用b系统成功,但b执行失败了②如果a执行数据库操作后远程调用b执行数据库操作成功了,a继续往下走才报错,这时候a回滚,b不会回滚

分布式事务没有100%解决的方案,

①可基于cap理论采取合适的解决方案,一致性、可用性、分区容错性

②BASE理论,从cap演化而来的,做到最终一致性(mq TCC),或实时一致性即强一致性(LCN seata)

LCN:全局事务管理器,当多个事务全部执行成功才进行真正的提交,并不创建事务,而是协调本地事务从而达到一致性

优点对代码的嵌入型较低,只需开启注解 @LcnTransactional,缺点增加了数据库连接占用时长,且支持节点有限

启动TXManager服务,在需要全局事务的服务中指定txmanager事务组地址,开启注解

TCC:try预处理,confirm确认,cancle撤销

在主事务一方,try{全局事务id,自己sql业务,远程调用},confirm{无需操作},cancle{自己sql业务,进行回滚}

被远程调用的一方,try{无需操作},confirm{sql业务},cancle{无需操作}

主事务try成功,被远程调用的一方confirm失败,这种情况会自动重试;

 

rabbitMQ:

生产者:

创建队列:

(直连,work):new Queue(queue 队列名,durable 是否持久化,exclusive 是否独享,autoDelete 是否自动删除该队列,arquments 其(他参数);

(广播型fanout):交换机                    new FanoutExchange(name);

                        队列 i                      new Queue(name 交换机名称);

                       绑定队列到交换机    BindingBuilder.bind(queuei().to(fanoutExchange()));

(路由直连routing-Direct):

                        交换机                     new DirectExchange(name);

                        队列  i                       new Queue(name 交换机名称);

                       绑定队列到交换机 i   BindingBuilder.bind(queuei().to(directExchange())).with(路由key i);

(路由主题routing-Topic):

                      交换机                     new TopicExchange(name);

                      队列  i                       new Queue(name 交换机名称);

                      绑定队列到交换机 i   BindingBuilder.bind(queuei().to(topicExchange())).with(xxx.* or xxx.#);

                                                        /* xxx.*匹配xxx后面只含1一个单词的路由key, xxx.# 匹配0 个或 多个*/

发送消息:

(直连,work):rabbitTemplate.convertAndSend(routingkey  队列名,object 内容);

(广播型fanout):rabbitTemplate.convertAndSend(exchange 交互机,routingkey  空,object 内容);

(路由直连routing-Direct):rabbitTemplate.convertAndSend(exchange 交互机,routingkey  路由key i,object 内容);

(路由主题routing-Topic):rabbitTemplate.convertAndSend(exchange 交互机,routingkey  路由key.one.two...,object 内容);

消费者:

方法上(直连,work):@RabbitListener(queuesToDeclare={@Queue("队列名")})

方法上(广播型fanout):@RabbitListener(bindings={@QueueBinging(value=@Queue(队列名)/*绑定队列*/,

                                                                                                           exchange(name=交换机名称,type=ExchangeTypes.FANOUT)/*绑定交换机,设置名称和类型*/)})

(路由直连routing-Direct):@RabbitListener(bindings={@QueueBinging(value=@Queue(队列名)/*绑定队列*/,

                                                                                                                key={路由key i,路由key i},

                                                                                                                exchange(name=交换机名称,type=ExchangeTypes.DIRECT))})

(路由主题routing-Topic):@RabbitListener(bindings={@QueueBinging(value=@Queue(队列名)/*绑定队列*/,

                                                                                                                key={xxx.* OR xxx.#},

                                                                                                                exchange(name=交换机名称,type=ExchangeTypes.TOPIC))})

手动确认消息:  channel.basicNark(deliveryTag 消息投递id,multiple false是否批量签收,requeue true是否重新放回队列);

序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。核心作用是对象状态的保存与重建。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值