技术专题报告-JFinal

公司做技术专题,这一期选择的JFinal,历时两天多完成,特将研究结果贴上来,其中难免有不妥之处,多多沟通交流,个人认为JFinal是非常好的一个框架,在某些应用场景下是很不错的选择!

===============正文开始===============

1. JFinal简介

1.1. 摘自官方:

http://www.jfinal.com/

JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python、php等动态语言的开发效率!为您节约更多时间,去陪恋人、家人和朋友 :)

1.2. 个人总结

主要实现功能类似现在流行的SSM框架,只是在开发变成方式上和运行速度上有区别,强调开发速度和运行速度快。

1.3. 主要技术

和其他主流技术对比

层次

JFinal

JEECG

普通框架

后台接口

前端

Enjoy/Freemarker

Freemarker

JSP+JQuery+EasyUI

控制层

JFinal Controller

SpringMVC

SpringMVC

SpringMVC

IOC容器

Spring

Spring

Spring

ORM

ActiveRecordPlugin

Hibernate

MyBatis

MyBatis

2. 研究原因

现有Spring为核心的技术框架已经比较普及,但在某些情况下存在开发速度慢,不灵活的问题(通过JEECG可解决代码创建时候的速度问题),听说过JFinal的极速开发,这次一探究竟,使用如下业务场景进行“代码量”和“开发速度”方面的比对测试:

开发新功能(前台+后台)-产品管理-单表

后台接口(获取警报)

增加一个字段

增加一个业务接口

修改业务逻辑

3. JFinal主要特点

官方API参考:

http://www.jfinal.com/doc

3.1. 总体架构

参考JFinal文档

上图看似简单,其实好多功能是在Plugin中实现,包括ORM,Cache等功能

3.2. 快速上手(以Maven为例)

1) 开发环境选择:

通用Maven

特定开发环境Eclipse、IDEA

Eclipse插件JBolt

2) 配置:数据库参数,Maven

3) 启动

内置Jetty:一般开发使用,速度快,打开开发模式会打印详细日志和进行热加载

外部Tomcat:一般生产环境使用,关闭开发模式

3.3. 配置参数:JFinalConfig

此处是各种配置参数的入口,每个Project需实现此抽象类,并在web.xml中作为filter的参数进行配置,系统在启动的时候会初始化此类并进行调用,完成运行参数的配置。

1) 常量配置(constant):一些系统使用的全局参数配置,比如开发模式(devMode),日志工厂等

2) 路由配置(route):主要功能类似SpringRequestMapping,将URL和类关联起来,此处配置类级别的路径;可添加多个Route,每个Route可设置自己的路径;可添加route级别的拦截器

3) 模板引擎配置(engine):模板可包括HTML模板和SQL模板,以及其他用途的模板,此处配置模板引擎的全局参数.

4) 插件配置(plugin):各种插件注册到系统,例如数据库插件,EHCacheRedis.

5) 拦截器配置(interceptor):此处添加全局的拦截器,类和方法的拦截器在Class中设置.

6) 处理器配置(handler):handler类似Spring中的mappingHandler,除了系统默认的Handler,可以增加自己的Handler,在HTTP请求的过程中进行干预,做修改数据等操作.

相比SpringMVC:

方式不同,效果相同,相比Spring的xml,如果配置出现问题在Java代码里面应该更好查找,因为可以debug:),相反XML文件则相对复杂,但如果是在生产环境需要修改的配置参数,还是需要独立为properties文件,因为在生产环境不能通过修改源代码来修改配置

3.4. 控制器:Controller

此和SpringMVC的Controller作用基本相同,主要作为前端和后端应用之间的控制层存在

3.4.1. URL路径映射

类路径:和SpringMVC不同,JFinal不用注解实现路径映射,类的base路径在JFinalConfigroute设置

类方法路径:类中所有public的方法自动映射为二级路径,直接访问类路径(例如/goods)会执行类的index()方法

相比SpringMVC:无大差别,实现只是省略了方法级别的注释

