前言

如果这是你第二次看到师长,说明你在觊觎我的美色!

点赞+关注再看,养成习惯

没别的意思,就是需要你的窥屏_

专车介绍

该趟专车是开往基于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事务思想实战专车的更多相关文章

  1. 原创001 | 搭上SpringBoot自动注入源码分析专车

    前言 如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~ 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本系列为SpringBoot深度源码专车系列,第一篇发车 ...

  2. 【原创】004 | 搭上SpringBoot事务诡异事件分析专车

    前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本专车系列文章 目前连载到第四篇,本专题是深入讲解Springboot源码,毕竟是 ...

  3. 【原创】005 | 搭上SpringBoot请求处理源码分析专车

    前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析S ...

  4. 基于springboot构建dubbo的入门demo

    之前记录了构建dubbo入门demo所需的环境以及基于普通maven项目构建dubbo的入门案例,今天记录在这些的基础上基于springboot来构建dubbo的入门demo:众所周知,springb ...

  5. 【原创】002 | 搭上SpringBoot事务源码分析专车

    前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍** 该趟专车是开往Spring Boot事务源码分析的专车 专车问题 为 ...

  6. 基于SpringBoot+SSM实现的Dota2资料库智能管理平台

    Dota2资料库智能管理平台的设计与实现 摘    要 当今社会,游戏产业蓬勃发展,如PC端的绝地求生.坦克世界.英雄联盟,再到移动端的王者荣耀.荒野行动的火爆.都离不开科学的游戏管理系统,游戏管理系 ...

  7. 基于spring-boot的应用程序的单元测试方案

    概述 本文主要介绍如何对基于spring-boot的web应用编写单元测试.集成测试的代码. 此类应用的架构图一般如下所示: 我们项目的程序,对应到上图中的web应用部分.这部分一般分为Control ...

  8. idea基于springboot搭建ssm(maven)

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/liboyang71/article/det ...

  9. MyBatis 进阶,MyBatis-Plus!(基于 Springboot 演示)

    这一篇从一个入门的基本体验介绍,再到对于 CRUD 的一个详细介绍,在介绍过程中将涉及到的一些问题,例如逐渐策略,自动填充,乐观锁等内容说了一下,只选了一些重要的内容,还有一些没提及到,具体可以参考官 ...

随机推荐

  1. 二、安装JDK - Java软件的安装

    jdk是 Java 语言的软件开发工具包,主要用于移动设备.嵌入式设备上的java应用程序. 1.安装包的下载:http://pan.baidu.com/s/1mgh58ve (该安装包是绿色的,解压 ...

  2. 百度艾尼ERNIE专场再入魔都,11月23日线下开讲!

    这个十一月,是属于深度学习开发者们的秋季盛宴.『WAVE Summit+』2019 深度学习开发者秋季峰会刚刚落下帷幕,基于ERNIE的语义理解工具套件也在此次峰会上全新发布,旨在为企业级开发者提供更 ...

  3. vue使用一些外部插件及样式的配置

    一.配置全局css及js样式 1.首先将事先写好的css文件及js文件放在src文件目录下的assets文件下 2.在main.js文件输上图右边两个红色框的代码 二.配置全局jQuery及boots ...

  4. HashMap深入分析及使用要点

    本文内容来自深入理解HashMap.从数据结构谈HashMap.HashMap深度分析 先说使用要点. 1.不要在并发场景中使用HashMap HashMap是线程不安全的,如果被多个线程共享的操作, ...

  5. Docker学习-Docker搭建Consul集群

    1.环境准备 Linux机器三台 网络互通配置可以参考 https://www.cnblogs.com/woxpp/p/11858257.html 192.168.50.21 192.168.50.2 ...

  6. JS简单循环遍历json数组的方法

    例如数据库里面的json字符串是这样的 1 2 3 4 5 var str = '[{"name":"宗2瓜","num":"1& ...

  7. 02. JVM运行机制

    JVM运行机制 JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一.JVM启动流程

  8. nyoj 257 郁闷的C小加(一)(栈、队列)

    郁闷的C小加(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 我们熟悉的表达式如a+b.a+b*(c+d)等都属于中缀表达式.中缀表达式就是(对于双目运算符来说 ...

  9. nyoj 64-鸡兔同笼 (解二元一次方程)

    64-鸡兔同笼 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:26 submit:58 题目描述: 已知鸡和兔的总数量为n,总腿数为m.输入n和m, ...

  10. python:类1——类和对象基础

    一.OO = Object Oriented 面向对象 OOP面向对象编程.OOA面向对象分析.OOD面向对象设计 二.属性+方法——>类(数据和函数) class Turtle(): #类名约 ...