注解解析器 ---- Element

Element

Element在中文的API文档中的解释为

javax.lang.model.element 表示一个程序元素,比如包、类或者方法。每个元素都表示一个静态的语言级构造(不表示虚拟机的运行时构造)。

简单的讲我们可以将一个类看成类似HTML文档样,一个类是最外层的根节点,类变量和实例变量是根节点下的一个子节点,方法是另一个根节点,而方法中的变量又可以看成这个方法的子节点,依次类推下去。通过面向对象的方法我们将这个节点抽象出一个Element类,这个类就提取出变量节点或者方法节点的一些相同的属性,Element就作为一个顶级的父类。

基于上面的思想我们可以看一看Element的继承关系
- TypeElement
我们可以简单的将Type类比为Class ,因此我们可以将TypeElement看做成类节点,这个类型的Element中包含该类节点的一些必要的信息,比如类的全限定名,该类的父类等信息。通过该类的一些方法我们也可以推断出TypeElement所代表的含义。
| 方法摘要 |
| List<? extends TypeMirror> | **getInterfaces**()
返回直接由此类实现或直接由此接口扩展的接口类型。 |
| NestingKind | **getNestingKind**()
返回此类型元素的嵌套种类 (nesting kind)。 |
| Name | **getQualifiedName**()
返回此类型元素的完全限定名称。 |
| TypeMirror | **getSuperclass**()
返回此类型元素的直接超类。 |
| List<? extends TypeParameterElement> | **getTypeParameters**()
按照声明顺序返回此类型元素的形式类型参数。 |
- VariableElement
VariableElement 在API中的解释为表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数。我们可以简单的将VariableElement对应于一个Field。VariableElement提供的方法有
| Object | **getConstantValue**()
如果此变量是一个被初始化为编译时常量的 static final 字段,则返回此变量的值。 |
- ExecutableElement
可执行的Element 对应于一个可以执行的方法,对应于API文档中的解释是表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。他提供的方法有
| AnnotationValue | **getDefaultValue**()
如果此 executable 是一个注释类型元素,则返回默认值。 |
| List<? extends VariableElement> | **getParameters**()
返回此 executable 的形参。 |
| TypeMirror | **getReturnType**()
返回此 executable 的返回类型。 |
| List<? extends TypeMirror> | **getThrownTypes**()
按声明顺序返回此方法或构造方法的 throws 子句中所列出的异常和其他 throwable。 |
| List<? extends TypeParameterElement> | **getTypeParameters**()
按照声明顺序返回此 executable 的形式类型参数。 |
| boolean | **isVarArgs**()
如果此方法或构造方法接受可变数量的参数,则返回 true,否则返回 false。 |

public class NameCheckProcesser extends AbstractProcessor {

    private Filer filerUtils; // 文件写入
    private Elements elementUtils; // 操作Element 的工具类
    private Messager messagerUtils; // Log 日志

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filerUtils = processingEnv.getFiler();
        elementUtils = processingEnv.getElementUtils();
        messagerUtils = processingEnv.getMessager();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        // messagerUtils.printMessage(Kind.WARNING, "processor start-------");
        // roundEnv.getRootElements() 貌似只会返回有该注解的类
        // Set<? extends Element> rootElements = roundEnv.getRootElements();
        // 返回有 NameCheck 注解的Element
        Set<? extends Element> elementsAnnotatedWith = roundEnv
                .getElementsAnnotatedWith(NameCheck.class);
        for (Element element : elementsAnnotatedWith) {
            messagerUtils.printMessage(Kind.WARNING, "processor start-------"
                    + element.getSimpleName());
         //  element.getKind() 返回该Element的类型,常见的有
             //    1. ElementKind.CLASS 一个类
             //    2.ElementKind.FIELD 一个字段
             //    3.  ElementKind.METHOD 一个方法
            if (element.getKind() == ElementKind.CLASS) {
                // class 类型
                messagerUtils.printMessage(Kind.WARNING, " class 类型 same : "
                        + ((TypeElement) (element)).getSimpleName()
                        + " / qname:"
                        + ((TypeElement) (element)).getQualifiedName()
                                .toString());
                List<? extends Element> enclosedElements = element
                        .getEnclosedElements();
                for (Element element2 : enclosedElements) {
                    messagerUtils.printMessage(Kind.WARNING, "class 分装的类型:"
                            + element2.getSimpleName());
                }

            } else if (element.getKind() == ElementKind.FIELD) {
                // 字段类型
                messagerUtils.printMessage(Kind.WARNING, "字段类型-------"
                        + element.getSimpleName());
                // 封装我的类型
                TypeElement enclosingElement = (TypeElement) element
                        .getEnclosingElement();
                messagerUtils.printMessage(Kind.WARNING,
                        "getEnclosingElement :"
                                + enclosingElement.getQualifiedName()
                                        .toString());

            } else if (element.getKind() == ElementKind.METHOD) {
                // 方法类型
                messagerUtils.printMessage(Kind.WARNING, " 方法类型 same : "
                        + ((ExecutableElement) (element)).getSimpleName());
                ExecutableElement element2 = (ExecutableElement) element;

                // 如果是方法则得到方法的参数,方法的返回值
                List<? extends VariableElement> parameters = element2
                        .getParameters();
                List<? extends TypeParameterElement> typeParameters = element2
                        .getTypeParameters();
                /*
                 * messagerUtils.printMessage( Kind.WARNING, "size:" +
                 * parameters.size() + ":" + typeParameters.size());
                 */
                for (int i = 0; i < parameters.size(); i++) {
                    messagerUtils.printMessage(Kind.WARNING, "方法的参数名称是 : "
                            + parameters.get(i).getSimpleName() + "/ 参数的类型是:"
                            + parameters.get(i).asType().toString());
                }
                TypeMirror returnType = element2.getReturnType();
                messagerUtils.printMessage(Kind.WARNING,
                        "返回值的类是" + returnType.toString());
            }
        }

