码迷,mamicode.com
首页 > 编程语言 > 详细

javac AbstractProcessor

时间:2021-01-02 11:25:37      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:doc   数据   dal   one   模板   abstract   substring   截取   ima   

说明

Annotation Processor是javac的一个工具,它用来在编译时扫描和处理注解,通过Annotation Processor可以获取到注解和被注解类的相关信息,然后根据注解自动生成Java代码,省去了手动编写,提高了编码效率。

它可以做什么

在编译的时候动态生成类或者改变类的代码!如:

lomock:减少get 和set方法的模板代码生成

mapstruct: 动态生成po vo 互转的Convert类

hibernate-jpamodelge 动态生成PO类的元数据映射,减少操作字段的模板代码

需求

公司内部自己实现了一套基于redis 的CRUD的ORM框架

     //保存活动信息
        BookingActivitySettingRo bookingActivitySettingRo=new BookingActivitySettingRo();
        bookingActivitySettingRo.setId(1L);
        bookingActivitySettingRo.setActivityName("哈哈哈");
        bookingActivitySettingRedisDao.save(bookingActivitySettingRo);
        //查询
        bookingActivitySettingRedisDao.findOne(1L);
        //批量查询
        bookingActivitySettingRedisDao.findByIds(Arrays.asList(1l,2l));
        //删除
        bookingActivitySettingRedisDao.delete(bookingActivitySettingRo.getId());
        //编辑
        BookingActivitySettingRo settingRedisDaoOne= bookingActivitySettingRedisDao.findOne(1L);
        settingRedisDaoOne.setActivityName("我是修改名字");
        bookingActivitySettingRedisDao.save(settingRedisDaoOne);

为了解决以下问题 

针对并发场景只操作RO部分字段,优化以下场景的写法导致魔法值过多不易维护问题
1.并发编辑操作,只操作指定字段,避免整个ro回填,覆盖了其他线程修改的值
2.并发查询操作,追求性能,RO字段过多,只查询关心部分字段 hmget
基础工程redis版本1.3.0-SNAPSHO,增加了编译时自动生成映射类

技术图片

 

 

 技术图片

 

 

自定义Processor

参考了hibernate-jpamodelge的实现

1.实现自定义Processor继承AbstractProcessor重写process方法

/**
 * @Project 商品uaa
 * @PackageName cn.wine.ms.common.gennerator
 * @ClassName RedisRoAbstractProcessor
 * @Author qiang.li
 * @Date 2020/12/28 1:13 下午
 * @Description 用于编译时针对打了RO注解的类 生成key的映射,优化hset等redis操作部分字段写魔法值的问题
 */
@SupportedAnnotationTypes({"cn.wine.base.redis.annotation.Ro"})//你的注解的全名称
@SupportedSourceVersion(SourceVersion.RELEASE_8)//jdk环境为java8
public class RedisRoProcessor extends AbstractProcessor {
    /**
     * {@inheritDoc}
     * @param annotations
     * @param roundEnvironment
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        //遍历所有打了注解的类
        if (!roundEnvironment.processingOver() && annotations.size() != 0) {
            Set<? extends Element> elements = roundEnvironment.getRootElements();
            Iterator var4 = elements.iterator();
            while (var4.hasNext()) {
                Element element = (Element) var4.next();
                //只处理打了RO注解的类
                if (this.isRoEntity(element)) {
                    try {
                        createClass(element);
                    }catch (Exception e){
                        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,e.getMessage());
                    }
                }
            }
        }
        return true;
    }
    /**
     * 创建class文件
     * @param element
     * @throws IOException
     */
    public void createClass(Element element) throws IOException {
        //获得full类名
        String className=(((TypeElement)element).getQualifiedName()).toString();
        //获得包名
        String metaModelPackage=className.substring(0,className.lastIndexOf("."));
        //获得属性元数据
        List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn(element.getEnclosedElements());
        //生成classBody
        String classBody=generateClassBody(fieldsOfClass);
        //用户截取原始类名的startIndex
        Integer index=className.lastIndexOf(".")+1;
        //获得class名字
        String simpleClassName=className.substring(index,className.length());
        //新类的className
        String newClassName=String.format("%s_",simpleClassName);
        //根据名字创建class文件
        createFile(newClassName,metaModelPackage,classBody);
    }
    public void  createFile(String genarateClassName,String metaModelPackage,String body) throws IOException {
        //生成包名
        String generatePackageName = metaModelPackage;
        //创建Java 文件
        JavaFileObject f =processingEnv.getFiler().createSourceFile(genarateClassName);
        try(Writer w = f.openWriter();){
            PrintWriter pw = new PrintWriter(w);
            pw.println("package " + generatePackageName + ";");
            pw.println("\npublic class " + genarateClassName + " { ");
            pw.println(body);
            pw.println("    }");
            pw.flush();
        }
    }

