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 就可以渲染此页面了。

浙公网安备 33010602011771号