晚来天欲雪,能饮一杯无

个人记录


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索

netty(三)

发表于 2020-05-15

无锁设计、线程绑定

Netty采用了串行无锁化设计,在IO线程内部进行串行操作,避免多线程竞争导致的性能下降。表面上看,串行化设计似乎CPU利用率不高,并发程度不够。但是,通过调整NIO线程池的线程
参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列多个工作线程模型性能更优。

Netty的NioEventLoop读取到消息之后,直接调用ChannelPipeline的fireChannelRead(Object msg),只要用户不主动切换线程,一直会由NioEventLoop调用到用户的Handler,期间不进行线程切换,这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。

高性能的序列化框架

Netty默认提供了对Google Protobuf的支持,通过扩展Netty的编解码接口,用户可以实现其它的高性能序列化框架,例如Thrift的压缩二进制编解码框架。

  1. SO_RCVBUF和SO_SNDBUF:通常建议值为128K或者256K。
    小包封大包,防止网络阻塞
  2. SO_TCPNODELAY:NAGLE 算法通过将缓冲区内的小封包自动相连,组成较大的封包,阻止大量小封包的发送阻塞网络,从而提高网络应用效率。但是对于时延敏感的应用场景需要关闭该优化算法。
    软中断Hash值和CPU绑定
  3. 软中断:开启RPS后可以实现软中断,提升网络吞吐量。RPS根据数据包的源地址,目的地址以及目的和源端口,计算出一个hash值,然后根据这个hash值来选择软中断运行的cpu,从上层来看,也就是说将每个连接和cpu绑定,并通过这个hash值,来均衡软中断在多个cpu上,提升网络并行处理性能。

netty(二)

发表于 2020-05-14

高效的Reactor线程模型

  常用的Reactor线程模型有三种,Reactor单线程模型, Reactor多线程模型, 主从Reactor多线程模型。

Reactor单线程模型

  Reactor单线程模型,指的是所有的IO操作都在同一个NIO线程上面完成,NIO线程的职责如下:
1) 作为NIO服务端,接收客户端的TCP连接;
2) 作为NIO客户端,向服务端发起TCP连接;
3) 读取通信对端的请求或者应答消息;
4) 向通信对端发送消息请求或者应答消息。
avatar
  由于Reactor模式使用的是异步非阻塞IO,所有的IO操作都不会导致阻塞,理论上一个线程可以独立处理所有IO相关的操作。从架构层面看,一个NIO线程确实可以完成其承担的职责。例如,通过Acceptor接收客户端的TCP连接请求消息,链路建立成功之后,通过Dispatch将对应的ByteBuffer派发到指定的Handler上进行消息解码。用户Handler可以通过NIO线程将消息发送给客户端。

Reactor多线程模型

  Rector多线程模型与单线程模型最大的区别就是有一组NIO线程处理IO操作。有专门一个NIO线程-Acceptor线程用于监听服务端,接收客户端的TCP连接请求;网络IO操作-读、写等由一个NIO线程池负责,线程池可以采用标准的 JDK 线程池实现,它包含一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送;
avatar

主从 Reactor多线程模型

  服务端用于接收客户端连接的不再是个1个单独的NIO线程,而是一个独立的NIO线程池。Acceptor接收到客户端TCP连接请求处理完成后(可能包含接入认证等),将新创建的SocketChannel注册到IO线程池(sub reactor线程池)的某个IO线程上,由它负责SocketChannel的读写和编解码工作。Acceptor线程池仅仅只用于客户端的登陆、握手和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的IO线程上,由IO线程负责后续的IO操作。
avatar

netty(一)

发表于 2020-05-12

Netty原理

  Netty是一个高性能、异步事件驱动的NIO框架,基于JAVA NIO提供的API实现。它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

Netty高性能

  在IO编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者IO多路复用技术进行处理。IO多路复用技术通过把多个IO的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源。
  与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。

多路复用通讯方式

  Netty架构按照Reactor模式设计和实现,它的服务端通信序列图如下:
avatar
  客户端通信序列图如下:
avatar
  Netty的IO线程NioEventLoop由于聚合了多路复用器Selector,可以同时并发处理成百上千个客户端Channel,由于读写操作都是非阻塞的,这就可以充分提升IO线程的运行效率,避免由于频繁IO阻塞导致的线程挂起。

