https://www.alexecollins.com/5-tips-for-using-lombok-in-production/
http://www.54tianzhisheng.cn/2018/01/09/lombok/
@EqualsAndHashCode(callSuper = true, of = {"id"})
https://groups.google.com/forum/#!topic/project-lombok/Xr13lPinsvg
The javadoc feature does not work in the eclipse javadoc view or hovers. You can generate the javadoc by running delombok on the code first and then run the javadoc compiler, as is hinted on the feature page near the bottom.
https://projectlombok.org/features/index.html
Creates
Creates
https://projectlombok.org/features/NonNull.html
public NonNullExample(@NonNull Person person) {
07 super("Hello");
08 if (person == null) {
09 throw new NullPointerException("person");
10 }
11 this.name = person.getName();
12 }
lombok.val
lombok.Value
lombok.Cleanup
lombok.Builder
How to Install:
.m2\repository\org\projectlombok\lombok\latest\lombok-latest.jar
https://www.credera.com/blog/technology-insights/java/project-lombok-learned-stop-worrying-love-autogeneration-annotations/
https://projectlombok.org/features/val.html
The
The
http://stackoverflow.com/questions/3418865/cannot-make-project-lombok-work-on-eclipse-helios/3425327#3425327
http://keaplogik.blogspot.com/2013/04/java-developers-need-to-be-using-lombok.html
06 @Cleanup InputStream in = new FileInputStream(args[0]);
07 @Cleanup OutputStream out = new FileOutputStream(args[1]);
To boldly throw checked exceptions where no one has thrown them before!
You can let lombok generate a getter which will calculate a value once, the first time this getter is called, and cache it from then on. This can be useful if calculating the value takes a lot of CPU, or the value takes a lot of memory. To use this feature, create a
04 @Getter(lazy=true) private final double[] cached = expensive();
05
06 private double[] expensive() {
07 double[] result = new double[1000000];
08 for (int i = 0; i < result.length; i++) {
09 result[i] = Math.asin(i);
10 }
11 return result;
12 }
Creates
Creates
Creates
Creates http://mvnrepository.com/artifact/org.projectlombok/lombok
https://github.com/rzwitserloot/lombok/issues/864
http://stackoverflow.com/questions/6853053/how-to-run-eclipse-clean-on-a-mac
eclipse/4.5m6/Eclipse.app/Contents/MacOS/eclipse -clean
Issues
http://stackoverflow.com/questions/3852091/is-it-safe-to-use-project-lombok
If set to
If set to
Without equals and hashCode, you can never...
put it in a HashSet
use it as a key in a HashMap, Cache, etc.
put it in any collection and have contains work
use assertEquals with it in tests.... etc.
Without toString, logging and debugging are painful.
Quite simply, if something feels like a value object, it's generally considered evil to not include all this stuff.
Suppose a required int field becomes optional. You change
int number;
to
Integer number;
Tests still pass... and everything's fine... until one day, objects put into Sets start mysteriously "disappearing" from the set! Why? (Left as an exercise to the reader.)
And there are also second-order costs:
Bugs caused by not bothering to do all that in your value types
Avoidance of even creating new types in the first plac
Imagine abstract base classes like Tuple2<A,B>, Tuple3<A,B,C>, etc.
The inserted code is invisible. This makes for a poor experience with tools, such as debuggers and code explorers.
The compiler hacks are non-standard and fragile.
In our view, your code is no longer really Java (Lombok is very "extralinguistic")
You write an abstract class
It has abstract accessors, but no fields
Annotate it with @AutoValue
Javac generates a concrete subclass for you
Callers only ever see the parent type
@AutoValue
public abstract class Foo {
public static Foo create(String text, int number) {
// defensive copies, preconditions
return new AutoValue_Foo(text, number);
}
/** Documentation here. */
public abstract String text(); // or getText(), if you like
/** Documentation here. */
public abstract int number();
}
User writes only plain old Java code
No runtime impact
no dependency (@AutoValue has source retention)
performs comparably to hand-written code
(1-morphic, so accessors are still inlinable)
Virtually no impact on API
Exception: if you already committed to a public constructor, you can't switch to this
No magical modifying of existing classes
Still just a single javac pass to compile!
AutoValue does introduce some fragility.
The generator has to choose the order of constructor parameters somehow, so it uses the order in which the accessors appear in the source file.
This means an innocent refactoring to reorder those accessors could break your tests. (You do have tests that actually do stuff with your value objects, right?)
https://projectlombok.org/features/experimental/Accessors.html
https://projectlombok.org/features/GetterSetter.html
If set to
If set to
Tip 1: No Lombok with logic
Tip 3: Use
@Data
for your DAOs
Where Lombok especially useful then? In DAOs. These objects typically don't have a lot of logic and a great deal of boilerplate. Specifically three annotations were the most useful.
@Data
creates your getters, setters, to string and equals/hash code. Great for DAOs in either the database layer, or in the API layer.
Tip 4: Use
@Value
for immutable value-objects@Value
is essentially an immutable version of @Data
. Very useful for immutable value-objects. Use in many of the cases you might use a Scala case class.
Tip 5: Use
@Builder
@Builder
is useful when you have an object with many fields with the same type. Rather than having a constructor with many string fields, use the builder instead.
Tip 6: Think about avoiding the other annotations
There are a number of annotations that we never found widely useful:
val
- A great idea, but hobbled by poor IDE support.@Cleanup
- Use try-with-resources.@SneakyThrows
- Throw only runtime exceptions, and perform exception mapping where needed.@Syncronized
- Just never found a place to use this.
Tip 7: Exclude generated classes from Sonar report
As the generated code typically ends up with many un-tested methods (e.g. you never test the generated
equals
as you don't need to, but they tend to end up being very complex for classes with many fields). These classes are excluded for static analysis and code coverage. If you are using Maven and Sonar, you can do this using the sonar.exclusions
property.
@Slf4j
注解在 类 上;为类提供一个 属性名为 log 的日志对象,提供默认构造方法
@AllArgsConstructor
注解在 类 上;为类提供一个全参的构造方法,加了这个注解后,类中不提供默认构造方法了。
@NoArgsConstructor
注解在 类 上;为类提供一个无参的构造方法。
@NonNull
注解在 属性 上,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常,也会有一个默认的无参构造方法。
@Cleanup
这个注解用在 变量 前面,可以保证此变量代表的资源会被自动关闭,默认是调用资源的 close() 方法,如果该资源有其它关闭方法,可使用 @Cleanup(“methodName”) 来指定要调用的方法,也会生成默认的构造方法
@RequiredArgsConstructor
这个注解用在 类 上,使用类中所有带有 @NonNull 注解的或者带有 final 修饰的成员变量生成对应的构造方法。
@Value
这个注解用在 类 上,会生成含所有参数的构造方法,get 方法,此外还提供了equals、hashCode、toString 方法。
@Synchronized
这个注解用在 类方法 或者 实例方法 上,效果和 synchronized 关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized 关键字的锁对象分别是类的 class 对象和 this 对象,而 @Synchronized 的锁对象分别是 私有静态 final 对象 lock 和 私有 final 对象 lock,当然,也可以自己指定锁对象,此外也提供默认的构造方法。
@EqualsAndHashCode(callSuper = true, of = {"id"})
https://groups.google.com/forum/#!topic/project-lombok/Xr13lPinsvg
@Data
class Address {
Municipality municipality;
}
class Address {
Municipality municipality;
}
@Data
@ToString(exclude = "addresses") // Without this we get
StackOverflowError
class Municipality {
Set<Address> addresses = new HashSet<Address>();
public void addAddress(Address a) {
addresses.add( a);
}
}
@ToString(exclude = "addresses") // Without this we get
StackOverflowError
class Municipality {
Set<Address> addresses = new HashSet<Address>();
public void addAddress(Address a) {
addresses.add(
}
}
public class JavaTest {
public static void main(String[] args) {
Address address = new Address();
Municipality municipality = new Municipality();
municipality. addAddress(address);
address. setMunicipality(municipality);
System.out. println(municipality);
System.out. println("Done.");
}
}
http://stackoverflow.com/questions/32273060/javadoc-not-generated-for-lombok-getter-and-setterAddress address = new Address();
Municipality municipality = new Municipality();
municipality.
address.
System.out.
System.out.
}
}
The javadoc feature does not work in the eclipse javadoc view or hovers. You can generate the javadoc by running delombok on the code first and then run the javadoc compiler, as is hinted on the feature page near the bottom.
https://projectlombok.org/features/index.html
@Log4j2
private static final org.apache.logging.log4j.Logger log =
org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(LogExample.class);
On javadoc, and other source-based tools
Use delombok first, then run javadoc or GWT on the delombok-ed code.public NonNullExample(@NonNull Person person) {
07 super("Hello");
08 if (person == null) {
09 throw new NullPointerException("person");
10 }
11 this.name = person.getName();
12 }
NEW in Lombok 0.11.10: You can use
@NonNull
on the parameter of a method or constructor to have lombok generate a null-check statement for you.lombok.val
lombok.Value
lombok.Cleanup
lombok.Builder
How to Install:
.m2\repository\org\projectlombok\lombok\latest\lombok-latest.jar
https://www.credera.com/blog/technology-insights/java/project-lombok-learned-stop-worrying-love-autogeneration-annotations/
@Log and its variants are a safe and easy way to add loggers without copying and pasting the same logging declaration line between every class. Using this approach can cut down on copy/paste errors, such as leaving the wrong class name in a copied logger declaration line.
Lombok has always treated any annotation named
@NonNull
on a field as a signal to generate a null-check if lombok generates an entire method or constructor for you, via for example @Data
. Now, however, using lombok's own @lombok.NonNull
on a parameter results in the insertion of just the null-check statement inside your own method or constructor.
The null-check looks like
if (param == null) throw new NullPointerException("param");
and will be inserted at the very top of your method. For constructors, the null-check will be inserted immediately following any explicit this()
or super()
calls.
07 val example = new ArrayList<String>();
07 final ArrayList<String> example = new ArrayList<String>();
Val can be especially useful when two imported packages have conflicting class names since it can prevent long package names from cluttering up method implementations. For example:
May be preferable to reading:
http://jnb.ociweb.com/jnb/jnbJan2010.htmlThe
@Data
annotation is likely the most frequently used annotation in the Project Lombok toolset. It combines the functionality of @ToString
, @EqualsAndHashCode
,@Getter
and @Setter
. Essentially, using @Data
on a class is the same as annotating the class with a default @ToString
and @EqualsAndHashCode
as well as annotating each field with both @Getter
and @Setter
. The
@Cleanup
annotation can be used to ensure that allocated resources are released. When a local variable is annotated with @Cleanup
, any subsequent code is wrapped in a try/finally
block that guarantees that the cleanup method is called at the end of the current scope. By default @Cleanup
assumes that the cleanup method is named "close", as with input and output streams@Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
Using the
synchronized
keyword on a method can result in unfortunate effects, as any developer who has worked on multi-threaded software can attest. The synchronized keyword will lock on the current object (this
) in the case of an instance method or on the class
object for a static method. This means that there is the potential for code outside of the control of the developer to lock on the same object, resulting in a deadlock. It is generally advisable to instead lock explicitly on a separate object that is dedicated solely to that purpose and not exposed in such a way as to allow unsolicited locking. Project Lombok provides the @Synchronized
annotation for that very purpose.
A look at the above code and the signature of
Lombok.sneakyThrow(Throwable)
would lead most to believe that the exception is being wrapped in a RuntimeException
and re-thrown, however this is not the case. The sneakyThrow
method will never return normally and will instead throw the provided throwable completely unaltered.
Project Lombok provides the
delombok
utility for replacing the Lombok annotations with equivalent source code. This can be done for an entire source directory via the command line.http://keaplogik.blogspot.com/2013/04/java-developers-need-to-be-using-lombok.html
- Never have to write getters and setters again.
public class Animal { @Getter @Setter private String name; @Getter @Setter private String gender; @Getter @Setter private String species; }https://projectlombok.org/features/
06 @Cleanup InputStream in = new FileInputStream(args[0]);
07 @Cleanup OutputStream out = new FileOutputStream(args[1]);
@Value
is the immutable variant of @Data
; all fields are made private
and final
by default, and setters are not generated. The class itself is also made final
by default, because immutability is not something that can be forced onto a subclass. Like @Data
, useful toString()
, equals()
and hashCode()
methods are also generated, each field gets a getter method, and a constructor that covers every argument (except final
fields that are initialized in the field declaration) is also generated.@Builder
lets you automatically produce the code required to have your class be instantiable with code such as:Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
By annotating one of the parameters (if annotating a method or constructor with
@Builder
) or fields (if annotating a class with @Builder
) with the @Singular
annotation, lombok will treat that builder node as a collection, and it generates 2 'adder' methods instead of a 'setter' method. One which adds a single element to the collection, and one which adds all elements of another collection to the collection. No setter to just set the collection (replacing whatever was already added) will be generated. A 'clear' method is also generated. These 'singular' builders are very complicated in order to guarantee the following properties:@SneakyThrows
@Synchronized
synchronized
done right: Don't expose your locks.You can let lombok generate a getter which will calculate a value once, the first time this getter is called, and cache it from then on. This can be useful if calculating the value takes a lot of CPU, or the value takes a lot of memory. To use this feature, create a
private final
variable, initialize it with the expression that's expensive to run, and annotate your field with @Getter(lazy=true)
. The field will be hidden from the rest of your code, and the expression will be evaluated no more than once, when the getter is first called. There are no magic marker values (i.e. even if the result of your expensive calculation is null
, the result is cached) and your expensive calculation need not be thread-safe, as lombok takes care of locking.04 @Getter(lazy=true) private final double[] cached = expensive();
05
06 private double[] expensive() {
07 double[] result = new double[1000000];
08 for (int i = 0; i < result.length; i++) {
09 result[i] = Math.asin(i);
10 }
11 return result;
12 }
@Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
https://github.com/rzwitserloot/lombok/issues/864
Never mind! It is my fault I renamed Eclipse.app, that is the reason it does not find my Mars installation
http://stackoverflow.com/questions/6853053/how-to-run-eclipse-clean-on-a-mac
If you CD to the eclipse installation directory using terminal, then you will see there is a directory called
eclipse.app
. CD to Eclipse.app\Contents\MacOS
under that directory there should be an executable called eclipse
.
I believe you can launch eclipse from the commandline by executing the
eclipse
executable with the -clean
argument, as below:./eclipse -clean
Issues
http://stackoverflow.com/questions/3852091/is-it-safe-to-use-project-lombok
UPDATE 3 Learning to use the various ways of doing things in Eclipse I guess. You can actually set a conditional breakpoint (BP) on a Lombok generated method. Using the
Outline
view, you can right-click the method to Toggle Method Breakpoint
. Then when you hit the BP, you can use the debugging Variables
view to see what the generated method named the parameters (usually the same as the field name) and finally, use the Breakpoints
view to right-click the BP and select Breakpoint Properties...
to add a condition. Nice.
UPDATE 7 This is a bit of an interesting update because it directly addresses the safety of adopting Lombok that the OP asked about.
As of v1.14, the
@Delegate
annotation has been demoted to an Experimental status. The details are documented on their site (Lombok Delegate Docs).
The thing is, if you were using this feature, your backout options are limited. I see the options as:
- Manually remove
@Delegate
annotations and generate/handcode the delegate code. This is a little harder if you were using attributes within the annotation. - Delombok the files that have the
@Delegate
annotation and maybe add back in the annotations that you do want. - Never update Lombok or maintain a fork.
- Delombok your entire project and stop using Lombok.
UPDATE 12 While trying to come up with justifications for why it's safe to bring in Lombok for the project I'm currently working on, I found a piece of gold that was added with
v1.14
- TheConfiguration System! This is means you can configure a project to dis-allow certain features that your team deems unsafe or undesirable. Better yet, it can also create directory specific config with different settings. This is AWESOME.
Usually, a user of lombok puts a
lombok.config
file with their preferences in a workspace or project root directory, with the special config.stopBubbling = true
key to tell lombok this is your root directory. You can then create lombok.config
files in any subdirectories (generally representing projects or source packages) with different settings.lombok.accessors.chain
true
, generated setters will 'chain' by default (They will return this
instead of having a void
return type).lombok.accessors.fluent
true
, generated setters and getters will simply be named the same as the field name, without a get
or set
prefix.lombok.log.fieldName
- The name of the generated log field (default:
log
). lombok.(featureName).flagUsage
- Allows you to forcibly stop or discourage use of a lombok feature. Legal values for this key are
warning
orerror
. Some examples of values for (featureName) are: "experimental
" (flags use of any of theexperimental features), "builder
", "sneakyThrows
", or "extensionMethod
".
To stop lombok from looking at parent directories for more configuration files, the special key:
can be included. We suggest you put this in the root of your workspace directory.
Lombok normally adds
Lombok can add the
config.stopBubbling = true
Lombok normally adds
@javax.annotation.Generated
annotations to all generated nodes where possible. You can stop this with:lombok.addGeneratedAnnotation = false
Lombok can add the
@SuppressFBWarnings
annotation which is useful if you want to run FindBugs on your class files. To enable this feature, make sure findbugs is on the classpath when you compile, and add the following config key:lombok.extern.findbugs.addSuppressFBWarnings = true
Alternatives
Maven also required the following snippet to be added to the
maven-compiler-plugin
’s <configuration>
section.<annotationProcessors>
<annotationProcessor>com.google.auto.value.processor.AutoValueProcessor</annotationProcessor>
</annotationProcessors>
There was also a weird issue I’m blaming on Eclipse. Even with the correct config files, when I imported the project, I needed to turn annotation processing off and on again to get it to work. Nasty.
put it in a HashSet
use it as a key in a HashMap, Cache, etc.
put it in any collection and have contains work
use assertEquals with it in tests.... etc.
Without toString, logging and debugging are painful.
Quite simply, if something feels like a value object, it's generally considered evil to not include all this stuff.
Suppose a required int field becomes optional. You change
int number;
to
Integer number;
Tests still pass... and everything's fine... until one day, objects put into Sets start mysteriously "disappearing" from the set! Why? (Left as an exercise to the reader.)
And there are also second-order costs:
Bugs caused by not bothering to do all that in your value types
Avoidance of even creating new types in the first plac
Imagine abstract base classes like Tuple2<A,B>, Tuple3<A,B,C>, etc.
The inserted code is invisible. This makes for a poor experience with tools, such as debuggers and code explorers.
The compiler hacks are non-standard and fragile.
In our view, your code is no longer really Java (Lombok is very "extralinguistic")
You write an abstract class
It has abstract accessors, but no fields
Annotate it with @AutoValue
Javac generates a concrete subclass for you
Callers only ever see the parent type
@AutoValue
public abstract class Foo {
public static Foo create(String text, int number) {
// defensive copies, preconditions
return new AutoValue_Foo(text, number);
}
/** Documentation here. */
public abstract String text(); // or getText(), if you like
/** Documentation here. */
public abstract int number();
}
User writes only plain old Java code
No runtime impact
no dependency (@AutoValue has source retention)
performs comparably to hand-written code
(1-morphic, so accessors are still inlinable)
Virtually no impact on API
Exception: if you already committed to a public constructor, you can't switch to this
No magical modifying of existing classes
Still just a single javac pass to compile!
AutoValue does introduce some fragility.
The generator has to choose the order of constructor parameters somehow, so it uses the order in which the accessors appear in the source file.
This means an innocent refactoring to reorder those accessors could break your tests. (You do have tests that actually do stuff with your value objects, right?)
@Accessors
therefore has 3 options:fluent
- A boolean. If true, the getter forpepper
is justpepper()
, and the setter ispepper(T newValue)
. Furthermore, unless specified,chain
defaults to true.
Default: false.chain
- A boolean. If true, generated setters returnthis
instead ofvoid
.
Default: false, unlessfluent=true
, then Default: true.prefix
- A list of strings. If present, fields must be prefixed with any of these prefixes. Each field name is compared to each prefix in the list in turn, and if a match is found, the prefix is stripped out to create the base name for the field. It is legal to include an empty string in the list, which will always match. For characters which are letters, the character following the prefix must not be a lowercase letter, i.e.pepper
is not a match even to prefixp
, butpEpper
would be (and would mean the base name of this field isepper
).
The
@Accessors
annotation is legal on types and fields; the annotation that applies is the one on the field if present, otherwise the one on the class. When a @Accessors
annotation on a field is present, any@Accessors
annotation also present on that field's type is ignored.lombok.accessors.chain
= [true
| false
] (default: false)true
, generated setters will return this
(instead of void
). An explicitly configured chain
parameter of an @Accessors
annotation takes precedence over this setting.lombok.accessors.fluent
= [true
| false
] (default: false)true
, generated getters and setters will not be prefixed with the bean-standard 'get
, is
or set
; instead, the methods will use the same name as the field (minus prefixes). An explicitly configured chain
parameter of an @Accessors
annotation takes precedence over this setting.
https://blog.mythsman.com/2017/12/19/1/
但是,我们发现这个包跟一般的包有很大区别,绝大多数java包都工作在运行时,比如spring提供的那种注解,通过在运行时用反射来实现业务逻辑。Lombok这个东西工作却在编译期,在运行时是无法通过反射获取到这个注解的。
但是,我们发现这个包跟一般的包有很大区别,绝大多数java包都工作在运行时,比如spring提供的那种注解,通过在运行时用反射来实现业务逻辑。Lombok这个东西工作却在编译期,在运行时是无法通过反射获取到这个注解的。
翻了翻现有的资料,再加上自己的一些猜想,Lombok的基本流程应该基本是这样:
- 定义编译期的注解
- 利用JSR269 api(Pluggable Annotation Processing API )创建编译期的注解处理器
- 利用tools.jar的javac api处理AST(抽象语法树)
- 将功能注册进jar包
<dependency><groupId>com.sun</groupId><artifactId>tools</artifactId><version>1.8</version><scope>system</scope><systemPath>${java.home}/../lib/tools.jar</systemPath></dependency>
|
创建Getter注解
这里的Target我选择了ElementType.TYPE表示是对类的注解,Retention选择了RententionPolicy.SOURCE,表示这个注解只在编译期起作用,在运行时将不存在。这个比较简单,稍微复杂点的是对这个注解的处理机制。像spring那种注解是通过反射来获得注解对应的元素并实现业务逻辑,但是我们显然不希望在使用Lombok这种功能的时候还要编写其他的调用代码,况且用反射也获取不到编译期才存在的注解。
幸运的是Java早已支持了JSR269的规范,允许在编译时指定一个processor类来对编译阶段的注解进行干预
幸运的是Java早已支持了JSR269的规范,允许在编译时指定一个processor类来对编译阶段的注解进行干预
|
需要定义两个注解,一个表示该处理器需要处理的注解,另外一个表示该处理器支持的源码版本。然后需要着重实现两个方法,init跟process。init的主要用途是通过ProcessingEnvironment来获取编译阶段的一些环境信息;process主要是实现具体逻辑的地方,也就是对AST进行处理的地方
那么如何在调用的时候不用加参数呢,其实我们知道java在编译的时候会去资源文件夹下读一个META-INF文件夹,这个文件夹下面除了MANIFEST.MF文件之外,还可以添加一个services文件夹,我们可以在这个文件夹下创建一个文件,文件名是javax.annotation.processing.Processor,文件内容是com.mythsman.test.GetterProcessor。
我们知道maven在编译前会先拷贝资源文件夹,然后当他在编译时候发现了资源文件夹下的META-INF/serivces文件夹时,他就会读取里面的文件,并将文件名所代表的接口用文件内容表示的类来实现。这就相当于做了-processor参数该做的事了。
当然这个文件我们并不希望调用者去写,而是希望在processor项目里集成,调用的时候能直接继承META-INF。
我们知道maven在编译前会先拷贝资源文件夹,然后当他在编译时候发现了资源文件夹下的META-INF/serivces文件夹时,他就会读取里面的文件,并将文件名所代表的接口用文件内容表示的类来实现。这就相当于做了-processor参数该做的事了。
当然这个文件我们并不希望调用者去写,而是希望在processor项目里集成,调用的时候能直接继承META-INF。