        return false;
    }

}

上面的代码主要分为四个部分
- 在init()函数中完成一些变量的初始化的工作

filerUtils = processingEnv.getFiler();
elementUtils = processingEnv.getElementUtils();
messagerUtils = processingEnv.getMessager();

-在Processor()函数中进行了三部分的判断
- TypeElement

当一个Element 是TypeElement 时我们主要关心他的全限定名继承的类或实现的接口等信息,这些我们都可以通过对于的方法获取到。
- VariableElement
当一个Element是VariableElement是,我们也可以通过相应的方法获取相应的信息
- ExecutableElement
当一个Element对应的是一个方法时,我们关心的是方法的参数和参数的类型,我们可以通过以下的方法获取

// 如果是方法则得到方法的参数
                List<? extends VariableElement> parameters = element2
                        .getParameters();
for (int i = 0; i < parameters.size(); i++) {
     String paramterType =parameters.get(i).asType().toString(); // 返回的形式例如 java.lang.String                    messagerUtils.printMessage(Kind.WARNING, "方法的参数名称是 : "
                            + parameters.get(i).getSimpleName() + "/ 参数的类型是:"
                            +paramterType);
                }

将上面的代码运用在Test.java上

package cn.imzhushang.jvm.annotation;

@NameCheck(nameChenckTest = 1)
public class Test {
    @NameCheck(nameChenckTest = 1)
    private int Aaa;

    @NameCheck(nameChenckTest = 1)
    public Long TestC(int arg1, Long l) {
        return 1L;
    }
}

执行的结果是

关于在自定义注解器运行的问题
1.在Java程序中

完成我们的注解处理器的最后一个步骤是打包并注册。这样Java编译器或者其它工具才能够找到这个注解处理器。

注册处理器最简单的方法就是利用标准的Java服务机制:
* 将你的注解处理器打包进一个Jar包。
* 在这个Jar包中要包含一个文件夹META-INF/services
* 在这个文件夹中要包含一个名为javax.annotation.processing.Processor的文件。
* 在这个文件里面将Jar包中所有注解处理器的完整类名写进去,每个类名一行。

Java编译器或者其它工具将会在所有声明的classpath路径下查找这个文件,并用于注册处理器。

然后执行命令

javac -cp testannotation.jar Test.java

具体的配置参考Java语言使用注解处理器生成代码——第二部分:注解处理器

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@EnableScheduling 是 Spring 框架中提供的一个注解,用于开启基于注解的定时任务。其主要作用是扫描带有 @Scheduled 注解的方法,并在指定的时间间隔内执行这些方法。 该注解的源码如下: ```java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(SchedulingConfiguration.class) public @interface EnableScheduling { } ``` 可以看到,该注解使用了 @Import 注解,导入了 SchedulingConfiguration 类。这个类是 Spring 中的一个配置类,它实现了 SchedulingConfigurer 接口,用于配置任务调度器。 SchedulingConfiguration 类的源码如下: ```java @Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration implements SchedulingConfigurer { private volatile ScheduledTaskRegistrar taskRegistrar; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { Assert.notNull(taskRegistrar, "ScheduledTaskRegistrar must not be null"); if (this.taskRegistrar != null && taskRegistrar != this.taskRegistrar) { throw new IllegalStateException("Only one ScheduledTaskRegistrar may exist"); } this.taskRegistrar = taskRegistrar; } @Bean(destroyMethod = "destroy") @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TaskScheduler taskScheduler() { return createDefaultTaskScheduler(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public AnnotationAsyncExecutionAspect asyncExecutionAspect() { return AnnotationAsyncExecutionAspect.aspectOf(); } private TaskScheduler createDefaultTaskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setThreadNamePrefix("spring-task-scheduler-"); return scheduler; } } ``` 可以看到,该类中定义了一个 taskScheduler() 方法,用于创建默认的任务调度器。同时,它还实现了 SchedulingConfigurer 接口,重写了 configureTasks() 方法,用于配置任务调度器。 总的来说,@EnableScheduling 注解的作用就是开启 Spring 的定时任务功能,通过扫描带有 @Scheduled 注解的方法,自动创建定时任务并执行。同时,它还提供了一些默认的配置,例如默认的任务调度器等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值