All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dubboclub.dubbogenerator.reference.DubboClientWrapper Maven / Gradle / Ivy

The newest version!
package net.dubboclub.dubbogenerator.reference;


import com.alibaba.dubbo.common.utils.ConfigUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.config.ReferenceConfig;
import net.dubboclub.dubbogenerator.InvokeTargetException;
import net.dubboclub.dubbogenerator.JavassistClassGenerator;
import net.dubboclub.dubbogenerator.handler.DefaultInvokeHandler;
import net.dubboclub.dubbogenerator.handler.InvokeHandler;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by bieber on 2015/7/31.
 * 动态加载封装Dubbo客户端调用
 */
public class DubboClientWrapper {
    
    //缓存已经生成的包装对象
    private static final ConcurrentHashMap,Object> WRAPPER_CACHE = new ConcurrentHashMap, Object>();
    
    private static final ConcurrentHashMap,Object> HANDLER_CACHE = new ConcurrentHashMap, Object>();
    
    private static final String DEFAULT_WRAPPER_HANDLER_KEY="dubbo.wrapper.default.handler";
    
    private static final String INVOKE_HANDLER_KEY_SUFFIX=".handler";
    
    private static final String DUBBO_WRAPPER_KEY_PREFIX="dubbo.wrapper.";
    
    //包装计数器
    private static final AtomicLong WRAPPER_COUNTER = new AtomicLong(0);
    
    
    private static Class DEFAULT_HANDLER = DefaultInvokeHandler.class;
    
    private static volatile boolean isShutdown = false;
    
    private static volatile boolean hadSetDefaultHandler = false;
    
    //动态类的标记接口
    public interface DCW{

    }//mark dynamic facade wrapper
    
