前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Java 注解处理器(Annotation Processor)来避免Spring事务抛出受检异常Exception无法回滚

使用Java 注解处理器(Annotation Processor)来避免Spring事务抛出受检异常Exception无法回滚

作者头像
崔认知
发布2024-01-22 15:41:21
2560
发布2024-01-22 15:41:21
举报
文章被收录于专栏:nobodynobody

Java 注解处理器

Java 注解处理器(Annotation Processor)是 Java 编译器的一部分,用于处理源代码中的注解信息。它可以在编译时扫描和处理注解,并生成额外的代码或者进行其它的操作。注解处理器可以用来自动生成代码、进行代码检查、生成文档等。

Spring声明式事务@Transactional避坑:抛出受检异常Exception无法回滚


默认情况下,非受检异常会回滚,受检异常Exception不会回滚事务

Spring避坑指南:Spring声明式事务@Transactional避坑 崔认知,公众号:认知科技技术团队Spring避坑指南:Spring声明式事务@Transactional避坑

所以,我们必须在配置:

代码语言:javascript
复制
@Transactional(rollbackFor = Exception.class)

Java 注解处理器自动检查代码


Java 注解处理器(Annotation Processor)由于是在编译期处理注解,处理的注解必须在编译期被保留,即:注解的RetentionPolicy不能是:java.lang.annotation.RetentionPolicy#SOURCE。由于Transactional的RetentionPolicy是

RetentionPolicy.RUNTIME,所以可以使用 Java 注解处理器来处理。

实现Java 注解处理器需要实现javax.annotation.processing.AbstractProcessor,并根据SPI的加载规则需要在文件META-INF/services/javax.annotation.processing.Processor中配置自定义实现的Java 注解处理类。

这里使用auto-service工具来自动实现SPI的文件生成:

代码语言:javascript
复制
 <dependency>
      <groupId>com.google.auto.service</groupId>
      <artifactId>auto-service</artifactId>
      <version>1.1.1</version>
    </dependency>

检测Spring注解事务没有配置rollbackFor = Exception.class的自定义注解处理器:

代码语言:javascript
复制
package org.renzhikeji;

import com.google.auto.service.AutoService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 * @author 认知科技技术团队
 * 微信公众号:认知科技技术团队
 */
@SupportedAnnotationTypes("org.springframework.transaction.annotation.Transactional")
@AutoService(Processor.class)
public class TransactionalProcessor extends AbstractProcessor {
    private static ConcurrentHashMap<Element, Element> message = new ConcurrentHashMap<>();

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("=======Transactional rollbackFor=Exception.class== 处理 ");

        Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(Transactional.class);
        for (Element element : elementsAnnotatedWith) {
            if (!element.getKind().isExecutable()) {
                continue;
            }

            Map<String, Object> keyValues = getAnnotation(element, Transactional.class.getName());

            if (keyValues.isEmpty()) {
                message.put(element, element);
                continue;
            }


            Set<String> rollbackFor = Optional.ofNullable((List<Object>) keyValues.get("rollbackFor")).stream()
                                              .map(Object::toString).collect(Collectors.toSet());



            if ( !rollbackFor.contains("java.lang.Exception.class")) {
                message.put(element, element);
            }
        }


        if (!message.isEmpty()) {
            throw new RuntimeException("使用spring的事务注解Transactional,请配置rollbackFor=Exception.class,防止事务失效");
        }

        return true;
    }


    private static Map<String, Object> getAnnotation(Element element, String name) {
        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
            if (mirror.getAnnotationType().toString().equals(name)) {
                return annotationKeyValues(mirror);
            }
        }
        throw new IllegalArgumentException(String.format("%s has no annotation %s", element, name));
    }

    private static Map<String, Object> annotationKeyValues(AnnotationMirror mirror) {
        Map<String, Object> result = new LinkedHashMap<>();
        for (ExecutableElement key : mirror.getElementValues().keySet()) {
            result.put(key.getSimpleName().toString(), mirror.getElementValues().get(key).getValue());
        }
        return result;
    }

}

编译打包后,auto-service工具来自动实现SPI的文件生成:

在项目中maven依赖自定义实现的注解处理器jar包,并测试:

编译时报错:

小结


Java 注解处理器是一种用于处理源代码中注解信息的工具,可以在编译时对代码进行静态分析和修改,实现自动化任务和定制框架行为。比如:代码生成工具框架lombok、SPI文件自动生成工具auto-service、代码检测工具error-prone等。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring声明式事务@Transactional避坑:抛出受检异常Exception无法回滚
相关产品与服务
检测工具
域名服务检测工具(Detection Tools)提供了全面的智能化域名诊断,包括Whois、DNS生效等特性检测,同时提供SSL证书相关特性检测,保障您的域名和网站健康。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档