java annotation+反射的应用记录

使用java 的annotation和反射的小例子,记录下来以供参考,

实现的功能是 配置页面可以动态选择一个实现检核接口的类,保存输入的参数,在真正检核时传入保存的参数

配置页面如下:第一行选择了检核1 有三个参数需要输入,第二行可以看到下拉选单,内容是根据annotation标注的class生成的

 

下拉选单是根据annotation标注的class生成的,目前是有3个测试class,选择了以后可以填入需要的参数进行保存,参数也是定义在class中,目前先讲一讲这部分配置的实现。

  自定义一个annotation

1 @Retention(RetentionPolicy.RUNTIME)
2 @Target(ElementType.TYPE)
3 public @interface AnnotBpbAssertionClass {
4 
5     public String descr() default "";
6 }

其中一个检核class,实现的接口是为了实作assertData方法,检核调用的真正方法,

@AnnotBpbAssertionArg标注输入的参数,可以看到和上面页面上的匹配
 1 @AnnotBpbAssertionClass(descr="检核1")
 2 public class TestAssert1 implements AssertionClassHandler{
 3 
 4     @AnnotBpbAssertionArg
 5     private String arg1;
 6     @AnnotBpbAssertionArg
 7     private String arg2;
 8     @AnnotBpbAssertionArg
 9     private String arg3;
10     public String getArg1() {
11         return arg1;
12     }
13     public void setArg1(String arg1) {
14         this.arg1 = arg1;
15     }
16     public String getArg2() {
17         return arg2;
18     }
19     public void setArg2(String arg2) {
20         this.arg2 = arg2;
21     }
22     public String getArg3() {
23         return arg3;
24     }
25     public void setArg3(String arg3) {
26         this.arg3 = arg3;
27     }
28     @Override
29     public AssertionResult assertData() {
30      
31     }
32  
33     
34 }

 

  为了效率比较高,标注有annotation的class是在spring加载bean的时候写入内存的,service需要实现InitializingBean,初始化方法中用到了类扫描

首先获得Reflections,PKG_NAME 为扫描其实包路径,如果觉得没有用也可以在调用时抓取一次

 

 1  private static Reflections getRef(String pkgName) {
 2         String sPkgName = pkgName == null ? PKG_NAME : pkgName;
 3 
 4         Set<URL> clzLoaderUrls = ClasspathHelper.forPackage(sPkgName);
 5         Set<URL> webInfoLibUrls = Collections.emptySet();
 6         Set<URL> scanUrls = new LinkedHashSet<URL>();
 7 
 8         try {
 9             ServletContext servletContext = WebContextInfo.getInstance().getParentServletContext();
10             webInfoLibUrls = ClasspathHelper.forWebInfLib(servletContext);
11             URL webInfoClassUrls = ClasspathHelper.forWebInfClasses(servletContext);
12             if(webInfoClassUrls != null){
13                 scanUrls.add(webInfoClassUrls);
14             }  
15         } catch (Exception e) {
16             LG.warn(ClassScanner.class.getSimpleName(),
17                     "get webinf lib/class failed., err: {0}", e.getMessage());
18         }
19 
20         scanUrls.addAll(webInfoLibUrls);
21         scanUrls.addAll(clzLoaderUrls);
22 
23         ConfigurationBuilder cfgBuilder = new ConfigurationBuilder();
24         cfgBuilder.filterInputsBy(new FilterBuilder.Include(FilterBuilder.prefix(sPkgName)));
25         cfgBuilder.addScanners(
26                 new SubTypesScanner(), 
27                 new TypeAnnotationsScanner(), 
28                 new MethodAnnotationsScanner(), 
29                 new FieldAnnotationsScanner());
30         cfgBuilder.setUrls(scanUrls);
31 
32         Reflections refs = new Reflections(cfgBuilder);
33         return refs;
34     }

获得所有标注annotation的class集合。

        Reflections ref = getRef();
        Set<Class<?>> ret = ref.getTypesAnnotatedWith(annotation);   

将class和annotation的信息封装在 BpbAssertionClassMeta 这个类中,可以看到class和annotation的一些方法。

 

      if (CollectionUtils.isNotEmpty(clazzSet)) {
                for (Class<?> clazz : clazzSet) {
                    BpbAssertionClassMeta meta = new BpbAssertionClassMeta();
                    List<ArgMeta> argMetas = new ArrayList<BpbAssertionClassMeta.ArgMeta>();
                    meta.setArgs(argMetas);
                    meta.setClassName(clazz.getCanonicalName());
                    AnnotBpbAssertionClass annotation = clazz.getAnnotation(AnnotBpbAssertionClass.class);//获取annotation
                    meta.setDesc(annotation.descr());
                    metas.add(meta);
                    Field[] declaredFields = clazz.getDeclaredFields();//获取类的所有字段
                    if (declaredFields != null) {
                        for (Field field : declaredFields) {
                            if (field.isAnnotationPresent(AnnotBpbAssertionArg.class)) {//是否标注的此annotation
                                if (String.class.isAssignableFrom(field.getType()) == false) {//是否string类型
                                    throw new IllegalArgumentException(
                                            String.format(
                                                    "unsupported type!, expected %s but %s found. @field: %s, @class: %s",
                                                    String.class.getSimpleName(), field.getType()
                                                            .getSimpleName(), field.getName(), clazz
                                                            .getName()));
                                }
                                ArgMeta argMeta = meta.new ArgMeta();
                                argMeta.setField(field);
                                argMeta.setDesc(field.getName());
                                argMetas.add(argMeta);
                            }
                        }
                    }
                }
            }

页面循环BpbAssertionClassMeta  就可以渲染此页面了。

 

posted @ 2015-07-21 15:03  口渴的鱼  阅读(984)  评论(0)    收藏  举报