Swagger

使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。

注解 说明
@Api 用在类上,例如Controller,表示对类的说明
@ApiModel 用在类上,例如entity、DTO、VO
@ApiModelProperty 用在属性上,描述属性信息
@ApiOperation 用在方法上,例如Controller的方法,说明方法的用途、作用

AOP

AOP (Aspect-Oriented Programming, 面向切面编程) 是一种编程范式,用于将横切关注点(cross-cutting concerns)从业务逻辑中分离出来。横切关注点是指那些跨越多个类和模块的公共行为,例如日志记录、事务管理、权限控制等。

  1. 切面 (Aspect)
    • 切面是横切关注点的模块化实现,它封装了影响多个类的行为。例如,日志记录切面可以用于在方法调用前后记录日志。
  2. 连接点 (Joinpoint)
    • 连接点是在程序执行过程中某个特定的点,如方法调用、异常抛出等。切面会在这些连接点上被激活。
  3. 通知 (Advice)
    • 通知是切面在特定连接点上采取的动作。通知可以是前置通知(Before)、后置通知(After)、环绕通知(Around)等。
  4. 切入点 (Pointcut)
    • 切入点是一组连接点的集合,它定义了通知何时被触发。通常通过表达式来定义哪些连接点属于某个切入点。
  5. 目标对象 (Target Object)
    • 目标对象是被一个或多个切面所通知的对象。通常是指业务逻辑类。
  6. 织入 (Weaving)
    • 织入是指将切面代码插入到目标对象中,创建一个新的代理对象的过程。织入可以在编译时、加载时或运行时进行。

AOP 的优点:

  • 解耦:AOP 允许开发者将横切关注点从业务逻辑中分离出来,提高了模块间的解耦。
  • 代码重用:横切关注点可以被封装成切面,这样就可以在多个地方重用这些切面。
  • 易于维护:修改横切关注点只需要修改相应的切面,而不需要修改业务逻辑代码。

实现 AOP 的工具和技术:

  1. Spring AOP
    • Spring AOP 是Spring框架的一部分,它提供了一种实现AOP的强大方法。Spring AOP使用代理机制来实现AOP,并且支持基于注解和XML配置的方式来定义切面。
  2. AspectJ
    • AspectJ 是一个流行的AOP框架,它提供了一种更加强大的AOP实现方式。AspectJ可以在编译时或加载时织入切面,并且支持更复杂的切入点表达式。

自定义注解

自定义注解 (@Autofill) 是一种在Java中定义元数据的方式,可以用来标记类、方法或字段,并在运行时或编译时被处理。在Spring框架中,自定义注解通常用于控制某些行为,比如自动填充字段、事务管理、切面等方面。

Target

在Java中,@Target 是一个元注解,用于指定一个注解可以应用的目标类型。当你定义一个自定义注解时,可以使用 @Target 来限制这个注解的应用范围。

@Target 的作用:

@Target 元注解允许你指定自定义注解可以应用到Java语言中的哪些元素上,例如类、方法、字段、构造器等。这对于确保注解被正确使用非常重要。

@Target 的取值:

@Target 元注解的取值类型是 ElementType 枚举,它定义了Java语言中可以被注解的目标类型。以下是一些常见的 ElementType 值:

  1. ElementType.TYPE:表示可以应用到类、接口或枚举的声明上。
  2. ElementType.FIELD:表示可以应用到字段或属性的声明上。
  3. ElementType.METHOD:表示可以应用到方法的声明上。
  4. ElementType.PARAMETER:表示可以应用到方法参数的声明上。
  5. ElementType.CONSTRUCTOR:表示可以应用到构造器的声明上。
  6. ElementType.LOCAL_VARIABLE:表示可以应用到局部变量的声明上。
  7. ElementType.ANNOTATION_TYPE:表示可以应用到注解类型的声明上。
  8. ElementType.PACKAGE:表示可以应用到包的声明上。
  9. ElementType.TYPE_PARAMETER:表示可以应用到类型参数的声明上。
  10. ElementType.TYPE_USE:表示可以应用到类型使用的任何地方,例如泛型类型参数、方法返回类型等。

与target等价的

