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

Posted

技术标签:

【中文标题】如何使用后面的代码创建自定义注释【英文标题】:How to create custom annotation with code behind 【发布时间】:2012-04-29 14:53:59 【问题描述】:

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

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

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

我想要的结果是触发“隐藏”代码(我的),这将触发已实现接口的方法(与我在下面编写的示例完全一样)。

【问题讨论】:

您使用的是什么容器或业务框架? 这是一个独立的 java 应用程序。 【参考方案1】:

我建议阅读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);
  

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

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);
  

尽管,我强烈推荐阅读Visitor 或Strategy 模式。在我看来,您的目标是您需要某些对象对应用程序中的公共对象/事件做出反应/行动/处理,但每个都有自己的解释/算法/实现。

【讨论】:

嗨,但我没有使用 Spring。 我提到了“直截了当”。春天只是如果你有春天,它仍然是完整的。 是的,我确实想向对象注入侦听器,但我很难从你的 Spring 示例中理解如何做到这一点。也许你有其他的参考资料给我?谢谢! 您好,感谢您的详细回答。但是告诉我我为每个类实现监听器的部分是@MyMessageDriven,所以当消息到达时它会触发类的onMessage方法。 我想要达到的效果与在 JAVA-EE 上实现的 MDB Annotation 完全一样【参考方案2】:

创建一个类似这样的注释:

 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();

Listener 实现可以放在 MyMessage 类或其他实现 MessageListener 的类中。

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

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

这是基于 MyMessage 类中存在的元数据。类似的方式,在实时场景中也是如此。

注释是类的元数据,它根据提供的数据说,做某事。如果 MyMessage 类中不存在此元数据,则无需执行 message() 方法。

希望这会对你有所帮助。

【讨论】:

嗨,但是有两件事:我应该把我的监听器实现放在哪里?以及如何将其注入 MyMessage 类。第二个什么时候/在哪里我需要使用你在下面写的执行代码? 在普通的MDB中,我们正在执行一些业务逻辑,对吧。那是自动执行的。所以这是怎么发生的,你的MDB被加载了。2。加载后,检查是否存在注释。3 .如果存在注释,则将此加载的类转换为 MyMessageListener 接口。这就是我向您展示的代码。但请记住,所有这些机制都发生在抽象的框架内。我只是在谈论那个场景。4。现在框架,正在做一些操作,比如从队列中获取消息或做一些操作。5.然后它正在调用 messagelistener.message() 方法。 你能说明我在哪里实现“监听”逻辑吗?以及它将如何连接到带注释的类。 想象一下框架作为加载 MyMessage 类的代码。想象一下这段代码是从一个类似的框架中提取的。现在“监听”意味着一个事件由于某些动作而刚刚触发。这就是你将在消息方法中写入。因为它是合同的实现。在这里,您不必担心监听器是如何被调用的。当 MyMessageListener 类具有该部分时,上述代码会自动处理该部分属性。

以上是关于如何使用后面的代码创建自定义注释的主要内容,如果未能解决你的问题,请参考以下文章

如何在java web项目中添加自定义注解

如何创建自定义 MKAnnotationView 和自定义注释标题和副标题

如何在Eclipse中如何自动添加注释和自定义注释风格

自定义地图注释标注 - 如何控制宽度

使用数据注释和代码的自定义验证属性

如何在Eclipse中如何自动添加注释和自定义注释风格