In the early days of JAVA, Web frameworks used XML files to manage interfaces, such as Struts and spring. Its components are basically defined in the XML file, and then loaded through the XML file when the system starts.

The system developed in this mode has bloated files and is very difficult to maintain and manage. Later, Java brought Annotation, coupled with Java’s reflection mechanism. It provides us with a very convenient way to manage the interface, and the built system is very simple and elegant. Let’s take a look at its specific application.

First define an Annotation that acts on the method

package webfunc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestFunction {
    String action();

    boolean cached() default false;

    boolean isSynchronize() default false;

    String explain() default "Request function";
}


//  @RequestFunction (action = "personVerify")
//  public ResponseData personVerifyMethod(WebSystemContext context) {
     //..............
//  }

The ElementType.METHOD attribute in this Annotation represents that this annotation is applied to the method. You can also define other functions for him according to system needs, such as caching, asynchronous operations, and so on. After the annotation is defined, it can be used like the business code above to see how the system loads the annotation.

    Before continuing, a brief explanation, the content of the annotation is like this:@RequestFunction (action = “personVerify”)。

    The code that needs to be executed is this:public ResponseData personVerifyMethod(WebSystemContext context)。

    This requires a corresponding relationship, representing the request instruction and the method respectively, and the corresponding method is executed through the request instruction.

    First define a calling class that actually executes the method. There are classes and methods that need to be called, just call the method.

    package webfunc;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class InvokedFunction {
        public Method method;
        public Class<?> clazz;
        public boolean single;
        public boolean cached;
        public boolean voided;
    
        public Object execute(WebSystemContext context) {
            Object refer = null;
            try {
                if (this.single != true) {
                    refer = clazz.newInstance();
                }
                Object[] args = new Object[]{context};
                Object result = method.invoke(refer, args);
    
                return voided == true ? null : result;
            } catch (InstantiationException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e.getTargetException());
            }
        }
    }
    

    This class uses the Java reflection mechanism, and its purpose is to execute the method that needs to be executed according to the parameters and return value. The definition of these contents is the pre-loaded, class instance, method name and other attributes.

    Next, define a class to manage the relationship between request instructions and calling methods

    package webfunc;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class InvokeCommand {
    
        Map<String, InvokedFunction> funcMap;
    
        public InvokeCommand() {
            funcMap = new HashMap<String, InvokedFunction>();
        }
    
        public boolean hasFunction(String func) {
            return funcMap.containsKey(func);
        }
    
        public InvokedFunction getFunction(String func) {
            return InvokeCommand.this.funcMap.get(func);
        }
    
        public void put(String func, InvokedFunction invFunc) {
            this.funcMap.put(func, invFunc);
        }
    
    }
    

    In this class we maintain a map that manages the relationship between request instructions and called objects. For example, if the instruction is personVerify, the corresponding called method is public ResponseData personVerifyMethod(WebSystemContext context).

    we will load annotations and methods when the system starts:

    package webfunc;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.util.HashMap;
    import java.util.Map;
    
    public class ServiceContext {
    
        public static Map<String, InvokeCommand> cmmdMap;
        private static ServiceContext context;
    
        private ServiceContext() {
            cmmdMap = new HashMap<String, InvokeCommand>();
            try{
                //...preload the Commands from xml file...
                //the business class
                String classStr = "com.test.example.Business.UserAction";
                //Request Command
                String commandStr = "personVerify";
                this.parseWebModule(Class.forName(classStr), commandStr);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    
        public static ServiceContext getContext() {
            if (context == null) {
                context = new ServiceContext();
            }
            return ServiceContext.context;
        }
    
        public boolean hasCommand(String cmmd) {
            return cmmdMap.containsKey(cmmd);
        }
    
        public InvokeCommand getCommand(String cmmd) {
            return this.cmmdMap.get(cmmd);
        }
    
        public void parseWebModule(Class<?> clz, String code) {
            Class<RequestFunction> antClass = RequestFunction.class;
            for (Method method : clz.getMethods()) {
                int modify = method.getModifiers();
                if (Modifier.isPublic(modify)) {
                    RequestFunction webfunc = null;
                    if (method.isAnnotationPresent(antClass)) {
                        webfunc = method.getAnnotation(antClass);
                        if (code.equals(webfunc.action())) {
                            InvokeCommand proxy = null;
                            if (!cmmdMap.containsKey(code)) {
                                proxy = new InvokeCommand();
                                cmmdMap.put(code, proxy);
                            }
                            InvokedFunction webmethod = null;
                            webmethod = new InvokedFunction();
                            webmethod.clazz = clz;
                            webmethod.method = method;
                            webmethod.cached = webfunc.cached();
                            webmethod.single = Modifier.isStatic(modify);
                            Class<?> returnType = method.getReturnType();
                            webmethod.voided = returnType.equals(Void.class);
    
                            proxy = cmmdMap.get(code);
                            proxy.put(code, webmethod);
    
                        }
                    }
                }
            }
    
        }
    }
    

    In this class, we loaded the business execution class and business execution method through the configuration file. Load them into the memory in advance, and when the request arrives, you can judge whether the request command is legal. If it is legal, you can call the corresponding method. Then return the response to the client, and the reflection mechanism of JAVA is also used here.

    The business execution classes and calling commands here should all be configured and loaded uniformly in the file. Now most frameworks have changed the mode, which will also cause bloated configuration files. Most frameworks now retrieve Annotation and use Java’s reflection mechanism to parse its content. Here is just an example to illustrate how the Annotation and reflection mechanism help us develop the Java framework.

    This set of things can be used not only in the Web framework, but also in the interface platform of the C/S structure, which is very practical.


    发表回复

    Thanks for your support to bet365fans!