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

注释处理器

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

24. @SupportedSourceVersion(SourceVersion.RELEASE_5)

25. @SupportedAnnotationTypes(EventListenerAnnotationProcessor.ANNOTATION_TYPE)

26. public class EventListenerAnnotationProcessor extends AbstractProcessor {

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

28. 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方法。

30. final Elements elements = processingEnv.getElementUtils();

31. final TypeElement annotation = elements.getTypeElement(ANNOTATION_TYPE);

32. final Set extends Element> methods =

33.         roundEnv.getElementsAnnotatedWith(annotation);

Element对象很像编译器以及注释处理器的反射对象(reflection objects)。TypeElement就像是类,而ExecutableElement跟构造器或者方法类似。RoundEnvironment(代表本轮注释处理)将会返回到被@EventListener 注释的Element。

EventDispatcherGenerator

EventDispatcherGenerator是一个非常简单的代码生成器。你可能更喜欢用模板(比如FreeMarker 或者Velocity)来生成你的源代码,但是这个例子中的代码是用PrintWriter写的。每个代表@EventListener注释方法的ExecutableElementEvent被传递到DispatcherGenerator.generate,它可以给EventDispatcher写出源代码。

35. for(final Element m : methods) {

36.     // ensure that the element is a method

37.     if(m.getKind() == ElementKind.METHOD) {

38.         final ExecutableElement method = (ExecutableElement)m;

39.         results.add(generator.generate(method));

40.     }

41. }

该EventDispatcherGenerator需要为每个方法产生一个Java源文件。一个注释处理器用ProcessingEnvironment提供的过滤目标来创建用于编写代码的源文件。

43. final JavaFileObject file = processingEnvironment.getFiler().createSourceFile(

44.         className, // ie: com.mydomain.example.OnMessageDispatcher

45.         method);     // ie: com.mydomain.example.Listener.onMessage(MessageEvent)

在这个例子中,给定的过滤器ExecutableElement代表了已经注释的方法(createSourceFile中的第二个观点)。这会告诉环境你正在生成跟那个方法相关的源代码,虽然不是必须的,但是比较有用。然后代码用JavaFileObject来打开一个书写器,并开始生成源代码。

47. final Writer writer = file.openWriter();

48. final PrintWriter pw = new PrintWriter(writer);

49. pw.append("package ").append(packageName).println(';');

在@EventListener注释中为方法指定值,从而在调用注释方法之前产生一个if 语句,这个if语句可以过滤BusEventObjects。EventDispatcherGenerator把if 语句写进源代码,从而决定是否把事件对象分派到@EventListener方法中去。

51. public final class EventBus {

52.     private static final EventDispatcher[] DISPATCHERS;

53.     static {

54.         final ServiceLoader loader =

55.                 ServiceLoader.load(EventDispatcher.class);

56.         final List list = new ArrayList();

57.         for(final EventDispatcher dispatcher : loader) {

58.             list.add(dispatcher);

59.         }

60.         DISPATCHERS = list.toArray(new EventDispatcher[list.size()]);

61.     }

62.     private EventBus() {

63.     }

64.     public static void dispatch(final BusEventObject object) {

65.         if(object == null) {

66.             throw new IllegalArgumentException("null event object");

67.         }

68.         for(final EventDispatcher dispatcher : DISPATCHERS) {

69.             dispatcher.dispatch(object);

70.         }

71.     }

72.     public static interface EventDispatcher {

73.

74.         void dispatch(BusEventObject object);

75.     }

76. }

32/3<123>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值