3.4.2. 获得业务数据

在Controller的方法中获得业务数据通常有以下方法,不用使用注解

Action参数注入:增加相关Bean类型的参数作为方法的参数,则自动生成相关Bean,此需要JDK8支持,打开“保留方法参数”的编译参数

getPara():可使用此类函数获得所有参数

getModel()/getBean():从request里面生成相关业务beangetModel()用于没有getter/setter方法的bean,要求request参数名和数据库字段名相同; getBean()则需要有相关方法,要求request参数名和beanget/set属性名相同

相比SpringMVC:无大差别,最大差别在于此处支持没有getter/setter方法的bean,但是此和面向对象原则相违背,不过这样更简洁,看个人各取所需

3.4.3. 返回数据

原生render*()接口,基本支持返回大部分数据类型的接口:HTML,JSP,Enjoy模板,Freemarker模板,Velocity模板,二维码,json,返回错误信息

renderJson*(): 返回json提供若干个个接口,供不同需要进行选择,并且提供四种json转换框架JFinalJsonFastJsonJacksonMixedJson(JFinalJson+FastJson)供选择,默认使用JFinalJson,如需改变在configConstant()中使用setJsonFactory()修改

自定义的render:rendernew MyRender()

相比SpringMVC:实现功能相同,但是易用性,简单性较强

扩展性方面:Spring可以对接各种ViewResolverMessageConverter,只是需要进行额外的xml配置,JFinal则直接定义class,方法简单粗暴,比较容易使用

3.5. AOP

1) 拦截器

可使用注解@Before和@Clear进行拦截器的使用,和SpringMVC类似

2) 对象注入

目前在Controller中可使用@Inject注入业务对象

相比SpringMVC:实现基本需要使用的功能,没有Spring复杂,简单易用,可满足一般需要

3.6. Service层

JFinal没有明确的提出Service层,在小型项目中,如果追求简介和快速,各业务之间逻辑重用不多的情况下,可将数据库访问调用代码直接在Controller完成,否则需要构建Service层访问数据库实现业务逻辑

3.7. DAO层:ORM

此节主要阐述JFinal在数据库ORM方面的概念和使用方法,并和SpringJdbcTemplate以及MyBatis进行对比

JFinal的ORM使用ActiveRecordPlugin实现,其特点是灵活,简单,使用方便,编码量少

3.7.1. 数据Bean

3.7.1.1. SSM中的贫血模式

数据Bean,在SSM中我们 一般都称之为POJO,也就是只是一个数据承载对象,不包含业务逻辑,即所谓的“贫血模式”,在此模式下,优点是所有业务逻辑集中在Service层,这样分层比较清晰,缺点是不太符合面向对象的原则。

3.7.1.2. JFinal中的充血模式

在JFinal中,数据Bean不是一个简单的POJO,其包含了后台的所有数据库操作,简单理解所有的CRUD操作都不用使用DAO来完成,其自身具备此能力,即所谓的“充血模式”,在此模式下,优点是面向对象,缺点是业务逻辑分散在BeanService层,代码不太清晰

3.7.1.3. JFinal中的Bean特点

3.7.1.3.1. 代码简化,编码加快

所有后台逻辑和参与数据库操作的操作可直接通过Bean来完成,在某些情况下极大简化了代码,例如:

empoyee.set(code,A001).set(name,张三).save()

1行代码完成了一般3行的功能

3.7.1.3.2. 不需要设置属性,没有getter/setter

Bean不需要每个属性增加get/set方法,包括从ORM取数,Controller中的Bean生成,传给ORM进行数据更新等阶段的操作,都可使用此种Bean,此极大的简化了传统Bean需要大量Set/Get方法,不需要进行字段的mapping配置,取到对象后直接使用。

实现方式

后台使用Map采用key/value的方式存储数据,可使用get*(fieldName),set*(fieldName,fieldValue)操作属性值,其中字段名和数据库表字段名相同