    /**
     * 构建class内容
     * @param fieldsOfClass
     * @return
     */
    public String  generateClassBody(List<? extends Element> fieldsOfClass){
        StringBuilder body=new StringBuilder();
        for(Element element:fieldsOfClass){
            body.append(String.format("    public final static String %s=\"%s\";",element.getSimpleName(),element.getSimpleName()));
            body.append("\n\n");
        }
        return body.toString();
    }

    /**
     * 是否是打了RO注解的Entity
     * @param element
     * @return
     */
    private boolean isRoEntity(Element element) {
        return containsAnnotation(element, new String[]{"cn.wine.base.redis.annotation.Ro"});
    }

    /**
     * 是否有打了指定注解
     * @param element
     * @return
     */
    public static boolean containsAnnotation(Element element, String... annotations) {
        assert element != null;

        assert annotations != null;

        List<String> annotationClassNames = new ArrayList();
        Collections.addAll(annotationClassNames, annotations);
        List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
        Iterator var4 = annotationMirrors.iterator();

        AnnotationMirror mirror;
        do {
            if (!var4.hasNext()) {
                return false;
            }

            mirror = (AnnotationMirror)var4.next();
        } while(!annotationClassNames.contains(mirror.getAnnotationType().toString()));

        return true;
    }
}

2.在resource下新增META-INF/services并创建文件javax.annotation.processing.Processor 

将自定义的processor的全名称配置进去

#注:如果搭配jpa和mapstract或者lomack的processr冲突 通过以下类似配置解决
# <plugin>
 #                <groupId>org.apache.maven.plugins</groupId>
 #                <artifactId>maven-compiler-plugin</artifactId>
 #                <version>3.7.0</version>
 #                <configuration>
 #                    <source>${java.version}</source>
 #                    <target>${java.version}</target>
 #                    <annotationProcessorPaths>
 #                        <path>
 #                            <groupId>org.projectlombok</groupId>
 #                            <artifactId>lombok</artifactId>
 #                            <version>${lombok.version}</version>
 #                        </path>
 #                        <path>
 #                            <groupId>org.mapstruct</groupId>
 #                            <artifactId>mapstruct-processor</artifactId>
 #                            <version>1.2.0.Final</version>
 #                        </path>
 #                        <path>
 #                            <groupId>org.hibernate</groupId>
 #                            <artifactId>hibernate-jpamodelgen</artifactId>
 #                            <version>5.2.17.final</version>
 #                        </path>
 #                    </annotationProcessorPaths>
 #                </configuration>
 #            </plugin>
#
cn.wine.base.redis.gennerator.RedisRoProcessor

技术图片

 

 技术图片

 

 然后在其他使用的地方引入这个jar就行了

如何调试

1.新建一个remote

技术图片

 

 2.指定mvnDebugger

技术图片

 

javac AbstractProcessor

标签:doc   数据   dal   one   模板   abstract   substring   截取   ima   

原文地址:https://www.cnblogs.com/LQBlog/p/14208046.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!