异步通讯NIO

  由于Netty采用了异步通信模式,一个IO线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞IO 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

零拷贝(DIRECT BUFFERS使用堆外直接内存)

  1. Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
  2. Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。
  3. Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。

内存池(基于内存池的缓冲区重用机制)

  随着JVM虚拟机和JIT即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区Buffer,情况却稍有不同,特别是对于堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty提供了基于内存池的缓冲区重用机制。

微服务(三)

发表于 2020-05-11

服务熔断(Hystrix)

  在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。
  熔断器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。

Hystrix 断路器机制

  断路器很好理解, 当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况,如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN).Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。

API 管理

  SwaggerAPI管理工具:
https://hacpai.com/article/1519833837647

微服务(二)

发表于 2020-05-09

配置中心

配置中心一般用作系统的参数配置,它需要满足如下几个要求:高效获取、实时感知、分布式访问。

zookeeper配置中心

实现的架构图如下所示,采取数据加载到内存方式解决高效获取的问题,借助zookeeper的节点监听机制来实现实时感知。
avatar

配置中心数据分类

avatar

事件调度(kafka)

消息服务和事件的统一调度,常用的kafka,activemq等
kafka:https://juejin.im/post/5a67f7e7f265da3e3c6c4f8b

服务跟踪(starter-sleuth)

随着微服务数量不断增长,需要跟踪一个请求从一个微服务到下一个微服务的传播过程,Spring Cloud Sleuth正是解决这个问题,它在日志中引入唯一 ID,以保证微服务调用之间的一致性,这样你就能跟踪某个请求是如何从一个微服务传递到下一个。

  1. 为了实现请求跟踪,当请求发送到分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的跟踪标识,同时在分布式系统内部流转的时候,框架始终保持传递该唯一标识,直到返回给请求方为止,这个唯一标识就是前文中提到的Trace ID。通过Trace ID的记录,我们就能将所有请求过程日志关联起来。
  2. 为了统计各处理单元的时间延迟,当请求达到各个服务组件时,或是处理逻辑到达某个状态时,也通过一个唯一标识来标记它的开始、具体过程以及结束,该标识就是我们前文中提到的Span ID,对于每个Span来说,它必须有开始和结束两个节点,通过记录开始 Span 和结束Span的时间戳,就能统计出该Span的时间延迟,除了时间戳记录之外,它还可以包含一些其他元数据,比如:事件名称、请求信息等。
  3. 在快速入门示例中,我们轻松实现了日志级别的跟踪信息接入,这完全归功于spring-cloudstarter-sleuth组件的实现。在Spring Boot应用中,通过在工程中引入 spring-cloudstarter-sleuth 依赖之后, 它会自动的为当前应用构建起各通信通道的跟踪机制,比如:①通过诸如 RabbitMQ、Kafka(或者其他任何 Spring Cloud Stream 绑定器实现的消息中间件)传递的请求。②通过Zuul代理传递的请求。③通过RestTemplate发起的请求。

微服务(一)

发表于 2020-05-08

服务注册发现

  服务注册就是维护一个登记簿,它管理系统内所有的服务地址。当新的服务启动后,它会向登记簿交待自己的地址信息。服务的依赖方直接向登记簿要Service Provider地址就行了。当下用于服务注册的工具非常多ZooKeeper,Consul,Etcd, 还有Netflix家的eureka等。服务注册有两种形式:客户端注册和第三方注册。

客户端注册(zookeeper)

  客户端注册是服务自身要负责注册与注销的工作。当服务启动后向注册中心注册自身,当服务下线时注销自己。期间还需要和注册中心保持心跳。心跳不一定要客户端来做,也可以由注册中心负责(这个过程叫探活)。这种方式的缺点是注册工作与服务耦合在一起,不同语言都要实现一套注册逻辑。
avatar

第三方注册(独立的服务Registrar)

  第三方注册由一个独立的服务Registrar负责注册与注销。当服务启动后以某种方式通知Registrar,然后Registrar负责向注册中心发起注册工作。同时注册中心要维护与服务之间的心跳,当服务不可用时,向注册中心注销服务。这种方式的缺点是Registrar必须是一个高可用的系统,否则注册工作没法进展。
avatar

