由浅入深了解Thrift之客户端连接池化续

    前文《由浅入深了解Thrift之客户端连接池化》中我们已经实现了服务调用端 连接的池化,实现的过于简陋,离实际的项目运用还很遥远。本文将在进一步改造,主要是两方面:1、服务端如何注册多个服务 2、调用端如何获取服务对象而不是服务连接

一、实现思路

    1、通过spring配置文件,配置服务类

    2、反射生成服务类实例,依次注册服务

    调用端获取服务对象亦是如此,废话不多说了

二、主要实现

   1、服务端

/**
 * thrift server端,向zk中注册server address
 * 
 * @author wy
 * 
 */
public class ThriftServiceServerFactory implements InitializingBean {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    // thrift server 服务端口
    private Integer port;
    // default 权重
    private Integer priority = 1;
    // service 实现类
    private Map<String, Object> services;
    // thrift server 注册路径
    private String configPath;
    // thrift service module
    private String configService;

    private ThriftServerIpTransfer ipTransfer;
    // thrift server注册类
    private ThriftServerAddressReporter addressReporter;
    // thrift server开启服务
    private ServerThread serverThread;

    @Override
    public void afterPropertiesSet() throws Exception {
        if (ipTransfer == null) {
            ipTransfer = new LocalNetworkIpTransfer();
        }
        String ip = ipTransfer.getIp();
        if (ip == null) {
            throw new NullPointerException("cant find server ip...");
        }
        String hostName = ip + ":" + port + ":" + priority;
        logger.info("registry services address = " + hostName);
        logger.info("registry services count = " + services.size());
        Set<Entry<String, Object>> set = services.entrySet();
        Iterator<Entry<String, Object>> iter = set.iterator();
        Map<String, TProcessor> processors = new HashMap<String, TProcessor>();
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        for (; iter.hasNext();) {
            Entry<String, Object> entry = iter.next();
            // 通过反射获取service interface
            String servieName = entry.getKey();
            Object serviceImplObject = entry.getValue();
            Class<?> serviceClass = serviceImplObject.getClass();
            // 返回本类直接实现的接口.不包含泛型参数信息
            Class<?>[] interfaces = serviceClass.getInterfaces();
            if (interfaces.length == 0) {
                throw new IllegalClassFormatException("service-class should implements Iface");
            }
            TProcessor processor = null;
            for (Class<?> interfaceClazz : interfaces) {
                logger.info("service Interfaces count = " + interfaces.length);
                // 获取源代码中给出的'底层类'简称
                String cname = interfaceClazz.getSimpleName();
                if (!cname.equals("Iface")) {
                    continue;
                }
                // 获取外部类Class;以String的形式,返回Class对象的'实体'名称
                String pname = interfaceClazz.getEnclosingClass().getName() + "$Processor";
                Class<?> pclass = classLoader.loadClass(pname);
                // class是否相同或是另一个类的超类或接口
                if (!pclass.isAssignableFrom(Processor.class)) {
                    continue;
                }
                Constructor<?> constructor = pclass.getConstructor(interfaceClazz);
                processor = (TProcessor) constructor.newInstance(serviceImplObject);
                processors.put(servieName, processor);
                break;
            }
            if (processor == null) {
                throw new IllegalClassFormatException("service-class should implements Iface");
            }
            
        }

        // 需要单独的线程,因为serve方法是阻塞的.
        serverThread = new ServerThread(processors, port);
        serverThread.start();
        // 向ZK中注册服务
        if (addressReporter != null) {
            addressReporter.report(configPath, hostName);
        }
    }

    class ServerThread extends Thread {
        private TServer server;

