最近一次开发的时候,我们一般都会和数据库打交道,同时我们自己也会创建一些		Entity
对象,比如		User
,它里面有一些属性	
@Entity(name = "t_user")
    @Getter
    @Setter
    @NoArgsConstructor  
    public class User {  
        private String email;  
        private Long age;  
    }
	
当我在做一些		CRUD
操作的时候,难免我会需要用到		User
里的		field
的名字,也就是字符串		"email"
和		"age"
,一般我们可能不会注意这种问题,可能直接就在需要用到的地方直接写上字符串		"email"
	
但其实这么写某种意义上算是一种硬编码了,毕竟若是这个		field
名字在代码中到处都有使用,可能我们要修改		field
名字时,就需要改很多地方	
于是我们可能顺其自然的,想到建立一个常量类,类似		UserConstants
,来存放User的属性的名字的静态常量	
public interface UserConstants {  
        String EMAIL = "email";  
        String AGE = "age";  
    }
	
这样我们貌似可以解决了,若是想要修改		field
名字,我们只用改		UserConstants
里的值即可	
不过正因为有这样的想法,假如我们有20个		Entity
,我们就要再写20个		Contants
类,真的太麻烦了,而且之前在		Entity
里写的属性名,就还要在		Contants
里再写一遍。。。真的太麻烦了	
于是我想,能不能当我创建了某个		Entity
,它就可以自动生成对应的		Contants
类呢	
别说,还真有,我发现了一个工具		hibernate-jpamodelgen
,这看名字也是		hibernate
出的,其实就是根据		JPA
标准的		@Entity
注解的类来自动生成了对应的元数据,有些叫元模型,		注意哈,这里不是运行时,而是编译的时候
,编译之后,就会生成新的类,下面是生成之后的类	
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")  
    @StaticMetamodel(User.class)  
    public abstract class User_ {  
        public static volatile SingularAttribute<User, String> name;  
        public static volatile SingularAttribute<User, Long> age;  
    }
	
而根据此类的给的		field
是		SingularAttribute
类型,通过该类你可以获取这个		field
的很多信息,不仅仅是我们之前想要的		field
的名字,	
		
			
		
	
看起来好像解决问题,但。。。。我用的不是关系型数据库啊,也就没用		JPA
,那更谈不上		hibernate
了,我用的		mongodb
,但是我也有类似		Entity
这样的数据结构,		mongodb
是		@Document
,类似这样	
@Document 
    @Getter
    @Setter
    @NoArgsConstructor  
    public class User {  
        private String name;  
        private Long age;  
    }
	
或者更往开的想,能不能做一个类似只要我标注的类,就可以自动生成它对应的类里的		field
的属性名常量类	
由于		hibernate-jpamodelgen
的实现思路跟我想要的效果一样,于是我去了解一下它的实现原理,就引申出		Pluggable Annotation Processing
	
		Pluggable Annotation Processing
其实是已经推出很久的		API
,从1.6开始的,不过知道的人不算特别多,但是很多人都是在用着该		API
提供的便利。		
该			API
只能是用于生成新文件,而不是用来更改现有文件		
	
			Pluggable Annotation Processing
,翻译过来可以叫可插拔(插件)化注解处理,是根据			[JSR 269]
来做出来的		
(			JSR
其实就是			Java Specification Requests
的缩写,意思是			Java
规范提案,如果把			Java
语言本身看成一个产品,那			JSR
就是产品经理提的需求,而产品经理其实就是			JCP
这个组织)		
如果简单理解编译过程是把源文件		.java
转换为		.class
文件的话,那		Pluggable Annotation Processing
就是允许你在这个过程中可以根据注解做一些额外的事,比如生成一些新的文件	
这个用面向接口编程的思想很好理解,就是定义一个接口在编译过程中调用,这样有多少实现类,就可以用多少定制的实现
			
		
了解了上面		Pluggable Annotation Processing
的功能,那我们就可以按照它的		API
来定制自己的实现了,由于		Pluggable Annotation Processing
是注解处理,因此,我们定制其实就是要关注两个点,这两个关注点输入给		Pluggable Annotation Processing API
,那应该就可以自动被执行了	
那按照之前我自己的需求,我希望有一个注解可以标注某个类,然后可以自动生成该类的		field
名字的常量类	
因此我们首先创建一个注解		@AutoConstants
	
@Retention(RetentionPolicy.SOURCE)  
    @Target(ElementType.TYPE)  
    public @interface AutoConstants {  
    }
	当然这样就解决了我们第一个要关注的点
接着我们做一个处理类		AutoConstantsProcessor
,来处理被		AutoConstants
标注的类,这里要介绍		Pluggable Annotation Processing
的关键类		AbstractProcessor
,这其实是一个抽象类,它的实现的接口		Processor
才是上层抽象,不过		AbstractProcessor
帮我们做了一些默认实现,让我们只关注处理的定制业务本身	
public class AutoConstantsProcessor extends AbstractProcessor {
        
        // 你要处理哪个注解
        @Override  
        public Set<String> getSupportedAnnotationTypes() {  
            return ImmutableSet.of(AutoConstants.class.getName());  
        }
        
        // 你处理支持的java版本
        @Override  
        public SourceVersion getSupportedSourceVersion() {  
            return SourceVersion.latestSupported();  
        }
        
        // 初始化参数
        @Override  
        public synchronized void init(ProcessingEnvironment processingEnv) {
        }
        
        // 关键方法,你怎么处理,这里面你可以做你想要做的
        @Override  
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        
        }
    }
	
当然你需要指定你是接口		Processor
的实现类,当然不是语法层面的告诉,而是直接告诉编译器,你是		Processor
的实现类,因此,这里要用到		ServiceLoader API
的方式,在		META-INF
下新建一个文件夹		services
,并在		services
下新建一个文件,以接口的全限定名为文件名,内容为实现类的全限定名	
		
			
		
	
		
			
		
	
补充一点,其实			ServiceLoader
这个大家平常也都很常用到,只是大家没有发觉而已,比如数据库驱动,			JDBC
标准里定义的驱动其实是一个接口			java.sql.Driver
,大家每次使用某个数据库,需要加一个驱动包,这个驱动包的也有个类似的配置(以			Mysql
为例)		
			
		
			
		
言归正传,这样的话,需要的工程直接简单依赖,然后加上		@AutoConstants
注解即可	
@Document  
    @Getter  
    @Setter  
    @NoArgsConstructor  
    @AutoConstants  
    public class User {  
        private String name;  
        private Long age;  
    }
	
编译后自动生成常量类		User_
		
		
			
		
	
中间实现过程不再描述拉,感兴趣的可以自己尝试一下,我生成代码用到了		JavaPoet
,多半需要熟悉哈		Pluggable Annotation Processing API
,当然其实大家熟知的		Lombok
也有用到		Pluggable Annotation Processing API
,不过我们知道		Lombok
其实是修改了原文件的,所以那里用到的		API
不在		Pluggable Annotation Processing
之内