@Retention(RetentionPolicy.RUNTIME) 是一个元注解,用于指定一个自定义注解的保留策略。@Retention 元注解定义了注解在哪些阶段是可用的,而 RetentionPolicy 枚举则定义了注解的生命周期。

@Retention 元注解的作用:

@Retention 元注解用于指定自定义注解的保留策略,即注解在编译时、类文件或运行时是否仍然可用。

RetentionPolicy 枚举的取值:

RetentionPolicy 枚举有三个取值,分别定义了注解的生命周期:

  1. SOURCE:注解仅存在于源代码中,编译时会被丢弃。
  2. CLASS:注解被编译到class文件中,但在运行时不可见。
  3. RUNTIME:注解被编译到class文件中,并且在运行时可见

Netty

为致力于高性能的服务器程序,客服端程序,必须学会Netty

学习路程:从NIO编程开始,netty的底层是NIO编程,所以需要先熟悉NIO。

NIO:non-blocking IO 非阻塞IO

三大组件

Channel是数据双向通道;Buffer数据缓存区;Selector

多线程版设计:内存占用高,线程上下切换成本高,只适合连接数较少的场景。

线程池版设计:阻塞模式下,线程仅能处理一个socket,仅适合短链接场景。

selector版设计:配合一个线程管理多个channel,获取channel上发生的事件,这些channel工作在非阻塞模式下,不会让线程吊死在一个channel上,适合连接数多,但流量低的场景。

byteBuffer正确使用姿势

1.向buffer读入数据,比如调用channel.read(buffer)

2.调用flip()切换至读模式

3.从buffer读取数据,列如调用buffer。get()

4.调用clear()或compact()切换至写模式

5.重复1到4

compact方法,是把未读完的部分向前压缩,然后切换至写模式。

java.nio.HeapByteBuffer Java堆内存,读写效率较低,受到GC(垃圾回收)的影响

java.nio.DIrectByteBuffer 直接内存,读写效率高(少一次拷贝),不受影响,分配效率低

rewind 从头开始读;mark做一个标记,reset将position重置到mark的位置;allocate分配内存;scattering

容易出现问题:粘包,半包.

1
2
3
4
5
6
7
8
for(source.get(i)=='\n'){
int length = i+1 - source.position();
ByteBuffer target = ByteBuffer.allocate(length);
for(int j=0;j<length;j++){
target.put(source.get())
}
debugAll(target);
}

这里注意换行符只占一个字节

tranferto:两个channel的数据传输;效率高,地层会利用零拷贝进行优化。

nio阻塞模式

1
2
3
4
5
6
7
8
9
10
11
12
ServerSocketChannel ssc = ServerSocketChannel.open();//建立服务器
ByteBuffer buffer = ByteBuffer.allocate(16);
ssc.bind(new InetSocketAddress(8080))//绑定监听端口
List<SocketChannel> channels = new ArrayList<>();//连接集合
While(true){
//accept建立于客服端连接,Socketchannel用来与客服端之间通信
SocketChannel sc = ssc.accept();
channels.add(sc);
for(SocketChannel channel : channels){
//遍历,接收数据
}
}

在accpet这里阻塞了。阻塞模式下,单线程不能去执行别的任务——解决方法,一个连接一个线程

非阻塞:线程还会继续运行。非阻塞太繁忙没有连接时也在工作,容易过劳死。解决方法使用selector

accept——会在有连接请求时触发,也叫处理事件(调用它时)

connect——是客户端有连接建立后触发

read——可读事件

write——可写事件

selector(多路复用):select方法,没有事件发生,线程阻塞,有事件发生,线程恢复。

select在事件未处理时,它不会阻塞;事件发生后要么处理,要么取消,要么置之不理

selector会在事件发售加入数据,但不会删除。要自己移除key,否则下次处理就会有问题。

处理消息的边界:

一种是固定消息长度,数据包大小一样,服务器按预定长度读取,缺点是浪费宽带

一种是按分隔符拆分,缺点是效率低

TLV格式:及Type类型,Length长度,Value数据,类型和长度已知的情况下,就可以方便获取消息的大小,分配合适的buffer,缺点是buffer需要提前分配,如果内容过多,影响server吞吐量。