GenericObjectPool实现了线程池中的对象回收和管理等功能(spark-mysql)

package sparkstreaming


import java.util.Properties

import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}
import poolutils.MysqlPool
object Spark_Mysql extends App{

  val conf = new SparkConf().setAppName("demo").setMaster("local[*]")
  val sc = new SparkContext(conf)
  val ssc =  new StreamingContext(sc,Seconds(5))
  //读取配置文件
  val pro = new Properties()//配置项
  pro.put("jdbc","jdbc://localhost:3306/iql?user=root&password=root")
  val pool = MysqlPool(pro)//这里调用了 mysqlpool的 GenericObjectPool方法,返回一个可以管理的对象池的所有操作
  //即创建对象,销毁对象,借出对象的一系列操作

  //创建一个Socket输入流,
  ssc.socketTextStream("localhost",12345).foreachRDD(rdd=>{
    rdd.foreach(f=>{
      //borrowObject方法就是:拿到一个MysqlProxy实例
      val mysqlProxy = pool.borrowObject()//====这里是线程池操作
      val con = mysqlProxy.conn//获取连接
      //预编译,
      //需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度
      val cs = con.prepareStatement("insert into s values (?)")//===从这里开始都是mysql数据操作
      //给第一个问好赋值为f
      cs.setString(1,f)
      //execute 方法返回一个 boolean 值,判断第一个结果的形式
      // 如果是查询的话返回true,如果是更新或插入的话就返回false了;
      cs.execute()
      cs.close()//===到这里结束 数据库操作结束
      //returnObject方法:归还对象到线程池
      pool.returnObject(mysqlProxy)//===这里是线程池操作

    }
    )
  })
  ssc.start()
  ssc.awaitTermination()
}

======================================
package sparkstreaming.poolutils

import java.sql.DriverManager
import java.util.Properties

import org.apache.commons.pool2.{BasePooledObjectFactory, PooledObject}
import org.apache.commons.pool2.impl.{DefaultPooledObject, GenericObjectPool, GenericObjectPoolConfig}
import poolutils.HBasePool

/**
  * 基于commons-pool2编写MySQL的连接池
  * GenericObjectPool <T> 实现了ObjectPool<T> 具备对象池的功能,
  * 同时 继承了BaseGenericObjectPool<T> 的对于对象状态管理和回收等功能
  * 构造函数通过GenericObjectPoolConfig 和PooledObjectFactory来进行参数的初始化和对象工厂类的引入
  *
  * 自我理解
  * 1首先我们拿到了一个传来的mysql的jdbc连接,然后我们使用一个方法MysqlProxy连接上我们的mysql,在里面我们提供了shutdown的方法方便后面使用
  * 2.我们创建了继承了BasePooledObjectFactory的一个MysqlProxyFactory方法,里面我们只需要实现来个方法即create和wrap方法,当然我们自己实现了
  * 一个销毁的方法destroyObject(这里我还不清楚用在什么时候).
  * 3.以上的步骤都是为了我们的apply的方法,里面的一个类是GenericObjectPool(很重要),这里我们需要俩个参数
  * 分别是连接池的一个配置属性的方法(GenericObjectPoolConfig)和一个对连接池的创建,删除和销毁的方法(MysqlProxyFactory)
  * 当我们拿到了 以上俩个参数后 我们即可返回给Spark_Mysql一个连接池的实例pool
  *
  * GenericObjectPool:采用LIFO/FIFO结构实现ObjectPool接口,池的默认行为是一个LIFO,这就意味着,当池中有空闲可用的对象时,调用borrowObject方法会返回最近(“后进”)的实例.
  * 如果LIFO策略在池中是false的,实例的返回按相反的顺序,-先进 - 先出.(这里我们没有配置所以是lifo结构)(主要的就是使用的这个功能!!)
  *
  * GenericObjectPool的构造方法共有七个,最简单的一个是GenericObjectPool(PoolableObjectFactory factory).仅仅指明要用的PoolableObjectFactory实例,其它参数则采用默认值(这里我们用的实例是MysqlProxy类)
  *
  */

object MysqlPool {

  //第三步,GenericObjectPool实现了线程池中的对象回收和管理等功能,这里我们先建立一个实例,用于返回给Spark_Mysql类的调用
  private var pool:GenericObjectPool[MysqlProxy]=_

  def apply(pro:Properties):GenericObjectPool[MysqlProxy]={//这里传来的参数就是"jdbc","jdbc://localhost:3306/iql?user=root&password=root"
    HBasePool.synchronized{
      if (null == pool){

        //①这里是GenericObjectPool的参数之一,传来参数为"jdbc","jdbc://localhost:3306/iql?user=root&password=root"
        val poolFactory = new MysqlProxyFactory(pro)//在这里我们拿到了工厂的实例,即可以创建(create),包装(wrap),销毁(destroyObject)

        //②这里是GenericObjectPool的参数之二,我们要配置的连接池的属性,
        val poolConfig={
          //参数的初始化
          val c = new GenericObjectPoolConfig
          //最大连接数,默认为8
          c.setMaxTotal(5)
          //最大空闲链接数,默认也为8
          c.setMinIdle(5)
          c
        }
        //③此时我们已经将俩参数 MysqlProxyFactory(pro) 和 GenericObjectPoolConfig添加到GenericObjectPool 即拿到了实例,然后返回给调用者
        pool = new GenericObjectPool[MysqlProxy](poolFactory,poolConfig)//①② GenericObjectPool实例,GenericObjectPool类已经实现了和对象池有关的所有核心操作,开发者可以通过继承或者封装的方式来使用它.通过此构造函数,
        // 我们能够清晰的看到,一个Pool中需要指定PoolableObjectFactory 实例,以及此对象池的Config信息.PoolableObjectFactory主要用来"创建新对象",比如当对象池中的对象不足时,可以使用 PoolableObjectFactory.makeObject()方法来创建对象,并交付给Pool管理.
        //此构造函数实例化了一个LinkedList作为"对象池"容器,用来存取"对象".此外还会根据timeBetweenEvictionRunsMillis的值来决定是否启动一个后台线程,此线程用来周期性扫描pool中的对象列表,已检测"对象池中的对象"空闲(idle)的时间是否达到了阀值,如果是,则移除此对象.
      }
      pool
    }

  }

}