此种方式的缺点(如果单纯考虑开发速度,以下不算缺点)

所有字段名为数据表的字段名,一方面不好记忆,另一方面数据库表字段的命名方式(下划线分隔)一般和Java属性(驼峰)不同,容易造成混淆

不符合面向对象的原则,对一些第三方框架(需要通过get读取属性等)不兼容,JFinal最新版本目前已经提供从数据库直接按照表结构生成具有getter/setter方法的基础对象

3.7.1.4. Bean和Controller的生成工具

JFinal示例程序中的_JFinalDemoGenerator使用active recordGenerator根据数据库表生成相关的BaseBeanBeanBaseBean为具有getter/setter方法的类,Bean只是继承BaseBean,无其他代码。

相比MyBatis:Java beanMytatis简单,只需要继承JfinalModel即可实现setter/getter以及和数据库表列的映射。

3.7.2. 查询数据

3.7.2.1. 普通查询

Bean直接提供了一系列的find方法用于查询数据,返回的ListBean可直接返回给前台

new Bean().dao().find*(sql,params)

3.7.2.2. 分页查询:

Bean直接提供了一系列的paginate方法用于进行分页数据查询,返回的ListBean可直接返回给前台

new Bean().dao().paginate*(sql,params)

3.7.2.3. 缓存查询:

 相比MyBatis:SQLMybatis更灵活,和jdbcTemplate相仿,但是比jdbcTemplate多了自动封装返回数据,SQL语句可直接写在代码里面或者使用模板独立于程序,另外JFinal提供封装好的Cache查询接口。

3.7.3. 更新数据

插入数据:bean.save()

修改数据:bean.update()

删除数据:bean.deleteById(id)

相比MyBatis:同”查询数据“。

3.7.4. 通用方式:Db+Record

JFinal提供类似Spring JDBCTemplate的方式,可直接操作数据库,不依赖于具体的Bean,其模式称之为Db+Record

Db:相当于Dao,提供数据访问接口

Record:类似通用的Bean,用于数据承载,数据操作需要通过Db的接口来完成

相比JdbcTemplates:和jdbcTemplate相仿,但是比jdbcTemplate多了自动封装返回数据,提供封装好的Cache查询接口。

3.7.5. 复杂SQL

 JFinal利用自带的Template Engine极为简洁的实现了Sql管理功能。

可将复杂SQL独立存储到单独文件中,其使用方式类似于MyBatis,但是更简单。

相比myBatis:和myBatis类似,使用模板语言实现。

 

3.7.6. 事务(Db.tx)

3.7.6.1. 声明式事务

3.7.6.1.1. 方法声明事务

事务的实现采用拦截器实现,在相关需要事务控制的方法增加”@Before(Tx.class)“即可,另外也提供按照方法名,类名等进行精细控制的事务

3.7.6.1.2. configInterceptor()支持正则表达式和多个Controller&方法控制事务

3.7.6.2. 代码直接处理事务

可添加一段Java代码控制事务:Run()方法里面发生异常,或返回false,事务都会自动回滚

 相比spring:基本类似,都是使用AOP的注解和事先配置(JFinal-拦截器;Spring-XML)实现。

3.8. 模板

JFinal在页面端的实现,类似于Freemarker, 据其测试报告,性能比Freemarker&Velocity快很多,没有深入研究。

3.9. EHCachePlugin

提供的EHCache插件,可提供如下缓存机制:

1)CacheInterceptor提供方法级别的拦截器Controller的某个Action进行Cache

2)CacheKit提供工具级别的缓存工具,get/put进行缓存数据的管理

3.10. RedisPlugin

提供RedisPlugin在JFinalConfig注册完毕后即可使用Redis类进行Redis缓存操作,后台使用jedis客户端实现和redis服务器交互

3.11. 任务调度Cron4jPlugin

任务调度使用Cron4J, 你也可实现自己的任务Plugin,例如quartzJFinal使用Cron4j的原因应该是Cron4J的小巧和不依赖于任何第三方框架

