简介
Finagle是Twitter的一个开源scala框架,支持Java语言和Scala语言,支持的协议包括Apache Thrift, Kestrel, Memcached, http, redis, mysql等。由于国内的scala应用程度不高,而Twitter已经逐渐发展成为了Scala的重度使用用户。Finagle是基于NIO和netty的,主体的结构如下图:本文的目的是实践Finagle框架的thrift协议,并在底层通过JPA,Hibernate与mysql进行交互,同时利用Spring framework管理Bean。
scrooge
scrooge也是twitter开源的一个项目,项目是用scala编写的一个thrift代码生成器。我们直接下载zip包使用scrooge脚本生成代码即可。
假设我们的thrift IDL代码如下:
struct User{
1:i32 id,
2:string name,
3:i32 createdAt,
4:i32 updated
}
service UserService{
User getUser(1:i32 id),
User saveUser(1:User user),
User updateUser(1:User user)
}
使用下面的命令生成scala代码:
> scrooge -finagle demo.thrift会生成一个thrift目录,scala代码就在目录下。
maven
通过eclipse新建一个scala项目,选择scala-archetype-simple,创建一个带maven支持的scala项目。
记得enable maven支持的同时,选中scala菜单的添加scala特性,否则不会编译。
需要调整pom中的scala版本和本地scala版本一致。
Finagle
拷贝scrooge生成的代码到工程中,并新建ThriftServer和ThriftClient两个scalaObject。
代码ThriftServer.scala
object ThriftServer {
def main(args: Array[String]) {
val protocol = new TBinaryProtocol.Factory()
val ctx = new ClassPathXmlApplicationContext("applicationContext.xml")
val userService = ctx.getBean("userService").asInstanceOf[UserService.FutureIface]
val server = new UserService.FinagledService(userService, protocol)
val address = new InetSocketAddress("localhost", 9000)
var builder = ServerBuilder()
.codec(ThriftServerFramedCodec())
.name("UserService")
.bindTo(address)
.build(server)
}
}
代码ThriftClient.scala:
新建一个实现类,并调用了封装的dao层代码:
object ThriftClient {
def main(args: Array[String]) {
val service = ClientBuilder()
.hosts(new InetSocketAddress("localhost", 9000))
.codec(ThriftClientFramedCodec())
.hostConnectionLimit(100)
.build()
val client = new UserService.FinagledClient(service)
val user = client.getUser(10)
println("getUser-->"+user.apply())
val user1 = client.saveUser(user.apply());
println("save db-->"+user1.apply())
}
}
ThriftServer中使用了spring管理了userService。新建一个实现类,并调用了封装的dao层代码:
class UserServiceImpl extends FutureIface {
@BeanProperty
var dao:Dao = null
def getUser(`id`: Int): Future[User] = {
val currentTime = (System.currentTimeMillis() / 1000).asInstanceOf[Int];
var user = if (id == 0) null else User.apply(id, "wenfeng", currentTime, currentTime)
Future.value(user)
}
def saveUser(`user`: User): Future[User] = {
var u = new com.scala.core.User(user._1, user._2, user._3, user._4)
try{
val id = dao.save(u)
u.setId(id.asInstanceOf[Long]);
}catch{
case ex:DalException => ex.printStackTrace()
}
println("save user-->"+user)
val res = User.apply(u.getId().asInstanceOf[Int],
u.getName(), (u.getCreatedAt() / 1000).asInstanceOf[Int],
(u.getUpdated() / 1000).asInstanceOf[Int])
Future.value(res)
}
def updateUser(`user`: User): Future[User] = Future.value(user)
}
Spring的配置文件:<beans xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:sca="http://www.springframework.org/schema/sca" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/sca http://www.osoa.org/xmlns/sca/1.0/spring-sca.xsd">
<context:component-scan base-package="com.scala">
<bean class="com.scala.dao.impl.DaoImpl" id="dao">
<bean class="com.scala.service.impl.UserServiceImpl" id="userService">
<property name="dao" ref="dao">
</property></bean>
</bean></context:component-scan></beans>
新建一个JPA的User类,使用scala的@BeanProperty 生成getter和setters@Entity
@Table(name="user")
class User extends java.io.Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@BeanProperty
var id:Long = _
@Column(name="name")
@BeanProperty
var name:String = _
@Column(name="created_at")
@BeanProperty
var createdAt:Long = _
@Column(name="updated")
@BeanProperty
var updated:Long = _
def this(id:Long, name:String, createdAt:Long, update:Long) = {
this()
this.id = id
this.name = name
this.createdAt = createdAt
this.updated = updated
}
override def toString() = "User["+id+","+name+","+createdAt+","+updated+"]"
测试插入一条用户数据,查看log和DB后,发现数据已经成功写入DB。
没有评论:
发表评论