[英]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.