通用的注解解析器,当前只分析了Field上的注解,其他地方的注解解析原理相同。
直接上代码
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
/**
* Created by zl on 14/12/8.
*/
public class KitAnnotation {
private static Map<String,List<Method>> annotationMethods=new HashMap<>();
private static Map<String,Class<? extends Annotation>> classedLoaders=new HashMap<>();
public static void addAnnotation(Class<? extends Annotation> cls){
if(!annotationMethods.containsKey(cls.getName())){
List<Method> list=new ArrayList<>();
list.addAll(Arrays.asList(cls.getDeclaredMethods()));
annotationMethods.put(cls.getName(),list);
}
}
private static Map<Class,AnnotationProcessor> annotationCache =new HashMap<>();
private static <T> AnnotationProcessor<T> getCache(T t){
Class<T> cls= (Class<T>) t.getClass();
AnnotationProcessor<T> cache= annotationCache.get(cls);
if(cache == null){
cache=new AnnotationProcessor(cls);
annotationCache.put(cls, cache);
}
return cache;
}
public static <T> void process(T t){
getCache(t).setValue(t);
}
static class AnnotationProcessor<T> {
private Map<String,List<Field>> fieldAnnotations=new HashMap<>();
public AnnotationProcessor(Class<T> cls){
analysis(cls);
}
public void analysis(Class<T> cls){
Field[] declaredFields = cls.getDeclaredFields();
Annotation[] ans;
String k;
for (Field field:declaredFields){
field.setAccessible(true);
ans=field.getDeclaredAnnotations();
if(ans != null){
for (Annotation a:ans){
k=a.annotationType().getName();
List<Field> fields = fieldAnnotations.get(k);
if(fields == null){
fields=new ArrayList<>();
fieldAnnotations.put(k,fields);
}
fields.add(field);
}
}
}
}
public void setValue(T t){
Set<Map.Entry<String, List<Field>>> entries = fieldAnnotations.entrySet();
Class<? extends Annotation> cls;
for(Map.Entry<String, List<Field>> entry:entries){
try {
List<Method> list = annotationMethods.get(entry.getKey());
if(list != null && !list.isEmpty()) {
cls=classedLoaders.get(entry.getKey());
if(cls == null){
cls= (Class<? extends Annotation>) Class.forName(entry.getKey());
classedLoaders.put(entry.getKey(),cls);
}
for (Method method : list) {
for (Field field : entry.getValue()) {
field.set(t, method.invoke(field.getAnnotation(cls)));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
用法
//先加入分析
KitAnnotation.addAnnotation(CustomerAnnotation.class); //自定义的注解类
//然后就可以解析属性上的注解了
KitAnnotation.process(new UserBean());
这个类只是简单的实现了用注解设置属性上的值,其他的特性未实现!
对比常规的实现(不要喷我,这个是最基本的实现方法)
public static void parseAnnotation(UserBean userBean){
//性能瓶颈在下面这一行,非常耗时!!定义在方法外面的话就和上面写的一样了~~
Field[] declaredFields = UserBean.class.getDeclaredFields();
for (Field field:declaredFields){
try {
field.setAccessible(true);
DefBeanId anId = field.getAnnotation(DefBeanId.class);
if(anId != null){
field.set(userBean,anId.id()); //anId.id()是自定义注解的方法
}
DefColum anColum = field.getAnnotation(DefColum.class);
if(anColum != null){
field.set(userBean,anColum.name());
}
}catch (Exception e){
}
}
}
public static void main(String[] args){
UserBean userBean=new UserBean();
int count=100000;
long s=System.currentTimeMillis();
for( int i=0;i<count;i++){
KitAnnotation.parseAnnotation(userBean);
}
System.out.println(System.currentTimeMillis()-s);
System.out.println("---------");
s=System.currentTimeMillis();
KitAnnotation.addAnnotation(DefBeanId.class);
KitAnnotation.addAnnotation(DefColum.class);
for( int i=0;i<count;i++){
KitAnnotation.process(userBean);
}
System.out.println(System.currentTimeMillis()-s);
}
输出结果
4458
---------
125
在十万次测试中速度比上面的常规方法快30倍左右,当然我这样测试的不是很准,但至少性能上应该会用一些提升吧。
这个类只是为了方便的解析属性上的注解,把如上面常规实现改一下,就没什么性能优势了,但好处在于不用把代码写死,
简化了一些相同的代码。