【原创】003 | 搭上基于SpringBoot事务思想实战专车


声明:本文转载自https://my.oschina.net/shizhang/blog/3141719,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

前言

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

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

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

专车介绍

该趟专车是开往基于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大进阶架构专题。欢迎来稿。

本文发表于2019年12月11日 23:00
(c)注:本文转载自https://my.oschina.net/shizhang/blog/3141719,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 255 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

又是一年五一,祝我们工人阶级劳动节快乐! 今年被困在北京了,离境再入境需要隔离十五天。只能京津冀周边走一走了,想出去玩啊啊啊啊啊~

人活一辈子,不是一年两年。时间是有连续性的,做抉择的时候要多看几步。保持警惕,大丈夫有所为,有所不为。

跟人接触,不要想:我能从你身上得到什么,要想:我能给你什么。 想通了,内核就稳了。

这个世界上,别人只会看你现在的样子而不是以后的样子。你以后的样子只有自己才相信。如果没有执行力,一切都是虚妄。

对普通人来说,人和人相处其实最重要的是感觉。感觉不好,你说什么都没用,怎么解释都没用,越说越错,反正最后不好的锅都往你身上扣。所谓“说你行你就行,不行也行。说你不行,你就不行,行也不行”就是这个意思。狼要吃人根本不需要理由,你也同样叫不醒装睡的人。遇到这种情况,早点闪人才是上策。不过大部分人的问题是没有闪人的心态,能力,和资源。

快捷链接
网站地图
提交友链
Copyright © 2016 - 2020 Cion.
All Rights Reserved.
ICP备案:鲁ICP备19012333号-4.

鲁公网安备 37061302000383号.