Java注解(二):注解处理器

来源:互联网 发布:温度测试仪软件 编辑:程序博客网 时间:2024/06/05 17:14

前言

在上篇博客中曾经提到过,注解实际上只是一个元数据,一个躯壳!只有通过注解处理器才能为你的注解赋予灵魂!没有注解处理器的注解和普通注释并没有什么区别! 在上篇博客中,我们已经学会了如何制造躯壳,那么在本篇中,我们将学习如何为注解赋予灵魂–注解处理器。

目标

本篇博客我们将会介绍如何写注解处理器,并且完成一个小例子(将在配置类中@Config通过@Alias注册了别名的类,将使用一个Map< String , Class< ? >>存放别名与注册类的关系。)

注解处理器

在写注解处理前,首先我们需要一些预备知识。

AnnotatedElement接口

为了使程序员能够通过反射对注解进行一系列操作,JDK定义了AnnotatedElement这个接口,其中反射机制的主要成员类Class、Method、Field、Package、Constructor、Parameter等都实现了该接口,现在先介绍一些该接口的方法的作用。

/**  *判断是否含有指定注解  *@param annotationClass 需判断的注解类型  *@since JDK1.5  **/boolean isAnnotationPresent(Class< ? extends Annotation> annotationClass);/**  *获取指定注解的实例  *@param annotationClass 指定注解类型  *@since JDK1.5  **/<T extends Annotation> T getAnnotation(Class<T> annotationClass);/**  *获取所有注解实例,返回实例数组  *@since JDK1.5  **/Annotation[] getAnnotations();/**   *获取所有非继承的注解(即不包括使用了@Inherited的注解,通过父类继承而来的),返回实例数组   *@since JDK1.5   **/Annotation[] getDeclaredAnnotations();/**  *从非继承的注解中获取指定注解实例  *@param annotationClass 指定注解类型  *@since JDK1.8  */< T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)/**  *返回指定重复注解的实例集合  *@param annotationClass 指定注解类型  *@since JDK1.8  */< T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)/**  *返回非继承的 指定重复注解的实例集合  *@param annotationClass 指定注解类型  *@since JDK1.8  **/< T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)

实战

目标:接下来我们将要实现,用@config标志一个配置类,在配置类中通过方法返回值来表示你要注册进容器的类的类型。通过@Alias表示是需要注册的类及对应的别名。如果@Alias没有设置值,则使用方法名作为别名存储。最终返回一个map容器。里面存储的是类别名与类的关系。

首先创建两个注解,一个代表配置类的标记型注解@config,一个用于注册别名的@Alias(name=”“)。

/** * 配置类标注注解 */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Config {}/** *别名注册 注解  */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Alias {    String value() default "";}

对应注解的处理器

/** * @Config注解处理器 */public class ConfigHandler {    /**     * 判断参数类型是否包含config注解     * @param 参数类型     */    public static boolean hasAnnotation(Class<?> classz){        if(null == classz)             return false;        if(classz.isAnnotationPresent(Config.class)){            return true;        }        return false;    }}public class AliasHandler {    private static Map<String,Class> map ;    static{        map = new HashMap<>();    }    /**     * 判断参数类型是否包含Alias注解     * @param 参数类型     * @return     */    public static boolean hasAnnotation(Method method){        if(null == method)             return false;        if(method.isAnnotationPresent(Alias.class)){            return true;        }        return false;    }    public static Map<String,Class> handler(List<Method> methods){        methods.forEach(AliasHandler::handler);        return map;    }    /**     * 将每个方法解析并放进map中     * @param method     */    public static void handler(Method method){        if(method == null)            return ;         Alias alias = method.getAnnotation(Alias.class);        Class<?> returnType = method.getReturnType();        //如果Alias没有设置别名书名,则使用方法名作为别名        if(alias.value() == null || "".equals(alias.value()))            map.put(method.getName(),returnType);        else            map.put(alias.value(),returnType);    }}

最后的主方法运行:

@Configpublic class DemoConfig {    @Alias    Demo1 demo1(){        return new Demo1();    }    @Alias("aliasDemo")    Demo2 demo2(){        return new Demo2();    }    public static void main(String[] args) {        Class<DemoConfig> classz = DemoConfig.class;        if(ConfigHandler.hasAnnotation(classz)){            List<Method> methods = CollectionUtils.toList(classz.getDeclaredMethods());            //过滤掉不包含@Alias注解的方法            methods.removeIf(method ->!AliasHandler.hasAnnotation(method));            Map<String,Class> map = AliasHandler.handler(methods);            map.forEach((a,b)->{System.out.println(a+":"+b);});        }else            throw new RuntimeException("不是配置类");    }}

最终打印结果:

aliasDemo:class two.demo.Demo2demo1:class two.demo.Demo1
原创粉丝点击