• Lombok简介及入门使用 (转载)


    Lombok简介及入门使用

          lombok既是一个IDE插件,也是一个项目要依赖的jar包.

           Intellij idea开发的话需要安装Lombok plugin,同时设置 Setting -> Compiler -> Annotation Processors -> Enable annotation processing勾选。

          lombok是依赖jar包的原因是因为编译时要用它的注解.是插件的原因是他要在编译器编译时通过操作AST(抽象语法树)改变字节码生成.也就是说他可以改变java语法. 他不像spring的依赖注入或者hibernate的orm一样是运行时的特性,而是编译时的特性.

    Lombok 是一种 Java实用工具,可用来帮助开发人员消除Java的冗长,尤其是对于简单的Java对象(POJO), 它通过注释实现这一目的。一个标准的Java bean 一般具有若干属性,每个属性具有getter()和setter()方法,Lombok中也用到了注解,但是它并没有用到反射,而是通过一些奇技淫巧,在代码编译时期动态将注解替换为具体的代码。所以JVM实际运行的代码,和我们手动编写的包含了各种工具方法的类相同。

    添加maven依赖

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.16</version>
    </dependency>

    Lombok注解

    • val: final 像动态语言一样,声明一个fianl的变量。
    • var: 同JDK10
    • @Data:注解在类上,将类提供的所有属性都添加get、set方法,并添加、equals、canEquals、hashCode、toString方法
    • @Setter:注解在类上,为所有属性添加set方法、注解在属性上为该属性提供set方法
    • @Getter:注解在类上,为所有的属性添加get方法、注解在属性上为该属性提供get方法
    • @NotNull:在参数中使用时,如果调用时传了null值,就会抛出空指针异常
    • @Synchronized 用于方法,可以锁定指定的对象,如果不指定,则默认创建一个对象锁定
    • @Log作用于类,创建一个log属性
    • @Builder:使用builder模式创建对象
    • @NoArgsConstructor:创建一个无参构造函数
    • @AllArgsConstructor:创建一个全参构造函数
    • @ToString:创建一个toString方法
    • @Accessors(chain = true)使用链式设置属性,set方法返回的是this对象。
    • @RequiredArgsConstructor:创建对象, 例: 在class上添加@RequiredArgsConstructor(staticName = "of")会创建生成一个静态方法
    • @UtilityClass:工具类
    • @ExtensionMethod:设置父类
    • @FieldDefaults:设置属性的使用范围,如private、public等,也可以设置属性是否被final修饰。
    • @Cleanup: 关闭流、连接点。
    • @EqualsAndHashCode:重写equals和hashcode方法。
    • @toString:创建toString方法。
    • @Cleanup: 用于流等可以不需要关闭使用流对象.

    一些使用的例子

    普通的bean:

    public class User {
            private String id;
            private String name;
            private Integer age;
        
            public String getId() {
                return id;
            }
        
            public void setId(String id) {
                this.id = id;
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public Integer getAge() {
                return age;
            }
        
            public void setAge(Integer age) {
                this.age = age;
            }
        }

    使用 lambok

    使用lombok,代码可以变得非常的简洁,看着也舒服。

    @Setter
    @Getter
    public class User {
        private String id;
        private String name;
        private Integer age;
    }
    
    public static void main(String[] args) {
        User user = new User();
        user.setId("1");
        user.setName("name");
        user.setAge(1);
    }
    @Accessors(chain = true):使用链式创建:
    @Setter
    @Getter
    @Accessors(chain = true)
    public class User {
        private String id;
        private String name;
        private Integer age;
    }
    
    public static void main(String[] args) {
        //使用@Accessors(chain = true)
        User userChain = new User();
        userChain.setId("1").setName("chain").setAge(1);
    }

    @Builder:使用builder模式创建对象

    @Setter
    @Getter
    @Builder
    public class User {
        private String id;
        private String name;
        private Integer age;
    }
    
    public static void main(String[] args) {
        User user = User.builder().id("1").name("builder").age(1).build();
        System.out.println(user.getId());
    }

    @UtilityClass:工具类注解

    @UtilityClass
    public class Utility {
    
        public String getName() {
            return "name";
        }
    }
    
    public static void main(String[] args) {
        // Utility utility = new Utility(); 构造函数为私有的,
        System.out.println(Utility.getName());
    
    }

    @CleanUp: 清理流对象

    @Cleanup
    OutputStream outStream = new FileOutputStream(new File("text.txt"));
    @Cleanup
    InputStream inStream = new FileInputStream(new File("text2.txt"));
    byte[] b = new byte[65536];
    while (true) {
       int r = inStream.read(b);
       if (r == -1) break;
       outStream.write(b, 0, r); 
    }

    Lombok注解原理

    说道 Lombok,我们就得去提到 JSR 269: Pluggable Annotation Processing API (www.jcp.org/en/jsr/deta…) 。JSR 269 之前我们也有注解这样的神器,可是我们比如想要做什么必须使用反射,反射的方法局限性较大。首先,它必须定义@Retention为RetentionPolicy.RUNTIME,只能在运行时通过反射来获取注解值,使得运行时代码效率降低。其次,如果想在编译阶段利用注解来进行一些检查,对用户的某些不合理代码给出错误报告,反射的使用方法就无能为力了。而 JSR 269 之后我们可以在 Javac的编译期利用注解做这些事情。所以我们发现核心的区分是在 运行期 还是 编译期

    从上图可知,Annotation Processing 是在解析和生成之间的一个步骤。具体详细步骤如下:

    上图是 Lombok 处理流程,在Javac 解析成抽象语法树之后(AST), Lombok 根据自己的注解处理器,动态的修改 AST,增加新的节点(所谓代码),最终通过分析和生成字节码

    自从Java 6起,javac就支持“JSR 269 Pluggable Annotation Processing API”规范,只要程序实现了该API,就能在javac运行的时候得到调用

    1. 常用的项目管理工具Maven所使用的java编译工具来源于配置的第三方工具,如果我们配置这个第三方工具为Oracle javac的话,那么Maven也就直接支持lombok了;
    2. Intellij Idea配置的编译工具为Oracle javac的话,也就直接支持lombok了;

    IDE工具问题解决:

    现在有一个A类,其中有一些字段,没有创建它们的setter和getter方法,使用了lombok的@Data注解,另外有一个B类,它调用了A类实例的相应字段的setter和getter方法

    编译A类和B类所在的项目,并不会报错,因为最终生成的A类字节码文件中存在相应字段的setter和getter方法

    但是,IDE发现B类源代码中所使用的A类实例的setter和getter方法在A类源代码中找不到定义,IDE会认为这是错误

    要解决以上这个不是真正错误的错误,可以下载安装Intellij Idea中的"Lombok plugin"。

     自定义支持JSR269的注解

    一般javac的编译过程,java文件首先通过进行解析构建出一个AST,然后执行注解处理,最后经过分析优化生成二进制的.class文件。我们能做到的是,在注解处理阶段进行一些相应处理。首先我们在META-INF.services下创建如下文件:

    文件中指定我们的注解处理器:com.alipay.kris.other.lombok.MyAnnotaionProcessor,然后我们接可以编写自己的注解处理器,一个简单的实例代码如下:

    @SupportedSourceVersion(SourceVersion.RELEASE_8)
    @SupportedAnnotationTypes("com.alipay.kris.other.lombok.*")
    public class MyAnnotaionProcessor extends AbstractProcessor {
        public MyAnnotaionProcessor() {
            super();
        }
        @Override
        public boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv) {
            for (Element elem : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
                MyAnnotation annotation = elem.getAnnotation(MyAnnotation.class);
                String message = "annotation found in " + elem.getSimpleName()
                    + " with  " + annotation.value();
                addToString(elem);
                processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
            }
            return true; // no further processing of this annotation type
        }
    }

    链接:https://juejin.im/post/5a6eceb8f265da3e467555fe

    链接:https://www.jianshu.com/p/2ea9ff98f7d6

  • 相关阅读:
    转:什么是即时编译(JIT)!?OpenJDK HotSpot VM剖析
    用好spring mvc validator可以简化代码
    接口服务中的日志
    rest api参数与content-type
    【单页应用】全局控制器app应该干些什么?
    【webapp的优化整理】要做移动前端优化的朋友进来看看吧
    【单页应用】理解MVC
    【单页应用】view与model相关梳理
    【单页应用之通信机制】view之间应该如何通信
    【单页应用巨坑之History】细数History带给单页应用的噩梦
  • 原文地址:https://www.cnblogs.com/guanbin-529/p/10927288.html
Copyright © 2020-2023  润新知