java annotation+反射的应用记录

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

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

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


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

  自定义一个annotation

<span style="font-size:14px;">@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnotBpbAssertionClass {

    public String descr() default "";
}</span>

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

@AnnotBpbAssertionArg标注输入的参数,可以看到和上面页面上的匹配
@AnnotBpbAssertionClass(descr="检核1")
public class TestAssert1 implements AssertionClassHandler{

    @AnnotBpbAssertionArg
    private String arg1;
    @AnnotBpbAssertionArg
    private String arg2;
    @AnnotBpbAssertionArg
    private String arg3;
    public String getArg1() {
        return arg1;
    }
    public void setArg1(String arg1) {
        this.arg1 = arg1;
    }
    public String getArg2() {
        return arg2;
    }
    public void setArg2(String arg2) {
        this.arg2 = arg2;
    }
    public String getArg3() {
        return arg3;
    }
    public void setArg3(String arg3) {
        this.arg3 = arg3;
    }
    @Override
    public AssertionResult assertData() {
     
    }
 
    
}

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

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

private static Reflections getRef(String pkgName) {
        String sPkgName = pkgName == null ? PKG_NAME : pkgName;

        Set<URL> clzLoaderUrls = ClasspathHelper.forPackage(sPkgName);
        Set<URL> webInfoLibUrls = Collections.emptySet();
        Set<URL> scanUrls = new LinkedHashSet<URL>();

        try {
            ServletContext servletContext = WebContextInfo.getInstance().getParentServletContext();
            webInfoLibUrls = ClasspathHelper.forWebInfLib(servletContext);
            URL webInfoClassUrls = ClasspathHelper.forWebInfClasses(servletContext);
            if(webInfoClassUrls != null){
                scanUrls.add(webInfoClassUrls);
            }  
        } catch (Exception e) {
            LG.warn(ClassScanner.class.getSimpleName(),
                    "get webinf lib/class failed., err: {0}", e.getMessage());
        }

        scanUrls.addAll(webInfoLibUrls);
        scanUrls.addAll(clzLoaderUrls);

        ConfigurationBuilder cfgBuilder = new ConfigurationBuilder();
        cfgBuilder.filterInputsBy(new FilterBuilder.Include(FilterBuilder.prefix(sPkgName)));
        cfgBuilder.addScanners(
                new SubTypesScanner(), 
                new TypeAnnotationsScanner(), 
                new MethodAnnotationsScanner(), 
                new FieldAnnotationsScanner());
        cfgBuilder.setUrls(scanUrls);

        Reflections refs = new Reflections(cfgBuilder);
        return refs;
    }
获得所有标注annotation的class集合。
<span style="white-space:pre">	</span>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  就可以渲染此页面了。
BpbAssertionClassMeta 类
public class BpbAssertionClassMeta {

    public String className;
    
    public String desc;
    
    public List<ArgMeta> args;
    
    
    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }


    public String getClassName() {
        return className;
    }


    public void setClassName(String className) {
        this.className = className;
    }

    public List<ArgMeta> getArgs() {
        return args;
    }


    public void setArgs(List<ArgMeta> args) {
        this.args = args;
    }


    public class ArgMeta{
        private Field field;
        private String desc;
       
        public Field getField() {
            return field;
        }
        public void setField(Field field) {
            this.field = field;
        }
        public String getDesc() {
            return desc;
        }
        public void setDesc(String desc) {
            this.desc = desc;
        }
    }
}


检核的调用,获取之前保存的数据就省略掉了
 Class<? extends AssertionClassHandler> forName = (Class<? extends AssertionClassHandler>) Class
                .forName(assertionClassName); 
        AssertionClassHandler newInstance = forName.newInstance();//获取实例
        // 将保存的参数填入实例中
        if (metaArgs != null && CollectionUtils.isNotEmpty(args)) {
            for (ArgMeta argMeta : metaArgs) {
                for (ClassArg arg : args) {
                    if (arg.getKey().equals(argMeta.getDesc())) {
                        Field field = argMeta.getField();
                        field.setAccessible(true);
                        field.set(newInstance, arg.getValue());
                        break;
                    }
                }
            }
        }
       //调用检核方法
<span style="white-space:pre">	</span>assertData = newInstance.assertData();



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值