【原创】003 | 搭上基于SpringBoot事务思想实战专车
前言
如果这是你第二次看到师长,说明你在觊觎我的美色!
点赞+关注再看,养成习惯
没别的意思,就是需要你的窥屏_

专车介绍
该趟专车是开往基于Spring Boot事务思想实战的专车,在上一篇 搭上SpringBoot事务源码分析专车[1]中我们详细介绍了Spring Boot事务实现的原理,这一篇是基于上一篇的实战。

在实战之前,我们再次回顾下上篇文章讲解的重点:
- 后置处理器:对Bean进行拦截并处理
- 切面:由切点和通知组成
- 切点:用于匹配符合的类和方法
- 通知:用于代理处理
专车问题
- 如何利用后置处理器对Bean进行拦截并处理?
- 如何定义切面?
- 如何定义切点?
- 如何定义通知?
- 如何实现自动配置?
专车分析
实现是以Spring Boot为基础,需要添加如下依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
按照如上提到的问题依次定义
定义bean后置处理器,特别注意,如果项目中使用到了事务特性,就不需要重复定义
/**
* 一定要声明InfrastructureAdvisorAutoProxyCreator,用于实现bean的后置处理
*
* @return
*/
@Bean
public InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator() {
return new InfrastructureAdvisorAutoProxyCreator();
}
定义切面
public class BeanFactorySystemLogAdvisor extends AbstractBeanFactoryPointcutAdvisor {
/**
* 定义切点
*/
private final SystemLogPointcut point = new SystemLogPointcut();
@Override
public Pointcut getPointcut() {
return this.point;
}
}
定义切点
public class SystemLogPointcut extends StaticMethodMatcherPointcut {
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 查找类上@SystemLog注解属性
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
targetClass, SystemLog.class, false, false);
if (Objects.nonNull(attributes)) {
return true;
}
// 查找方法上@SystemLog注解属性
attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
method, SystemLog.class, false, false);
return Objects.nonNull(attributes);
}
}
定义通知
@Slf4j
public class SystemLogInterceptor implements MethodInterceptor, Serializable {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
String className = method.getDeclaringClass().getSimpleName();
String methodName = method.getName();
log.info("======[" + className + "#" + methodName + " method begin execute]======");
Arrays.stream(invocation.getArguments()).forEach(argument -> log.info("======[execute method argument:" + argument + "]======"));
Long time1 = Clock.systemDefaultZone().millis();
Object result = invocation.proceed();
Long time2 = Clock.systemDefaultZone().millis();
log.info("======[method execute time:" + (time2 - time1) + "]======");
return result;
}
}
自动配置
@Configuration
public class ProxySystemLogConfiguration {
/**
* 定义切面
* 此处一定要指定@Role注解
*
* @return
*/
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Bean
public BeanFactorySystemLogAdvisor beanFactorySystemLogAdvisor() {
BeanFactorySystemLogAdvisor advisor = new BeanFactorySystemLogAdvisor();
advisor.setAdvice(systemLogInterceptor());
return advisor;
}
/**
* 定义通知
*
* @return
*/
@Bean
public SystemLogInterceptor systemLogInterceptor() {
return new SystemLogInterceptor();
}
/**
* 一定要声明InfrastructureAdvisorAutoProxyCreator,用于实现bean的后置处理
*
* @return
*/
@Bean
public InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator() {
return new InfrastructureAdvisorAutoProxyCreator();
}
}
定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {
}
专车集成业务
定义控制器
@RestController
public class SystemLogController {
@Autowired
private SystemLogService systemLogService;
@GetMapping("/log")
public String hello(@RequestParam("name") String name) throws InterruptedException {
return systemLogService.log(name);
}
}
定义业务方法
@Slf4j
@Service
public class SystemLogService {
@SystemLog
public String log(String name) throws InterruptedException {
log.info("执行业务方法");
TimeUnit.SECONDS.sleep(1);
return "hello " + name;
}
}
定义启动类
@SpringBootApplication
public class TransactionImitateApplication {
public static void main(String[] args) {
SpringApplication.run(TransactionImitateApplication.class, args);
}
}
访问http://localhost:8080/log?name=advisor
查看控制台
2019-08-23 11:13:36.029 INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor : ======[SystemLogService#log method begin execute]======2019-08-23 11:13:36.030 INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor : ======[execute method argument:advisor]======2019-08-23 11:13:36.038 INFO 23227 --- [nio-8080-exec-1] c.boot.example.service.SystemLogService : 执行业务方法2019-08-23 11:13:37.038 INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor : ======[method execute time:1004]======
可以看到通过模拟@Transaction注解的实现方式,完成了日志切面功能。
专车总结
- 首先我们需要定义一个Bean后置处理器,用于拦截处理Bean
- 然后定义切面,在切面中定义切点
- 切点中实现切入的逻辑,比如此处我们的实现逻辑就是查找类或方法上是否含有@SystemLog注解
- 定义通知,完成代理工作
- 自动装配,将我们的切面、通知、Bean后置处理器声明在配置类中
- 集成业务
专车回顾
回顾下开头的五个问题:
- 如何利用后置处理器对Bean进行拦截并处理?直接在配置类中声明后置处理器
- 如何定义切面?继承AbstractBeanFactoryPointcutAdvisor,并在配置类中中声明
- 如何定义切点?继承StaticMethodMatcherPointcut,实现matches方法
- 如何定义通知?实现MethodInterceptor接口,实现invoke方法
- 如何实现自动配置?自定义配置类,声明所有需要加入容器的Bean
最后
师长,【java进阶架构师】号主,短短一年在各大平台斩获15W+程序员关注,专注分享Java进阶、架构技术、高并发、微服务、BAT面试、redis专题、JVM调优、Springboot源码、mysql优化等20大进阶架构专题,关注【java进阶架构师】回复【架构】领取2019架构师完整视频一套。
转载说明:请务必注明来源(本文首发于公众号:【java进阶架构师】)
【原创】003 | 搭上基于SpringBoot事务思想实战专车的更多相关文章
- 原创001 | 搭上SpringBoot自动注入源码分析专车
前言 如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~ 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本系列为SpringBoot深度源码专车系列,第一篇发车 ...
- 【原创】004 | 搭上SpringBoot事务诡异事件分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本专车系列文章 目前连载到第四篇,本专题是深入讲解Springboot源码,毕竟是 ...
- 【原创】005 | 搭上SpringBoot请求处理源码分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析S ...
- 基于springboot构建dubbo的入门demo
之前记录了构建dubbo入门demo所需的环境以及基于普通maven项目构建dubbo的入门案例,今天记录在这些的基础上基于springboot来构建dubbo的入门demo:众所周知,springb ...
- 【原创】002 | 搭上SpringBoot事务源码分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍** 该趟专车是开往Spring Boot事务源码分析的专车 专车问题 为 ...
- 基于SpringBoot+SSM实现的Dota2资料库智能管理平台
Dota2资料库智能管理平台的设计与实现 摘 要 当今社会,游戏产业蓬勃发展,如PC端的绝地求生.坦克世界.英雄联盟,再到移动端的王者荣耀.荒野行动的火爆.都离不开科学的游戏管理系统,游戏管理系 ...
- 基于spring-boot的应用程序的单元测试方案
概述 本文主要介绍如何对基于spring-boot的web应用编写单元测试.集成测试的代码. 此类应用的架构图一般如下所示: 我们项目的程序,对应到上图中的web应用部分.这部分一般分为Control ...
- idea基于springboot搭建ssm(maven)
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/liboyang71/article/det ...
- MyBatis 进阶,MyBatis-Plus!(基于 Springboot 演示)
这一篇从一个入门的基本体验介绍,再到对于 CRUD 的一个详细介绍,在介绍过程中将涉及到的一些问题,例如逐渐策略,自动填充,乐观锁等内容说了一下,只选了一些重要的内容,还有一些没提及到,具体可以参考官 ...
随机推荐
- RocketMQ 主从同步若干问题答疑
目录 1.初识主从同步 2.提出问题 3.原理探究 3.1 RocketMQ主从读写分离机制 3.2 消息消费进度同步机制 4.总结 温馨提示:建议参考代码RocketMQ4.4版本,4.5版本引入了 ...
- Scrapy进阶知识点总结(三)——Items与Item Loaders
一.Items 抓取的主要目标是从非结构化源(通常是网页)中提取结构化数据.Scrapy蜘蛛可以像Python一样返回提取的数据.虽然方便和熟悉,但Python缺乏结构:很容易在字段名称中输入拼写错误 ...
- websocket socketJs
springboot实现服务器端消息推送(websocket + sockjs + stomp) 服务器端推送技术在web开发中比较常用,可能早期很多人的解决方案是采用ajax向服务器轮询消息,这 ...
- 使用vue-cli搭建项目开发环境
一.前言 本篇文章主要是使用vue-cli搭建一个简单的vue项目,这个项目在其他文章中作为代码演示的环境会一直使用. 注意:默认大家的电脑已经安装nodejs,所以这里不总结nodejs的安装. 二 ...
- 利用爬虫爬取LOL官网上皮肤图片
今天在浏览网页时,看到一篇很有意思的文章,关于网络爬虫的.该文章是讲述如何利用request爬取英雄联盟官网皮肤图片.看过文章后觉得挺有用的,把代码拿过来运行了一下,果真爬取成功.下面给大家分享一下代 ...
- [UWP]使用Win2D的BorderEffect实现图片的平铺功能
1. WPF有,而UWP没有的图片平铺功能 在WPF中只要将ImageSource的TileMode属性设置为Tile即可实现图片的平铺,具体可见WPF的这些文档: ImageBrush 类 (Sys ...
- PHP 将数据从 Laravel 传送到 vue 的四种方式
在过去的两三年里,我一直在研究同时使用 Vue 和 Laravel 的项目,在每个项目开发的开始阶段,我必须问自己 “我将如何将数据从 Laravel 传递到 Vue ?”.这适用于 Vue 前端组件 ...
- java编程思想第四版第十八章总结
一.概述 如何学习java I/O 学习I/O类库 学习I/O发展史,为什么要学习发展史呢? 因为,如果缺乏发展史,我们就会对什么时候使用哪个类,以及什么时候不该使用它们而感到迷惑. 了解nio 二. ...
- nyoj 822-画图 (*)
822-画图 内存限制:64MB 时间限制:1000ms 特判: No 通过数:133 提交数:187 难度:0 题目描述: 计算机画图也挺有趣的哈!那我们就来用计算机画幅图吧... 输入描述: 输入 ...
- 在 Windows 上 安装 Oracle 11g Xe
去oracle官网下载 https://www.oracle.com/database/technologies/xe-prior-releases.html 点击下载: Oracle Databas ...