客户端发现

  客户端发现是指客户端负责查询可用服务地址,以及负载均衡的工作。这种方式最方便直接,而且也方便做负载均衡。再者一旦发现某个服务不可用立即换另外一个,非常直接。缺点也在于多语言时的重复工作,每个语言实现相同的逻辑。
avatar

服务端发现

  服务端发现需要额外的Router服务,请求先打到Router,然后Router负责查询服务与负载均衡。这种方式虽然没有客户端发现的缺点,但是它的缺点是保证Router的高可用。
avatar


API 网关

  API Gateway是一个服务器,也可以说是进入系统的唯一节点。这跟面向对象设计模式中的Facade模式很像。API Gateway封装内部系统的架构,并且提供API给各个客户端。它还可能有其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等。下图展示了一个适应当前架构的API Gateway。
avatar
  API Gateway负责请求转发、合成和协议转换。所有来自客户端的请求都要先经过API Gateway,然后路由这些请求到对应的微服务。API Gateway将经常通过调用多个微服务来处理一个请求以及聚合多个服务的结果。它可以在web协议与内部使用的非Web友好型协议间进行转换,如HTTP协议、WebSocket协议。

请求转发

  服务转发主要是对客户端的请求安装微服务的负载转发到不同的服务上

响应合并

  把业务上需要调用多个服务接口才能完成的工作合并成一次调用对外统一提供服务。
  ps:https://blog.csdn.net/u012702547/article/details/78213270

协议转换

  重点是支持SOAP,JMS,Rest间的协议转换。
  ps:JSM https://www.cnblogs.com/chenpi/p/5559349.html

数据转换

  重点是支持 XML和Json之间的报文格式转换能力(可选)

安全认证

  1. 基于Token的客户端访问控制和安全策略
  2. 传输数据和报文加密,到服务端解密,需要在客户端有独立的SDK代理包
  3. 基于Https的传输加密,客户端和服务端数字证书支持
  4. 基于OAuth2.0的服务安全认证(授权码,客户端,密码模式等)

spring原理(五)

发表于 2020-05-01

JPA原理

事务

  事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation )和持久性(Durabilily)。

本地事务

  紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内。此种事务处理方式不存在对应用服务器的依赖,因而部署灵活却无法支持多数据源的分布式事务。在数据库连接中使用本地事务示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void transferAccount() {
Connection conn = null;
Statement stmt = null;
try {
conn = getDataSource().getConnection();
// 将自动ᨀ交设置为 false,若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动ᨀ交
conn.setAutoCommit(false);
stmt = conn.createStatement();
// 将 A 账户中的金额减少 500
stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
// ᨀ交事务
conn.commit();
// 事务ᨀ交:转账的两步操作同时成功
} catch (SQLException sqle) {
// 发生异常,回滚在本事务中的操做
conn.rollback();
// 事务回滚:转账的两步操作完全撤销
stmt.close();
conn.close();
}
}

分布式事务

  Java事务编程接口(JTA:Java Transaction API)和Java事务服务(JTS;Java Transaction Service)为J2EE平台提供了分布式事务服务。分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器(Resource Manager )。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务参与单元的协调与控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void transferAccount2() {
UserTransaction userTx = null;
Connection connA = null;
Statement stmtA = null;
Connection connB = null;
Statement stmtB = null;
try {
// 获得 Transaction 管理对象
userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction");
connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
userTx.begin(); // 启动事务
stmtA = connA.createStatement();// 将 A 账户中的金额减少 500
stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmtB = connB.createStatement();
stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
userTx.commit();// 提交事务
// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
} catch (SQLException sqle) {
// 发生异常,回滚在本事务中的操纵
userTx.rollback();// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销
} catch (Exception ne) {
}
}

两阶段提交

  两阶段提交主要保证了分布式事务的原子性:即所有结点要么全做要么全不做,所谓的两个阶段是指:第一阶段:准备阶段;第二阶段:提交阶段。
avatar

准备阶段

  事务协调者(事务管理器)给每个参与者(资源管理器)发送Prepare消息,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的redo和undo日志,但不提交,到达一种“万事俱备,只欠东风”的状态。

提交阶段

  如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)

  将提交分成两阶段进行的目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作。

Springboot(一)