//第一步先是获取了连接创建driver驱动,
case class MysqlProxy(pro:Properties) {

  lazy val conn = {//懒加载机制 调用时启动 此步骤为拿到jdbc的连接
    //获取jdbc连接
    classOf[com.mysql.jdbc.Driver] //反射机制 拿到连接mysql的实例
    //getProperty方法:用指定的键在此属性列表中搜索属性(value)
    val jdbc = pro.getProperty("jdbc")
    //DriverManager是驱动的管理类,通过重载的getConnection()方法获取数据库连接,较为方便
    DriverManager.getConnection("jdbc")//连接到mysql
  }
  //关闭客户端
  def shutdown()= {conn.close()}//这里提供一个shutdown的方法在工厂中被调用,后期被apply方法使用以传回实例给Spark_Mysql使用
}

/*第二步
注解 先创建工厂的实例
@PooledObjectFactory,是一个池化对象工厂接口,定义了生成对象、激活对象、钝化对象、销毁对象的方法
如果需要使用Commons-Pool,那么你就需要提供一个PooledObjectFactory接口的具体实现
一个比较简单的办法就是,继承BasePooledObjectFactory这个抽象类,而继承这个抽象类,只需要实现两个方法:create()和wrap(T obj)
实现create()方法很简单,而实现wrap(T obj)也有捷径,可以使用类DefaultPooledObject

此MysqlProxyFactory方法继承 BasePooledObjectFactory的目的是为了生成,激活,钝化,和销毁对象的方法,
这里我们只需要实现一个create方法和wrap方法 还有一个销毁的方法 目的是为了后续的使用(这里我还不确定在哪里使用)
 */

class MysqlProxyFactory(pro:Properties)extends BasePooledObjectFactory[MysqlProxy]{//泛型为mysqlproxy
  //实现create方法:创建一个MySQLproxy实例
  override def create(): MysqlProxy = MysqlProxy(pro)
  //对实例进行封装
  override def wrap(obj: MysqlProxy): PooledObject[MysqlProxy] = new DefaultPooledObject[MysqlProxy](obj)
  //归还对象到线程池是通过returnObject方法实现,简单而言就是先调用validateObject方法判断该对象是否是可用的,
  // 如果可用则归还到池中,LinkedList容器加一,如果是不可以的则则调用destroyObject方法进行销毁。
  override def destroyObject(p: PooledObject[MysqlProxy]): Unit = {
    p.getObject.shutdown()
    super.destroyObject(p)
  }

}

==========================================

package poolutils

import org.apache.commons.pool2.{ BasePooledObjectFactory, PooledObject}
import org.apache.commons.pool2.impl.{DefaultPooledObject, GenericObjectPool, GenericObjectPoolConfig}
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client.{ConnectionFactory, Table}

//habse和mysql一个套路 ...
object HBasePool {
  private var pool:GenericObjectPool[HBaseProxy]= _

  def apply (quorum:String ,port:String ):GenericObjectPool[HBaseProxy]={
    HBasePool.synchronized{
      if (null == pool){
        val poolFactory = new HBaseProxyFactory(quorum,port)
        val poolConfig = {
          val c = new GenericObjectPoolConfig
          //最大连接数
          c.setMaxTotal(5)
          //最大空闲连接数
          c.setMaxIdle(5)
          c
        }
        pool = new GenericObjectPool[HBaseProxy](poolFactory,poolConfig)
      }
      pool
    }
  }

}
case class HBaseProxy(quorum:String ,port:String){
  //懒加载连接,调用时启动
  lazy private val conn ={
    val config  = HBaseConfiguration.create()
    config.set("hbase.zookeeper.quorum", quorum)
    config.set("hbase.zookeeper.property.clientPort", port)
    //
    ConnectionFactory.createConnection(config)
  }
  //获得表:
  def getTable (tablename :String ):Table ={
    conn.getTable(TableName.valueOf(tablename))
  }
  //关闭客户端
  def shutdown():Unit=conn.close()
}

//这个类是创建池的对象的工厂类
class HBaseProxyFactory(quorum: String, port: String)extends BasePooledObjectFactory[HBaseProxy]{
  //创建实体:
  override def create(): HBaseProxy = HBaseProxy(quorum,port)
  //包装实体
  override def wrap(obj: HBaseProxy): PooledObject[HBaseProxy] = new DefaultPooledObject[HBaseProxy](obj)

  override def activateObject(p: PooledObject[HBaseProxy]): Unit = {
    p.getObject.shutdown()
    super.activateObject(p)
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值