欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-09-27 16:11:32
前言 如果这是你 第二次 看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往基于Spring Boot事务思想实战的专车,在上一篇 搭上SpringBoot事务源码分析专车 [1]中我们详细介绍了Spring Boot事务实现的原 ......

前言

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

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

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

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

专车介绍

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

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

在实战之前,我们再次回顾下上篇文章讲解的重点:

  • 后置处理器:对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进阶架构师】)