发表于 2020-04-30

  Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。其特点如下:

  1. 创建独立的Spring应用程序
  2. 嵌入的Tomcat,无需部署WAR文件
  3. 简化Maven配置
  4. 自动配置Spring
  5. 供生产就绪型功能,如指标,健康检查和外部配置
  6. 绝对没有代码生成和对XML没有要求配置 [1]

  约定大于配置是springboot的主导思想,对于springboot而言,大部分情况下存在默认的配置。
  对于你收这些项目必须的功能,Springboot 提供starter的依赖,例如spring-boot-starter-web提供了SpringMVC所依赖的包,spring-boot-starter-tomcat绑定了内嵌的tomcat,这样能使开发者尽快的搭建环境,快速开发和部署

Spring原理(四)--MVC流程和注解

发表于 2020-04-28

  Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。

MVC流程

avatar
  Http请求到DispatcherServlet(1)客户端请求提交到DispatcherServlet。
  HandlerMapping寻找处理器(2)由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller。
  调用处理器Controller(3)DispatcherServlet将请求提交到Controller。Controller调用业务逻辑处理后,返回ModelAndView。
  (4)(5)调用业务处理和返回结果:Controller调用业务逻辑处理后,返回ModelAndView。DispatcherServlet查询ModelAndView
  (6)(7)处理视图映射并返回模型:DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图。ModelAndView反馈浏览器HTTP
  (8)Http响应:视图负责将结果显示到客户端。

MVC 常用注解

avatar
【类上的标注】
@Controller
  用于标注控制层组件,标记在一个类上,使用它标记的类就是一个SpringMVC Controller对象,分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解,可以吧Request请求header部分的值绑定到方法的参数上。
@RestController
  相当于@Controller和@reponseBody的组合效果
@Conmponent
  泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注
@Repository
  用于注解dao层,在daoImpl类上面注解
@Service
  用于标注业务层组件
【类内的标注】
@ResponseBody
  异步请求,用于将Controller的方法返回的对象,通过适当单独HTTPMessageConverter转换为指定格式后,写入到Response对象的body数据区。返回的数据不是html标签的页面,而是其他某种格式的数据(json,xml)时使用
@RequestMapping
  一个用来处理请求地址映射的注解,可用于类或者方法上,用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@Autowired
  他对类成员变量,方法及构造函数进行标注,完成自动装配的工作,通过@Autowired的使用来消除setget方法。
@PathVariable
  用于将请求url中的模板变量映射到功能处理方法的参数上,即取出url模板中的变量作为参数
@RequestParam
  主要用于在SpringMVC后台控制层获取参数,类似一种request.getParameter(“name”)
@RequestHeader
  可以把request请求header部分父值绑定到方法的参数上。

Spring原理(三)---AOP

发表于 2020-04-27

概念

  “横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面。所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
  使用”横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
  AOP主要应用场景有:

  1. Authentication 权限
  2. Caching 缓存
  3. Context passing 内容传递
  4. Error handling 错误处理
  5. Lazy loading 懒加载
  6. Debugging 调试
  7. logging, tracing, profiling and monitoring 记录跟踪 优化 校准
  8. Performance optimization 性能优化
  9. Persistence 持久化
  10. Resource pooling 资源池
  11. Synchronization 同步
  12. Transactions 事务

AOP核心概念

  1. 切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象。
  2. 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。
  3. 连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。
  4. 切入点(pointcut):对连接点进行拦截的定义
  5. 通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
  6. 目标对象:代理的目标对象
  7. 织入(weave):将切面应用到目标对象并导致代理对象创建的过程
  8. 引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
    avatar

AOP两种代理方式

  Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。

JDK动态接口代理

  JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

CGLib动态代理

  CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。
  和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。

实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Aspect
public class TransactionDemo {
@Pointcut(value = "execution(* com.wuxu.core.service.*.*.*(..))")
public void point() {}
@Before(value = "point()")
public void before() {
System.out.println("transaction begin");
}
@AfterReturning(value = "point()")
public void after() {
System.out.println("transaction commit");
}
@Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("transaction begin");
joinPoint.proceed();
System.out.println("transaction commit");
}
}

参考

https://blog.csdn.net/moreevan/article/details/11977115/#

123…10
无恤

无恤

java博客

95 日志
7 分类
29 标签
GitHub
© 2018 - 2021 无恤
本站访客数:人次
本站总访问量次