代码拉取完成,页面将自动刷新
用netty + scala 写的一个简易web框架.支持路由(相当于@RequestMapping
),支持返回值: string
,json对象
,byte[]
.自用,轻量级,启动只需要2秒,占用20m的堆.
做这个小框架的初衷是,自家云服务器的内存只有256M.实在是承受不起spring-web的占用.
况且我只是想要个简单的rest-api而已.web容器那些强大的功能我根本用不上.所以就打算自己写一个web服务器.
╮( ̄▽ ̄)╭ 算是练手吧.对java8特性了解比较深的话上手scala还是很快的.好多scala的特性在新的jdk里面也有啦.
总共两百多行代码.用到了很多scala的特性.比如traint,lambda,模式匹配,caseClass 换成jdk7实现估计怎么也得1000行以上吧.
使用了Google-Guice作为依赖注入,
Reflections扫描指定路径下的Mappings
,
JSON转换用了FastJSON(自己写着玩,用着爽就完事了)
启动类: com.mina.spider.Application.main
核心类:Dispatcher.scala
@Singleton
class Dispatcher {
private[this] val log = LoggerFactory.getLogger(this.getClass)
private[this] val allocator = UnpooledByteBufAllocator.DEFAULT
private[this] var mapping: mutable.Set[MappingCase] = _
@Inject
def this(scanner: MappingScanner) {
this()
mapping = scanner.routerMapping(Constant.mappingPackage)
}
def dispatch(req: FullHttpRequest): Option[DefaultFullHttpResponse] = {
log.debug("dispatch uri :{}", req.uri())
mapping
.find(x => x.pattern.matches(req.uri()) && x.method == req.method.toString.toUpperCase)
.map(_.mappings)
.flatMap(routingTo(req, _))
.orElse(strResponse(str = Constant.NOT_FOUND, status = HttpResponseStatus.NOT_FOUND))
}
private def routingTo(req: FullHttpRequest, mapping: Mappings): Option[DefaultFullHttpResponse] = {
try {
mapping.execute(req).flatMap {
case str: String => strResponse(str)
case bytes: Array[Byte] => response(allocator.heapBuffer(bytes.length).writeBytes(bytes), contentType = "application/octet-stream")
case ref: AnyRef => Option(ref).map(JSON.toJSONString(_)).flatMap(strResponse(_, contentType = "application/json"))
case _ => strResponse("null")
}
} catch {
case e: Exception =>
log.error("execute mapping error:\r\n", e)
strResponse(str = Option(e.getMessage).getOrElse("exception with 417"), status = HttpResponseStatus.EXPECTATION_FAILED)
}
}
...
http服务启动类:HttpServer.scala
@Singleton
class HttpServer {
private[this] val log = LoggerFactory.getLogger(this.getClass)
private[this] val bossGroup = new NioEventLoopGroup()
private[this] val workerGroup = new NioEventLoopGroup()
@Inject
private[this] var channelIn: HttpChannelInitializer = _
@throws[InterruptedException]
def start(): Unit = {
try {
log.info("------ http server starting..")
val serverBootstrap = new ServerBootstrap
serverBootstrap
.group(bossGroup, workerGroup)
.channel(classOf[NioServerSocketChannel])
.childHandler(channelIn)
.option(ChannelOption.SO_BACKLOG.asInstanceOf[ChannelOption[Any]], 128)
.childOption(ChannelOption.SO_KEEPALIVE.asInstanceOf[ChannelOption[Any]], true)
.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(Constant.MIN_BUFFER_SIZE, Constant.INITIAL_BUFFER_SIZE, Constant.MAXIMUM_BUFFER_SIZE));
val channelFuture = serverBootstrap.bind(Constant.iNetPort).sync
log.info("------http server started,port:" + Constant.iNetPort)
channelFuture.channel.closeFuture.sync
} finally {
workerGroup.shutdownGracefully()
bossGroup.shutdownGracefully()
}
}
...
mapping映射类扫描器:MappingScanner.scala
@Singleton
class MappingScanner {
private val log = LoggerFactory.getLogger(this.getClass)
val injector: Injector = Application.injector
def routerMapping(packageName: String = "*"): mutable.Set[MappingCase] = {
val reflections: Reflections = new Reflections(packageName)
log.info("scan mappings,package:{}", packageName)
CollectionConverters.SetHasAsScala(reflections.getTypesAnnotatedWith(classOf[HandlerMapping]))
.asScala
.map(k => {
val mapping = k.getAnnotation(classOf[HandlerMapping])
MappingCase(mapping.httpMethod(), injector.getInstance(k).asInstanceOf[Mappings], methodMatcher(mapping))
})
}
private def methodMatcher(mapping: HandlerMapping): Regex = ("^" + mapping.value() + "$").r
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。