• 由浅入深了解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

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

  • 相关阅读:
    Android存储方式之SQLite的使用
    Is there a way to add a badge to an application icon in Android?
    Android SDK Manager更新失败的解决办法
    Android中的Handler机制
    解决SDK下载中遇到的“Connection to https://dl-ssl.google.com refused”问题
    Testlink使用心得
    解决Android Toast重复显示等待时间过长的问题
    Unicode和多字符集的区别
    WEB FARM NLB TEST
    win8.1驱动安装
  • 原文地址:https://www.cnblogs.com/exceptioneye/p/4983916.html
Copyright © 2020-2023  润新知