Java - 使用指定注释执行类方法

时间:2014-07-31 08:43:41

标签: java annotations

我有一个Android应用程序,但它不相关。

我有一个名为"前控制器"这将收到一些消息 通过它的构造函数。为了简洁起见,该消息可以是整数。

我想在其他地方创建一个将要执行的新控制器 基于上面定义的整数的方法

public class OtherController {

   @MessageId("100")
   public void doSomething(){
        //execute this code
   }


   @MessageId("101")
   public void doSomethingElse(){
        //code
   }
}

前置控制器可能是这样的:

public class FrontController {

    private int id;

    public FrontController(int id){
        this.id=id;
        executeProperControllerMethodBasedOnId();  
    }

    public void executeProperControllerMethodBasedOnId(){
        //code here
    }

    public int getId(){
        return id;
    }
}

因此,如果Front Controller将接收整数100,那么 将执行使用@MessageId(100)注释的方法。该 前控制器并不完全知道这种方法所在的类 是

我发现的问题是我需要以某种方式注册 每个控制器类。我春天我有@Component或@Controller 用于自动加载。每个控制器注册后,我需要 调用正确注释的方法。

如何完成这项任务?在Spring MVC中,我有这个系统 已实现,用于匹配HTTP路由。我怎么能实现 这是一个简单的java项目吗?

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

感谢Google Reflections(希望你能将它集成到你的android项目中。)

    <dependency>
        <groupId>org.reflections</groupId>
        <artifactId>reflections-maven</artifactId>
        <version>0.9.8</version>
    </dependency>

为了优化,我添加了使用MessageType注释来注释类的要求,并且这些类应该在同一个包中(在我的示例中为org.conffusion):

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

OtherController看起来像:

@MessageType
public class OtherController  {

    @MessageId(id=101)
    public void method1()
    {
        System.out.println("executing method1");
    }
    @MessageId(id=102)
    public void method2()
    {
        System.out.println("executing method2");
    }
}

实施将如下所示:

public void executeProperControllerMethodBasedOnId() {
    Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
            .getTypesAnnotatedWith(MessageType.class);
    System.out.println("found classes " + classes.size());
    for (Class<?> c : classes) {
        for (Method m : c.getMethods()) {
            try {
                if (m.isAnnotationPresent(MessageId.class)) {
                    MessageId mid = m.getAnnotation(MessageId.class);
                        Object o = c.newInstance();
                    if (mid.id() == id)
                        m.invoke(o);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

也许您可以优化并构建包含已扫描的消息ID的静态哈希映射。

答案 1 :(得分:1)

您需要使用反射自行实现一些工作,我建议在初始阶段就性能准备消息处理程序。您还可以考虑 Singleton / Per Request 控制器。实现解决方案的一些方法:

interface MessageProcessor {
    void execute() throws Exception;
}

/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {

    private final Object instance;
    private final Method method;

    SingletonProcessor(Object instance, Method method) {
        this.instance = instance;
        this.method = method;
    }

    public void execute() throws Exception {
        method.invoke(instance);
    }
}

/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {

    private final Class clazz;
    private final Method method;

    PerRequestProcessor(Class clazz, Method method) {
        this.clazz = clazz;
        this.method = method;
    }

    public void execute() throws Exception {
        Object instance = clazz.newInstance();
        method.invoke(instance);
    }
}

/* Dummy controllers */
class PerRequestController {
    @MessageId(1)
    public void handleMessage1(){System.out.println(this + " - Message1");}
}

class SingletonController {
    @MessageId(2)
    public void handleMessage2(){System.out.println(this + " - Message2");}
}

class FrontController {

    private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();

    static {
        try {
            // register your controllers
            // also you can scan for annotated controllers as suggested by Conffusion
            registerPerRequestController(PerRequestController.class);
            registerSingletonController(SingletonController.class);
        } catch (Exception e) {
            throw new ExceptionInInitializerError();
        }
    }

    private static void registerPerRequestController(Class aClass) {
        for (Method m : aClass.getMethods()) {
            if (m.isAnnotationPresent(MessageId.class)) {
                MessageId mid = m.getAnnotation(MessageId.class);
                processors.put(mid.value(), new PerRequestProcessor(aClass, m));
            }
        }
    }

    private static void registerSingletonController(Class aClass) throws Exception {
        for (Method m : aClass.getMethods()) {
            if (m.isAnnotationPresent(MessageId.class)) {
                MessageId mid = m.getAnnotation(MessageId.class);
                Object instance = aClass.newInstance();
                processors.put(mid.value(), new SingletonProcessor(instance, m));
            }
        }
    }

    /* To process the message you just need to look up processor and execute */
    public void processMessage(int id) throws Exception {
        if (processors.containsKey(id)) {
            processors.get(id).execute();
        } else {
            System.err.print("Processor not found for message " + id);
        }
    }    
}