easyopen原理解析——不到100行代碼實現一個最精簡的easyopen

easyopen的核心代碼很是簡單,底層是調用method.invoke()方法實現的。最精簡的代碼以下:java

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 迷你版easyopen
 *
 * @author tanghc
 */
public class MiniEasyopen {

    @Documented
    @Retention(RUNTIME)
    @Target(METHOD)
    @interface Api {
        String name() default "";
    }

    static class ApiInfo {
        private Object handler;
        private Method method;

        public ApiInfo(Object handler, Method method) {
            this.handler = handler;
            this.method = method;
        }
    }

    // 業務類
    static class GoodsService {
        // 獲取商品接口
        @Api(name = "goods.get")
        public String getGoods(String param) {
            return "your param is " + param;
        }
    }

    // 存放接口信息的地方
    Map<String, ApiInfo> map = new ConcurrentHashMap<String, ApiInfo>();

    // 註冊接口
    public void regist() {
        // 找到bean對象,能夠從spring容器中獲取
        Object[] beans = {new GoodsService()};

        for (Object bean : beans) {
            Class<?> serviceClass = bean.getClass();
            Method[] methods = serviceClass.getMethods();
            for (Method method : methods) {
                // 找到註解方法
                Api api = method.getAnnotation(Api.class);
                if (api != null) {
                    System.out.println(String.format("【註冊接口%s,%s】", api.name(), method.toString()));
                    map.put(api.name(), new ApiInfo(bean, method));
                }
            }
        }

    }

    // 調用接口
    public Object invoke(String name, String param) throws Exception {
        // 根據方法名找到對應的接口信息
        ApiInfo apiInfo = map.get(name);
        if (apiInfo == null) {
            throw new IllegalAccessException("調用不存在的服務" + name);
        }
        Method method = apiInfo.method;
        Object handler = apiInfo.handler;
        return method.invoke(handler, param);
    }


    public static void main(String[] args) throws Exception {
        // 服務啓動
        MiniEasyopen miniEasyopen = new MiniEasyopen();
        // 註冊接口
        miniEasyopen.regist();

        // 請求名,請求參數,假設已經從request中解析出來
        String name = "goods.get";
        String param = "iphone";

        // 方法調用
        Object result = miniEasyopen.invoke(name, param);

        System.out.println("返回結果:" + result);
    }
}

從main方法開始看,服務啓動作了註冊接口操做,即找到被@Api標記的方法,而後保存這個方法的信息。spring

調用接口時,根據接口名找到方法信息,而後invoke一下,返回結果。api

這個最基本的骨架搭建完以後,能夠進行一些額外則操做,好比簽名驗證、攔截器、方法結果處理操做。iphone

easyopen就是在此基礎上逐漸完善起來的。this

相關文章
相關標籤/搜索