/** * */ package io.client.thrift; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.Socket; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.net.SocketFactory; /** * @author HouKangxi * */ public class ClientInterfaceFactory { private ClientInterfaceFactory() { } private static ConcurrentHashMap<Long, Object> ifaceCache = new ConcurrentHashMap<Long, Object>(); /** * 获得与服务端通信的接口对象 * <p> * 调用者可以实现自定义的 SocketFactory来内部配置Socket参数(如超时时间,SSL等),也可以通过返回包装的Socket来实现连接池 * <br/><pre> * class SocketPool extends javax.net.SocketFactory{ * public Socket createSocket(String methodName,int flag)throws IOException{ * return getSocketFromPool(); * } * private MySocketWrapper getSocketFromPool(){ * ... * } * private void returnToPool(MySocketWrapper socket){ * ... * } * } * class MySocketWrapper extends Socket{ * private Socket target; * private SocketPool pool; * // 包装close()方法,归还连接到连接池 * public void close()throws IOException{ * pool.returnToPool(this); * } * public OutputStream getOutputStream()throws IOException{ * return target.getOutputStream(); * } * public InputStream getInputStream()throws IOException{ * return target.getInputStream(); * } * } * </pre> * <br/> * * * @param ifaceClass * - 接口class * @param factory * - 套接字工厂类, 注意:需要实现 createSocket() 方法,需要实现hashCode()方法来区分factory * @return 接口对象 */ @SuppressWarnings("unchecked") public static <INTERFACE> INTERFACE getClientInterface(Class<INTERFACE> ifaceClass, SocketFactory factory) { long part1 = ifaceClass.getName().hashCode(); final Long KEY = (part1 << 32) | factory.hashCode(); INTERFACE iface = (INTERFACE) ifaceCache.get(KEY); if (iface == null) { iface = (INTERFACE) Proxy.newProxyInstance(ifaceClass.getClassLoader(), new Class[] { ifaceClass }, new Handler(factory)); ifaceCache.putIfAbsent(KEY, iface); } return iface; } private static class Handler implements InvocationHandler { final AtomicInteger seqIdHolder = new AtomicInteger(0); final SocketFactory factory; public Handler(SocketFactory factory) { this.factory = factory; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (args == null || args.length == 0) { if (methodName.equals("toString")) { return Handler.class.getName() + "@" + System.identityHashCode(this); } if (methodName.equals("hashCode")) { return System.identityHashCode(this); } } int seqId = seqIdHolder.incrementAndGet(); ByteArrayOutputStream outbuff = new ByteArrayOutputStream(); TCompactProtocol protocol = new TCompactProtocol(outbuff, null); ProtocolIOUtil.write(methodName, seqId, protocol, method.getGenericParameterTypes(), args); Socket connection = null; Object rs = null; try { connection = factory.createSocket(); OutputStream out = connection.getOutputStream(); out.write(outbuff.toByteArray()); out.flush(); InputStream in = connection.getInputStream(); if (in != null) { protocol.transIn = in; rs = ProtocolIOUtil.read(protocol, method.getGenericReturnType(), method.getExceptionTypes(), seqId); } } finally { if (connection != null) { connection.close(); } } return rs; } } }