如何使用后面的代码创建自定义注释

时间:2012-04-18 07:58:02

标签: java dependency-injection interface annotations

我想创建自己的自定义注释。我的框架是Stand alone java应用程序。当某人注释他的pojo类时,后面的“隐藏”代码将触发方法。

例如,今天在Java EE中我们有@MessageDriven注释。 当您使用@MessageDriven注释您的类时,另外实现MessageListener接口,后面的代码将触发onMessage(Message msg)。当消息从队列/主题到达时。

如何创建可以添加到pojo并实现@MyMessageDriven的注释(MyCustomMessageListener)。

我想要的结果是触发“隐藏”代码(我的),它将触发一个已实现接口的方法(就像我在下面写的样本一样)。

2 个答案:

答案 0 :(得分:34)

我建议阅读this blog entry (snapshot on archive.org),直到作者记得他可以访问Spring的组件扫描功能。

最初的问题是扫描类路径以查找具有自定义注释的类。完成此操作后,您将在独立应用程序中拥有使用object.getClass().getAnnotations()的对象,然后可以注入需要添加到包含自定义注释的对象的侦听器或自定义行为。

假设您有以下自定义注释:

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMessageDriven {}

你在应用程序中使用了一些类:

@MyMessageDriven
public class MyObject {}

现在,在应用程序的适当位置,您应该有一个方法来提供所有带有MyMessageDriven的类:

Set<Class<?>> findAllMessageDrivenClasses() {
  final StopWatch sw = new StopWatch();
  sw.start();
  final Reflections reflections = new Reflections("org.projectx", new TypeAnnotationsScanner());
  Set<Class<?>> allMessageDrivens = reflections.getTypesAnnotatedWith(MyMessageDriven.class); // NOTE HERE
  sw.stop();
  return allMessageDrivens;
}

有了这个,我假设您的应用程序中有一点要么(1)您可以访问应用程序中的对象,或者(2)应用程序中的所有对象都有访问者或迭代器模式。因此,在某些方面,我假设我们将所有目标对象都设为objects

Set<Class<?>> msgDrivenClasses = findAllMessageDrivenClasses();
for (Object o : objects) {
  if (msgDrivenClasses.contains(o.getClass()) {
    invokeTheMessageListener(o);
  }
}

另一方面,当找到MyMessageListener的对象时,应该有一些MyMessageDriven的实现:

void invokeTheMessageListener(Object o) {
  theMessageListener.onMessage(o);
}

此答案是根据博客条目量身定制的,因此请参阅博客以了解库的配置。最后但并非最不重要的是,这是问题的示例代码,它可以重构为更加模式兼容和优雅的风格。

更新:要求目标对象应了解自己的侦听器。所以,我建议采用以下方法。我们有一个接口MyMessageListenerAware

interface MyMessageListenerAware {
  MyMessageListener getMyMessageListener();
}

// and this is the original MyMessageListener
interface MyMessageListener {
  void onMessage(Object o);
}

现在,目标对象应该实现上面的接口:

class MySampleObject implements MyMessageListenerAware {

  public MyMesssageListener getMyMessageLisener() {
    return mySampleObjectImplementationOfMyMessageListener;
  }

}

有了这个,方法invokeTheMessageListener就变成了:

void invokeMessageListener(Object o) {
  if (o instance MyMessageListenerAware) {
    MyMessageListener l = ((MyMessageListenerAware) o).getMyMessageListener();
    l.onMessage(o);
  }
}

虽然,但我强烈建议您阅读VisitorStrategy模式。在我看来,你需要做的事情就像你需要某些对象对应用程序中的公共对象/事件做出反应/行动/处理,但每个都有自己的解释/算法/实现。

答案 1 :(得分:10)

创建这样的注释:

 public @interface MyMessageDriven{
 }

你有一个可以应用这样的注释的界面:

public interface MyMessagListener {

    public void message();
}



@MyMessageDriven  
public class MyMessage implements MyMessagListener  {
   public void message(){
     System.out.println(" I am executed")
   }
} 

使用类加载器加载上面的类并使用反射检查注释是否有效。

如果存在,请使用加载的实例执行它。

  Object obj = ClassLoader.getSystemClassLoader().loadClass("MyMessage").newInstance();
  MyMessagListener mml =  (MyMessagListener) obj;
  mml.message();

您可以将侦听器实现放在MyMessage类或其他实现MessageListener的类中。

在这种情况下,需要为message()提供实现目标。

但是应该加载这个类,更重要的是你的MyMessage类是如何加载的。

这是基于MyMessage类中存在的元数据。类似的方式,在实时场景中,这也是它的工作原理。

Annotation是一个类的元数据,它根据提供的数据说,做一些事情。如果MyMessage类中没有这个元数据,你就不需要执行message()方法。

希望这会对你有所帮助。