        ServerThread(Map<String, TProcessor> processors, int port) throws Exception {
            // 设置传输通道
            TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(
                    port);
            // 设置二进制协议
            Factory protocolFactory = new TBinaryProtocol.Factory();
            // 网络服务模型
            TThreadedSelectorServer.Args tssArgs = new TThreadedSelectorServer.Args(
                    serverTransport);
            //
            TMultiplexedProcessor processor = new TMultiplexedProcessor();

            Set<Entry<String, TProcessor>> set = processors.entrySet();
            Iterator<Entry<String, TProcessor>> iter = set.iterator();
            //
            for (; iter.hasNext();) {
                Entry<String, TProcessor> entry = iter.next();
                processor.registerProcessor(entry.getKey(),
                        (TProcessor) entry.getValue());
                tssArgs.processor(processor);
            }

            tssArgs.protocolFactory(protocolFactory);
            //
            tssArgs.transportFactory(new TFramedTransport.Factory());
            int num = Runtime.getRuntime().availableProcessors() * 2 + 1;
            tssArgs.selectorThreads(num);
            tssArgs.workerThreads(num * 10);

            server = new TThreadedSelectorServer(tssArgs);

        }

        @Override
        public void run() {
            try {
                server.serve();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 关闭thrift server
        public void stopServer() {
            if (server != null && !server.isServing()) {
                server.stop();
            }
        }
    }

    // 关闭thrift server
    public void close() {
        serverThread.stopServer();
    }

    public void setServices(Map<String, Object> services) {
        this.services = services;
    }

    public void setPriority(Integer priority) {
        this.priority = priority;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public void setIpTransfer(ThriftServerIpTransfer ipTransfer) {
        this.ipTransfer = ipTransfer;
    }

    public void setAddressReporter(ThriftServerAddressReporter addressReporter) {
        this.addressReporter = addressReporter;
    }

    public void setConfigPath(String configPath) {
        this.configPath = configPath;
    }

    public String getConfigService() {
        return configService;
    }

    public void setConfigService(String configService) {
        this.configService = configService;
    }

}
View Code

       spring配置文件

<!-- zookeeper -->
    <bean id="thriftZookeeper" class="com.wy.thriftpool.commzkpool.zookeeper.ZookeeperFactory" destroy-method="close">
        <property name="connectString" value="127.0.0.1:2181" />
        <property name="namespace" value="thrift/thrift-service" />
    </bean>
    
    <bean id="serviceAddressReporter" class="com.wy.thriftpool.commzkpool.support.impl.DynamicAddressReporter" destroy-method="close">
        <property name="zookeeper" ref="thriftZookeeper" />
    </bean>
    
    <bean id="userService" class="com.wy.thrift.service.UserServiceImpl"/>
    
    <bean class="com.wy.thriftpool.commzkpool.server.ThriftServiceServerFactory" destroy-method="close">
        <property name="configPath" value="serviceAddress" />
        <property name="configService" value="serviceModule" />
        <property name="port" value="9090" />
        <property name="addressReporter" ref="serviceAddressReporter" />
        <property name="services">
            <map>
                <entry key="userService" value-ref="userService" />
            </map>
        </property>
    </bean>
View Code

   2、调用端

/**
 * TServiceClient,工厂类 
 * thrift Client端负责于thrift server通信
 * 
 * @author wy
 */
public class AbstractThriftServiceClientFactory extends BasePoolableObjectFactory<TServiceClient> {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    // 超时设置
    private int timeOut;

    private final ThriftServerAddressProvider addressProvider;
    private final TServiceClientFactory<TServiceClient> clientFactory;
    private PoolOperationCallBack callback;

    protected AbstractThriftServiceClientFactory(
            ThriftServerAddressProvider addressProvider,
            TServiceClientFactory<TServiceClient> clientFactory)
            throws Exception {
        this.addressProvider = addressProvider;
        this.clientFactory = clientFactory;
    }

    protected AbstractThriftServiceClientFactory(
            ThriftServerAddressProvider addressProvider,
            TServiceClientFactory<TServiceClient> clientFactory,
            PoolOperationCallBack callback) throws Exception {
        this.addressProvider = addressProvider;
        this.clientFactory = clientFactory;
        this.callback = callback;
    }

    protected AbstractThriftServiceClientFactory(
            ThriftServerAddressProvider addressProvider,
            TServiceClientFactory<TServiceClient> clientFactory,
            PoolOperationCallBack callback, int timeOut) throws Exception {
        this.addressProvider = addressProvider;
        this.clientFactory = clientFactory;
        this.callback = callback;
        this.timeOut = timeOut;
    }

    /**
     * 创建对象
     */
    @Override
    public TServiceClient makeObject() throws Exception {
        InetSocketAddress address = addressProvider.selector();
        logger.info("server address=" + address.getHostName() + ":" + address.getPort());
        TSocket tsocket = new TSocket(address.getHostName(), address.getPort(), this.timeOut);
        TProtocol protocol = new TBinaryProtocol(tsocket);
        TServiceClient client = this.clientFactory.getClient(protocol);
        tsocket.open();
        if (callback != null) {
            callback.make(client);
        }
        return client;
    }

    /**
     * 销毁对象
     */
    public void destroyObject(TServiceClient client) throws Exception {
        if (callback != null) {
            callback.destroy(client);

            try {
                TTransport transport = client.getInputProtocol().getTransport();
                if (transport.isOpen()) {
                    transport.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 检验对象是否可以由pool安全返回
     */
    public boolean validateObject(TServiceClient client) {
        try {
            TTransport transport = client.getInputProtocol().getTransport();
            if (transport.isOpen()) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    public static interface PoolOperationCallBack {
        // 创建成功前执行
        void make(TServiceClient client);

        // 销毁client之前执行
        void destroy(TServiceClient client);
    }

}
View Code
/**
 * 服务调用方使用
 * 
 * @author wy
 * 
 */
public class ThriftServiceClientProxyFactory implements FactoryBean<Object>, InitializingBean {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    
    // 最大活跃连接数
    private Integer maxActive = 32;
    // 最小空闲对象数量
    private Integer minIdle =1;
    // 链接空闲时间default 3
    private Integer idleTime = 1000 * 60 * 3;
    // 连接超时配置 
    private int conTimeOut = 1000 * 2;
    //
    private boolean testOnBorrow = true;
    //
    private boolean testOnReturn = true;
    //
    private boolean testWhileIdle = true;
    
        
    // 具体的服务接口类
    private String service;
    // fixed server address provider
    private String serverAddress;
    // dynamic server address provider
    private ThriftServerAddressProvider addressProvider;
    // 对象缓存池
    private GenericObjectPool<TServiceClient> pool;
        
    // 服务实例
    private Object proxyClient;
    // 服务接口类Iface
    private Class<?> objectClass;

    @Override
    public void afterPropertiesSet() throws Exception {
        logger.info("init objectPool...");
        
        if (serverAddress != null) {
            logger.info("FixedAddressProvider...");
            addressProvider = new FixedAddressProvider(serverAddress);
        } else {
            logger.info("DynamicAddressProvider...");
        }
        
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 加载Iface接口
        objectClass = classLoader.loadClass(service + "$Iface");
        // 加载Client.Factory类
        Class<TServiceClientFactory<TServiceClient>> clazz = (Class<TServiceClientFactory<TServiceClient>>) 
                classLoader.loadClass(service + "$Client$Factory");
        TServiceClientFactory<TServiceClient> clientFactory = clazz.newInstance();
        // PoolFactory
        AbstractThriftServiceClientFactory clientPool = new AbstractThriftServiceClientFactory(
                addressProvider, clientFactory, callback, conTimeOut);
        // 对象缓存池
        GenericObjectPool.Config poolConfig = new GenericObjectPool.Config();
        // 缓存池中分配对象的最大数量
        poolConfig.maxActive = maxActive;
        // 缓存池中最小空闲对象数量
        poolConfig.minIdle = minIdle;
        // 
        poolConfig.minEvictableIdleTimeMillis = idleTime;
        // 
        poolConfig.timeBetweenEvictionRunsMillis = idleTime / 2L;
        //
        poolConfig.testOnBorrow = testOnBorrow;
        //
        poolConfig.testOnReturn = testOnReturn;
        //
        poolConfig.testWhileIdle = testWhileIdle;
        
        pool = new GenericObjectPool<TServiceClient>(clientPool, poolConfig);
        
        // 反射,服务实例
        proxyClient = Proxy.newProxyInstance(classLoader,
                new Class[] { objectClass }, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        // 从对象池取对象
                        TServiceClient client = pool.borrowObject();
                        try {
                            return method.invoke(client, args);
                        } catch (Exception e) {
                            throw e;
                        } finally {
                            // 将对象放回对象池
                            pool.returnObject(client);
                        }
                    }
                });
    }

    /**
     * 获取服务实例,并已归还池中对象
     */
    @Override
    public Object getObject() throws Exception {
        return proxyClient;
    }
    
    /**
     * 销毁对象池
     * 
     * @throws Exception
     */
    public void destroyObject() throws Exception {  
        try {  
            pool.close();  
        } catch (Exception e) {  
            throw new RuntimeException("erorr destroy()", e);  
        }  
    }
    
    /**
     * 关闭server address provider
     */
    public void close() {
        if (addressProvider != null) {
            addressProvider.close();
        }
    }
    
    @Override
    public boolean isSingleton() {
        // To change body of implemented methods use File | Settings | File Templates.
        return true; 
    }

    @Override
    public Class<?> getObjectType() {
        return objectClass;
    }
    
    PoolOperationCallBack callback = new PoolOperationCallBack() {

        @Override
        public void make(TServiceClient client) {
            logger.info("create proxyClient...");
        }

        @Override
        public void destroy(TServiceClient client) {
            logger.info("destroy proxyClient...");
        }
    };
    
    public void setMaxActive(Integer maxActive) {
        this.maxActive = maxActive;
    }

    public void setIdleTime(Integer idleTime) {
        this.idleTime = idleTime;
    }

    public void setService(String service) {
        this.service = service;
    }

    public void setServerAddress(String serverAddress) {
        this.serverAddress = serverAddress;
    }

    public void setAddressProvider(ThriftServerAddressProvider addressProvider) {
        this.addressProvider = addressProvider;
    }

    public int getConTimeOut() {
        return conTimeOut;
    }

    public void setConTimeOut(int conTimeOut) {
        this.conTimeOut = conTimeOut;
    }

    public Integer getMaxActive() {
        return maxActive;
    }

    public Integer getIdleTime() {
        return idleTime;
    }

    public boolean isTestOnBorrow() {
        return testOnBorrow;
    }

    public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    public boolean isTestOnReturn() {
        return testOnReturn;
    }

    public void setTestOnReturn(boolean testOnReturn) {
        this.testOnReturn = testOnReturn;
    }

    public boolean isTestWhileIdle() {
        return testWhileIdle;
    }

    public void setTestWhileIdle(boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }
    
}
View Code

     spring配置文件

<!-- zookeeper -->
    <bean id="thriftZookeeper" class="com.wy.thriftpool.commzkpool.zookeeper.ZookeeperFactory" destroy-method="close">
        <property name="connectString" value="127.0.0.1:2181" />
        <property name="namespace" value="thrift/thrift-service" />
    </bean>
    <bean id="userService" class="com.wy.thriftpool.commzkpool.client.ThriftServiceClientProxyFactory" destroy-method="close">
        <property name="maxActive" value="5" />
        <property name="idleTime" value="1800000" />
        <property name="addressProvider">
            <bean class="com.wy.thriftpool.commzkpool.support.impl.DynamicAddressProvider">
                <property name="configPath" value="serviceAddress" />
                <property name="zookeeper" ref="thriftZookeeper" />
            </bean>
        </property>
        <property name="service" value="com.wy.thrift.service.UserService" />
    </bean>
View Code

 

由于本人经验有限,文章中难免会有错误,请浏览文章的您指正或有不同的观点共同探讨!

posted @ 2015-11-21 17:02  三石雨  阅读(2755)  评论(0编辑  收藏  举报