java 自动启动监听_玩转Java注释:自动调用监听器

Listener,直译为侦听器或监听器,在面向对象的开发中经常需要用到。如果你需要启动或者停止基于Java的Web系统中不同部分的代码,那么你可以使用一个简单的ServletContentListener来监听容器(container)里面的启动事件和停止事件。这个监听器可以使用java.util.ServiceLoader去寻找这些被侦听事件所对应的已注册类。

这个方法不错,但是如果添加一个编译时间注释处理器会不会更好呢?如果你用@Lifecycle(LifecycleEvent.STARTUP)注释一个静态方法,它将会在开机的时候被调用(在关机的时候被关掉)。处理器会产生类,并为了ServiceLoader而注册它们。你也可以把同样的机制用在任何事件总线(event-bus)模型上:在编译的时候注册listener,并且带有注释,当事件被触发的时候总线会自动调用他们。从本质上讲,你可以通过注释实现用ServiceLoader在运行时间自动发现代码。

实际过程中,其概念如下 你用@EventListener对方法进行注释(可能包含一些元信息(meta-info))。

2. 注释处理器为每个@EventListener方法生成一个EventDispatcher,包括注释中元信息需要的过滤器。

3.  事件总线利用java.util.ServiceLoader找到EventDispatcher的实现。

当EventBus.dispatch被调用时,任何有兴趣的、已经用@EventListener注释的方法都会被调用。

将对事件总线创建的几个必要步骤进行分析,从而阐明这一概念。事件总线不需要任何手动注册就可以调用已注释了的listener方法。我们将从Eventbus开始讨论,然后是注释处理器,最后是一个用法实例。

组织你的代码

这个例子的代码包含两个单独的IDE工程

◆EventBus ——包含了事件总线以及注释处理器

◆EventBusExample ——包含了一个使用事件总线的例子

当操作注释处理器的时候,你应该在IDE选项中关闭"Compile on Save"(或者其他等同的选项)。这些选项可能会删除注释处理器所生成的类,让你摸不着头脑。

以下内容将会解释这些工程中的代码是如何工作的,而且为了便于说明还提供了一些程序片段。

注释和事件

你需要的第一个东西是一个@EventListener注释,用来标识那些侦听事件的方法。下面是一个EventListener注释的例子,它只能用来注释方法。在代码编译后它将被抛弃,因为所有的处理都是对源代码进行的。

@Target(ElementType.METHOD)  @Retention(RetentionPolicy.SOURCE)  public @interface EventListener {   String name() default ".*";   Class> source() default Object.class;  }   由于这个例子是一个事件总线模型,那么listener方法最好只接受它们唯一感兴趣的事件。为了便于执行这个规则,在BusEventObject类中包含了你想过滤的名字(以@EventListener注释里面的名字为基础)。为了让过滤事件更加简单,这个普通的EventObject类中还有一个附加的名字域。BusEventObject也作为一个标识,可以标识出通过EventBus分派的事件。

public abstract class BusEventObject extends EventObject {   private final String name;   public BusEventObject(       final Object source,       final String name) {     super(source);     if(name == null || name.isEmpty()) {       throw new IllegalArgumentException("empty or null name");     }     this.name = name;   }   public String getName() {     return name;   }  }   注释处理器

为了开始写注释处理器,你首先应该熟悉javax.annotation.processing 和 javax.lang.model的包组。一般来说,你可以直接掠过执行处理器接口,进入抽象类javax.annotation.processing.AbstractProcessor。AbstractProcessor需要一些关于实现的信息,这些信息用来提供注释。例子中的EventListenerAnnotationProcessor代码声明如下所示

@SupportedSourceVersion(SourceVersion.RELEASE_5)  @SupportedAnnotationTypes(EventListenerAnnotationProcessor.ANNOTATION_TYPE)  public class EventListenerAnnotationProcessor extends AbstractProcessor {   @SupportedSourceVersion告诉AbstractProcessor你只想要用java5或者更高版本写的源文件;而@SupportedAnnotationTypes告诉AbstractProcessor哪个注释是你感兴趣的(EventListener.class.getName()不会作为一个注释值起作用,因为编译器不能计算这种表达式的值)。

public static final String ANNOTATION_TYPE = "eventbus.EventListener";   为了简单起见,注释处理器被分成两个主要的类(EventListenerAnnotationProcessor 和EventDispatcherGenerator)以及一个通用工具类(ServiceRegistration)。为了便于编译器注释工具执行EventListenerAnnotationProcessor,你需要用一个服务文件来注册它(编译器也使用ServiceLoader)。

eventbus.processor.EventListenerAnnotationProcessor

服务注册文件(META-INF/services/javax.annotation.processing.Processor)是根据ServiceLoader一定能找到的接口来命名的。

EventListenerAnnotationProcessor.process()方法的第一个行动就是找到这轮编译中所有的@EventListener方法。

final Elements elements = processingEnv.getElementUtils();  final TypeElement annotation = elements.getTypeElement(ANNOTATION_TYPE);  final Set extends Element> methods =     roundEnv.getElementsAnnotatedWith(annotation);   Element对象很像编译器以及注释处理器的反射对象(reflection objects)。TypeElement就像是类,而ExecutableElement跟构造器或者方法类似。RoundEnvironment(代表本轮注释处理)将会返回到被@EventListener 注释的Element。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值