如果使用分布式的任务调度,则需要使用更复杂的任务调度框架来完成,例如Quartz,Elastic-Job

3.12. 数据验证Validator

Validator可对Controler某个Action的数据进行验证,其实现原理就是拦截器,在Controller的方法上面增加@Before注解即可实现

首先继承Validator定义自己基于某个Controller的验证代码,例如EmployeeValidator.java

使用@Before(EmployeeValidator.class)修饰相关Controlleraction方法

 

4. 业务场景测试

4.1. 开发新功能(前台+后台)-产品管理-单表

1. 根据需求进行分析,建立数据库表goods

2. 规划JFinal程序:

包名:com.demo.base.goods

类:Goods,GoodsControlerGoodsServiceGoodsValidator

Web目录:base/goods

3. 使用_JFinalDemoGenerator从数据库生成BaseGoodsGoods

4. 建立相关的Controller和前端页面(jsp或者相关模板)

4.2. 后台接口(获取警报)

1. 规划JFinal程序:

包名:com.demo.ded.api.alert

类:Alert,AlertController

2. 规划JFinal程序:

包名:com.demo.api.alert

类:Alert,AlertControler

对外接口路径:/alert/get/#,其中”#“为相关的alert id

3. 从Model继承,建立Alert

4. 对AlertControler进行编码,增加get方法,使用renderJson()返回数据

4.3. 增加一个字段

1. 修改数据库表结构,增加字段

2. SQL中增加此列名

3. 如果有页面,页面中增加此列的显示

SSM:除了以上工作还需要增加:修改Bean,修改Bean字段映射XML

4.4. 增加一个业务接口

Controller中增加接口即可,如以Service为业务逻辑点,则还需要在Service中增加接口

SSM:需要增加接口道ControllerServiceServiceImplDaoMyBatisMappingXML

4.5. 修改业务逻辑

直接修改相关Controller或Service层的代码

5. 研究结果

根据不同技术的自身特点,列出研究结果

5.1. 优点

5.1.1. 使用简单,上手快

因为不涉及太多复杂的概念,没有那么多XML的配置项,不管有没有Spring基础,即使是新手,上手也会很快

5.1.2. 后期维护简单

后期增加或修改业务逻辑的时候,代码修改简单

5.1.3. 运行速度快

号称“jfinal 性能是 spring + mybatis 的 4.56 

https://www.oschina.net/news/90815/jfinal-3-3

https://gitee.com/jfinal/jfinal-performance

5.1.4. 扩展性好

采用plugin机制

根据标准接口,扩展相关插件

5.2. 缺点

5.2.1. 插件没有Spring丰富,有些情况需要自己开发插件对接第三方开源插件

5.2.2. JFinal周边生态链框架弱

周边已经形成一定数量的外围框架,但是不如Spring丰富,选择性较少

5.2.3. 缺乏大项目案例,虽然架构上理论可支持,但是缺乏公开的实践

6. 公司可利用范围

6.0.1. 一些小型项目可以使用,尤其是时间比较紧张的时候,不过仍需对其进行一定的包装,例如类似jeecg的代码生成机制

6.0.2. 大型项目目前不宜使用,可在一些小型项目的经验基础上,逐渐推广使用

 



评论区

JFinal

2018-10-26 16:40

部分知识点总结得简单到位,很不错

有一些地方有所误解,这类总结其实是一个相当庞大的话题,时间关系,在此仅作一个极小的补充:

0:最最重要一点就是:一定要有业务层、一定要有业务层、一定要有业务层。就算业务再简单,项目再小,也一定要有业务层。jfinal 官网的 demo 都是有业务层的。

jfinal 作为一个框架存在,本质目标就是将用户尽可能从具体技术中解放出来,尽可能将精力放在业务功能的实现上。 如果连业务层都没有,那可是极大远离了框架存在的目标。

是否存在业务层不是框架可以限定死的,在使用 Spring 的时候,你也可以将业务写在 controller 中,这个是 spring 永远无法强制你不去这样做的。

