简体   繁体   English

Java-执行带有指定批注的类方法

[英]Java - Execute a class method with a specify annotation

I have a android application, but it is not relevant. 我有一个android应用程序,但无关紧要。

I have a class called "Front controller" which will receive some message through it's constructor. 我有一个名为“ Front controller”的类,它将通过其构造函数接收一些消息。 The message, for brievity, could be an integer. 为了简洁起见,该消息可以是整数。

I want somewhere else to create a new controller which will execute a method based on the integer defined above 我想在其他地方创建一个新的控制器,该控制器将基于上面定义的整数执行一个方法

public class OtherController {

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


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

The front controller could be something like this: 前端控制器可能是这样的:

public class FrontController {

    private int id;

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

    public void executeProperControllerMethodBasedOnId(){
        //code here
    }

    public int getId(){
        return id;
    }
}

So, if the Front Controller will receive the integer 100, it will execute the method annotated with @MessageId(100). 因此,如果前端控制器将接收整数100,它将执行@MessageId(100)注释的方法。 The front controller don't know exactly the class where this method is. 前端控制器不完全知道此方法所在的类。

The problem which I found is that I need to register somehow each controller class. 我发现的问题是我需要以某种方式注册每个控制器类。 I Spring I had @Component or @Controller for autoloading. 我春天我有@Component或@Controller自动加载。 After each controllers are register, I need to call the properly annotated method. 每个控制器注册后,我需要调用正确注释的方法。

How to achieve this task? 如何完成这项任务? In Spring MVC, I had this system implemented, used to match the HTTP routes. 在Spring MVC中,我实现了该系统,用于匹配HTTP路由。 How could I implement this in a plain java project? 如何在普通的Java项目中实现呢?

Any suggestions? 有什么建议么?

Thanks to Google Reflections (hope you can integrate this in your android project.) 感谢Google Reflections(希望您可以将其集成到您的android项目中。)

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

For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example): 为了进行优化,我添加了也必须使用MessageType注释对类进行注释的要求,并且这些类应位于同一包中(在我的示例中为org.conffusion):

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

The OtherController looks like: 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");
    }
}

The implementation will look like: 该实现将如下所示:

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

Maybe you can optimise and build a static hashmap containing already scanned message ids. 也许您可以优化并构建包含已扫描消息ID的静态哈希图。

You need to implement some of the work by yourself using reflection , I would recommend to prepare message handlers on initial phase in regards to performance. 您需要使用反射自己实现一些工作,我建议在性能方面在初始阶段准备消息处理程序。 Also you possibly want to think about Singleton/Per Request controllers. 您可能还想考虑Singleton / Per Request控制器。 Some of the ways to implement the solution: 实施解决方案的一些方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM