当前位置: 移动技术网 > IT编程>开发语言>Java > 【原创】003 | 搭上基于SpringBoot事务思想实战专车

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

2019年12月11日  | 移动技术网IT编程  | 我要评论

前言

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

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

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

专车介绍

该趟专车是开往基于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进阶架构师】)

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网