所以 "jfinal 没有明确的提出Service层" 这个不能成为一个问题,因为没法控制用户是否要将业务写在 controller 这个行为

1:IOC 容器本质是用于对目标对象注入代理类,从而实现 AOP。而 jfinal 没有 IOC 却更简洁实现了 AOP,所以没有 IOC 其实是一个优点,而不是缺点。这个是 jfinal 有意为之的。如无必要,勿增实体这个是设计的基本原则

2:jfinal 建议 Model 是贫血领域模型,也就是 Model 只承载数据,不要写任何业务,所有业务都要放在业务层,无论你的项目有多少都要这样做。

当然,如果开发者将 Model 用成充血领域模型,站在 jfinal 的角度是无法干预到的,就像是开发者在使用 Spring 的时候将 Model/Bean 用成充血领域模型,一样也无法干预。 是否充血与贫血这个完全取决于开发者自己怎么去用

3:最后一个重要问题就是 jfinal 非常适合在大型中使用,我跟我同事用 jfinal 开发的项目规模已经相当大,比起先前的 SSM 版本,20 台机器减少到 12 台,跑了超过三年,跑得又快又稳

记住:简洁的力量是无比强大的

山东小木

2018-10-26 17:52

很多项目都是后台管理的 所以没法公开 亿万流量的应用你可以看看jboot微服务框架

fansunion

2018-10-26 18:46

收藏了

金辉

2018-10-27 11:38

写的确实透彻

jiren

2018-10-27 13:07

生态问题又被提到, 确实应该 发发力

混世侃

2018-10-27 19:20

simple_john

2018-10-29 09:28

@山东小木 您那边有吗?可以隐去项目名字和实际数据,给大家介绍一下,JBoot有空研究下,看介绍很不错

山东小木

2018-10-29 09:42

@simple_john ERP OA CRM 大型亿万级游戏后台数据监控 系统 金融 航空 智慧城市 都在用

ddjfinal

2018-11-05 12:09

已经在公司的多个项目中实战应用,性能绝对没有问题,关键是开发效率高,维护方便,特别是orm比mybatis那一套好太多,另外模板引擎的话,enjoy用的太爽了,之前一直在用freemarker,现在公司另外的一个项目,springmvc+mybatis+enjoy做的,起码,我觉得模板这一块,enjoy自由灵活太多。你如果习惯用enjoy的话,jsp你是再也不想碰的东西了!生态确实不如spring,但目前我们还没有用到必须在springmvc下使用的插件。

simple_john

2018-11-06 10:08

@JFinal 今天回来看了下看到了这么详细的回复,赞一个!
"jfinal 没有明确的提出Service层" :这个我没说是缺点,这个不是框架能决定的,是架构的问题,我认同业务层一般都应该存在的观点,现在的大多数程序员上来都是套框架,一般是不会丢掉Service层的
1."没有IOC容器”:我没说这个是缺点,抛弃容器实现相同功能是更好的实现
2.jfinal 建议 Model 是贫血领域模型
这个问题,因为JFinal的Model对象已经是充血模型,起码数据库端所有的操作都是在这个对象可访问到的,这个我是认同的,极大简化并加快了开发代码
3.相信jfinal可在大型项目中应用,加油!
最后,来研究JFinal就是因为简洁,从简化开发的角度看,这些特点我都非常认同!
顺便说下,我正在项目中使用一些JFinal的小工具,例如PropKit,Db+Record,就是整体不用JFinal,这些非常好用的工具类也可以使用

simple_john

2018-11-06 10:11

@山东小木 有空多请教,netty你们嵌入到JFinal里面使用过吗?

山东小木

2018-11-06 11:54

@simple_john 欢迎加我QQ 909854136 或者加入JFinal学院 www.jfinalxueyuan.com 这里有学院群 大咖云集 jfinal开源项目和商业项目 成熟产品 都有 欢迎交流

热门分享

扫码入社