    static {
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                isShutdown=true;
                WRAPPER_CACHE.clear();
            }
        });
        String handlerClassName = ConfigUtils.getProperty(DEFAULT_WRAPPER_HANDLER_KEY);
        if(!StringUtils.isEmpty(handlerClassName)){
            DEFAULT_HANDLER = generateHandler(handlerClassName);
        }
    }


    public static T getWrapper(Class clientType,String id){
        return getWrapper(clientType,id, null);
    }

    public static T getWrapper(Class clientType,Class handler){
        return getWrapper(clientType,null,handler);
    }
    /**
     * 对外提供的接口,获取指定类型的dubbo客户端引用
     * 如果之前创建过,则直接从缓存中获取,不必再次创建
     * @param clientType
     * @param 
     * @return
     */
    public static T getWrapper(Class clientType){
        return getWrapper(clientType,generateClientId(clientType));
    }
    
    public static T getWrapper(Class clientType,String id,Class handler){
        if(isShutdown){
            throw new IllegalStateException("JVM had shutdown,can not generate wrapper!");
        }
        T clientInstance = null;
        if(StringUtils.isEmpty(id)){
            id = generateClientId(clientType);
        }
        if(handler==null){
            handler = getInvokeHandler(clientType,id);
        }
        if(WRAPPER_CACHE.containsKey(clientType)){
            clientInstance =  (T) WRAPPER_CACHE.get(clientType);
        }else{
            clientInstance = (T) makeClientWrapper(clientType,id,handler);
            Object oldInstance = WRAPPER_CACHE.putIfAbsent(clientType,clientInstance);
            if(oldInstance!=null){
                clientInstance= (T) oldInstance;
            }
        }
        return clientInstance;
    }


    
    public static synchronized void setDefaultHandler(Class handler){
        if(hadSetDefaultHandler){
            throw new IllegalStateException("had already set default InvokeHandler ["+DEFAULT_HANDLER.getName()+"].");
        }
        hadSetDefaultHandler=true;
        DEFAULT_HANDLER=handler;
    }

    /**
     * 判断当前类是不是包装类
     * @param type
     * @return
     */
    public static boolean isWrapped(Class type){
        return DCW.class.isAssignableFrom(type);
    }
    
    private static String generateClientId(Class clientType){
        return "["+clientType.getName()+"]";
    }

    private static Class getInvokeHandler(Class clientType,String id){
        //dubbo.wrapper.[clientfacadefullname].handler
        String handlerName = ConfigUtils.getProperty(DUBBO_WRAPPER_KEY_PREFIX + id + INVOKE_HANDLER_KEY_SUFFIX);
        if(StringUtils.isEmpty(handlerName)){
            return DEFAULT_HANDLER;
        }
        return generateHandler(handlerName);
        
    }

    private static Class generateHandler(String handlerClassName){
        try {
            Class handlerClass = Class.forName(handlerClassName);
            if(!InvokeHandler.class.isAssignableFrom(handlerClass)){
                throw new IllegalArgumentException("Class ["+handlerClassName+"] must implements InvokerHandler or extends sub class,please check property [default.dubbo.wrapper.handler]");
            }
            return (Class) handlerClass;
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("Class ["+handlerClassName+"] not found ,please check property [default.dubbo.wrapper.handler]",e);
        }
    }
    /**
     * 构造一个新的指定类型的Dubbo客户端引用
     * @param clientType 该参数只能是接口类型,不支持其他类型
     * @return
     */
    private static Object makeClientWrapper(Class clientType,String clientId,Class handlerClass){
        String clientName = clientType.getSimpleName();
        long id = WRAPPER_COUNTER.getAndIncrement();
        if(clientType==DCW.class){
            throw new IllegalArgumentException("not support generate wrapper for interface "+clientName);
        }
        if(!clientType.isInterface()){
            throw new IllegalArgumentException("only support interface to generate wrapper,but type "+clientName+" is not interface");
        }
        JavassistClassGenerator generator = JavassistClassGenerator.newInstance(clientType.getClassLoader());
        generator.addInterface(clientType.getName());
        generator.addInterface(DCW.class.getName());
        StringBuilder className = new StringBuilder();
        className.append(clientType.getSimpleName()).append("$DCW").append(id);
        generator.setClassName(className.toString());
        Method[] methods = clientType.getDeclaredMethods();
        StringBuilder methodCode = new StringBuilder();
        for(Method method:methods){
            methodCode.append("public ");
            Class returnType = method.getReturnType();
            Class[] argsTypes = method.getParameterTypes();
            if(returnType== Void.TYPE){
                methodCode.append("void ");
            }else{
                methodCode.append(returnType.getName()).append(" ");
            }
            methodCode.append(method.getName()).append("(");
            //append arguments
            if(argsTypes.length!=0){
                for(int i=0;i[] exceptionTypes = method.getExceptionTypes();
            methodCode.append(")");
            if(exceptionTypes.length!=0){
                methodCode.append("throws ");
                for(Class exceptionType:exceptionTypes){
                    methodCode.append(exceptionType.getName()).append(",");
                }
                methodCode.setLength(methodCode.length()-1);
            }
            methodCode.append("{");
            methodCode.append("try{");
            //append method body
            //handle invoke before
            if(argsTypes.length==0){
                methodCode.append("invokeHandler.beforeInvoke(clientType,\"" + method.getName() + "\",null);");
            }else{
                methodCode.append("invokeHandler.beforeInvoke(clientType,\"" + method.getName() + "\",$args);");
            }
            //handle invoke complete
            if(returnType== Void.TYPE){
                methodCode.append("(($w)clientRef).").append(method.getName()).append("($$);");
                if(argsTypes.length==0){
                    methodCode.append("invokeHandler.completeInvoke(clientType,\"" + method.getName() + "\",null,null);");
                }else{
                    methodCode.append("invokeHandler.completeInvoke(clientType,\"" + method.getName() + "\",null,$args);");
                }
            }else{
                methodCode.append("Object result=(($w)clientRef).").append(method.getName()).append("($$);");
                if(argsTypes.length==0){
                    methodCode.append("invokeHandler.completeInvoke(clientType,\"" + method.getName() + "\",(Object)result,null);");
                }else{
                    methodCode.append("invokeHandler.completeInvoke(clientType,\"" + method.getName() + "\",(Object)result,$args);");
                }
                methodCode.append("return ($r)result;");
            }
            methodCode.append("}catch(Throwable t){");
            //handle invoke exception
            if(argsTypes.length==0){
                methodCode.append("invokeHandler.caughtException(clientType,\"" + method.getName() + "\",t,null);");
            }else{
                methodCode.append("invokeHandler.caughtException(clientType,\"" + method.getName() + "\",t,$args);");
            }

            methodCode.append("throw new ").append(InvokeTargetException.class.getName()).append("(clientType,\""+method.getName()+"\",t);");
            methodCode.append("}");
            methodCode.append("}");
            generator.addMethod(methodCode.toString());
            methodCode.setLength(0);
        }
        generator.addField("public static "+clientType.getName()+" clientRef;");
        generator.addField("public static "+InvokeHandler.class.getName()+" invokeHandler;");
        generator.addField("public static "+Class.class.getName()+" clientType;");
        Class clazz = generator.toClass();
        try {
            ReferenceConfig config = new ReferenceConfig();
            config.setId(clientId);
            config.setCheck(false);
            config.setInterface(clientType.getName());
            clazz.getField("clientRef").set(null,config.get());
            if(!HANDLER_CACHE.containsKey(handlerClass)){
                HANDLER_CACHE.putIfAbsent(handlerClass,handlerClass.newInstance());
            }
            clazz.getField("invokeHandler").set(null,HANDLER_CACHE.get(handlerClass));
            clazz.getField("clientType").set(null,clientType);
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy