基于Java语言开发的一套轻量级框架,亲手实现JSON/XML解析、服务容器、服务框架、字节码工具等解决方案,学习成本低,即插即用,扩展性高,更加轻量级!
NoFramework是笔者在闲暇之余写的一个网络爬虫项目Seeker一路延续发展到后来的No系列的框架的诞生。一路走来,不知不觉已经快一年了,这期间有些项目有的被重写过,有的架构也发生了大的改变,还有的一直在调优过程中转变着解决方案,在付出时间的同时,获得的回报是独立思考过程带给自己的对底层细节的了解。
Seeker
No
很多人很疑惑于它的作用,在这里诠释一下:
它可以代替tomcat、spring、mybatis来帮助开发者进行web服务搭建!
您使用这套框架的好处是:
可直接与作者沟通交流 可参与框架的开发 能够感受到使用国产框架的魅力
可直接与作者沟通交流
可参与框架的开发
能够感受到使用国产框架的魅力
Java界的很多框架原理都很简单,我所熟知的框架中不出意外的会利用到:
ThreadLocal Dynamic Proxy Reflect Genericity AQS&CAS
ThreadLocal
Dynamic Proxy
Reflect
Genericity
AQS&CAS
所以实现一套框架看起来很简单,因为需要的技术也并不怎么高大上,并且还有一堆现成的开源可以直接拿来用的。但是在实现的过程中确实有很多意想不到的难点,如果您有兴趣可以亲自简单实现个Spring并在测试环境下小用一下,保证能达到需求的情况下,这个过程应该会使您对我刚才的话感悟颇深。
回归主题,在将近一年的时间里,我从最基本的Json、XML解析到服务容器再到服务框架最终满足了一个小型网站的基本开发。当然有些模块还有很多不足,也有很多待优化的功能,这些笔者都会坚持下来接着去完成。也许最终这些代码变得毫无意义,但是我仍然会坚持的去完成它,并将它打造的越来越好!
Json、XML解析
服务容器
服务框架
No Framework,简称 NF ,为Java Web开发提供整套服务框架解决方案。
Maven (groupId:com.gitee.ainilili)
Git (https://gitee.com/ainilili)
在学习使用之前,如果您有兴趣,可以先看看它们是具体作用~
NF每个模块都占据着很重要的地位,它们相互协调,一起完成最终的工作,下面就简单介绍一下它们都担负着什么样的重要使命。
Noson负责着前后台交互过程中的Json数据解析工作,是MVC容器默认的Json序列化及反序列化工具。在经过不断的优化后,Noson的解析性能也是相当可观,虽然不及前辈们写的FastJson、Jackson、Gson等,但是如果不是对性能太过要求,Noson是您最好的选择。
Noson有着极高的容错率,例如一下的Json字符串,Noson也能容错解析
{value:[{\"key1\":a,'key2':b,key3:1c,key4:'\"d',key5:\"'e\",key6:':,[]{}',key7:,key8:'%$&%$&%^><:'}]}
以下是解析后并序列化为标准Json字符串
{"value":[{"key1":"a","key2":"b","key3":"1c","key4":"\"d","key5":"\'e","key6":":,[]{}","key7":"key8:\'%$&%$&%^><:\'"}]}
Noson也可以处理非常复杂的类型
json = "{list:[{map:{map:{list:[{map:{value:{\"name\":nico,age:21,skill:[java,c,c#,python,php,javascript],deposit:0.0,info:{address:china,job:IT}}}},{map:{value:{\"name\":nico,age:21,skill:[java,c,c#,python,php,javascript],deposit:0.0,info:{address:china,job:IT}}}}]}}},{map:{map:{list:[{map:{value:{\"name\":nico,age:21,skill:[java,c,c#,python,php,javascript],deposit:0.0,info:{address:china,job:IT}}}},{map:{value:{\"name\":nico,age:21,skill:[java,c,c#,python,php,javascript],deposit:0.0,info:{address:china,job:IT}}}}]}}}]}"; Map<String, List<Map<String, Map<String, Map<String, List<Map<String, Map<String, Nico>>>>>>>> target = Noson.convert(json, new NoType<Map<String, List<Map<String, Map<String, Map<String, List<Map<String, Map<String, Nico>>>>>>>>>(){});
Noson可以解决循环嵌套
Cycle c = new Cycle(); System.out.println(Noson.reversal(c)); Map<String, Object> map = new HashMap<String, Object>(); map.put("map", map); System.out.println(Noson.reversal(map)); List<Object> list = new ArrayList<Object>(); list.add(list); System.out.println(Noson.reversal(list)); Set<Object> sets = new HashSet<Object>(); sets.add(sets); System.out.println(Noson.reversal(sets)); map.put("list", list); System.out.println(Noson.reversal(map));
输出
{"cycle":{}} {"map":{}} [[]] [[]] {"list":[[]],"map":{"list":[[]]}}
Noson还有更多神奇的地方,如果您有兴趣,可以在下一节学习的过程中深入了解。
Nocat是基于Java socket编制的轻量级web服务器,提供简单的资源访问功能,向外提供三大模块:
Filter
Listener
Api
功能可以看做Tomcat的过滤器、监听器、Servlet,区别于Tomcat的地方在于Nocat可以更简单的在Main函数中启动一个服务:
public static void main(String[] args) { ServerBootStrap bootStrap = new ServerBootStrap(); bootStrap.start(8080); }
上述代码会在本地启动一个8080为端口的服务。
8080
Noaoc使用及其少的代码量实现了Spring核心的两大模块IOC和AOP,并且同时支持xml及注解的配置。
IOC
AOP
Noaoc负责整个大家族中的类依赖管理,并提供及其灵活的对外扩展能力,这就大大方便了Nomvc的接入。
Nomvc
Noaoc提供一个对Nocat的Listener监听器用于容器初始化
noaoc-listener-for-nocat
在Nocat的xml配置文件中加上监听器并设置参数:
<listener> <handler>org.nico.aoc.listener.NoaocListener</handler> <payload> { //要扫描的xml配置 "xmls":["cat-mysql.xml","cat-redis.xml"], //要扫描的注解包配置 "packs":["org.nico.ct"], //自扩展组件 "compents":["org.nico.cat.mvc.compent.MVCCompent"] } </payload> </listener>
Nomvc是基于路由层的一个MVC控制器,出参入参使用Noson辅助解析,自带Verify模块负责方法入参的验证。
Verify
Nomvc对外提供两个扩展模块:
nomvc-support-for-nocat nomvc-support-for-tomcat
nomvc-support-for-nocat
nomvc-support-for-tomcat
接入Nocat只需要在xml配置文件中加上监听器和Api拦截路径:
<listener> <handler>org.nico.cat.mvc.listener.ListenerForNocat</handler> <payload> //mvc注解包 {"scanpack":"org.nico.ct.controller"} </payload> </listener> <api> <uri>/v1/**</uri> <handler>org.nico.cat.mvc.router.RouterForNocat</handler> </api>
Nolog使用简单几个文件,实现了轻量级的日志工具,另外附带着一些常用的工具包。
Nolog本身并没有任何依赖,因为要支持切换Log4J,所以添加了对Log4J级SLF的依赖。
Log4J
Nolog入口文件名为logno.properties,之后将会简单介绍Nolog的配置参数及使用。
logno.properties
Seeker最初的定位是爬虫工具,将爬取的HTML文本解析并提供可搜索的接口去获取目标数据,后来发现Seeker也可以用来做XML的解析。
Seeker在NF大家族中负责超文本解析工作,例如Nocat及Noaoc的配置。
类似Hibernate,但是比Hibernate轻得多的orm框架,目前只支持Mysql,性能直逼JDBC,提供方便的条件查询及分页接口。
可使用Noaoc直接整合:
<book id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <param key="jdbcUrl" value="jdbc:mysql://localhost:3306/xx?useUnicode=true&characterEncoding=utf8&useSSL=false" /> <param key="user" value="xx" /> <param key="password" value="xx" /> <param key="driverClass" value="com.mysql.jdbc.Driver" /> <param key="maxPoolSize" value="100" /> <param key="minPoolSize" value="10" /> </book> <book id="MysqlSession" class="org.nico.db.session.branch.MysqlSession"> <param key="autoCommit" value="false" /> <label name="dataSource" ref="DataSource" /> </book> <book id="MysqlDBHelper" class="org.nico.db.helper.impl.MysqlDBHelper"> <param key="printLog" value="false" /> <label name="session" ref="MysqlSession" /> </book> <book id="TransationManager" class="org.nico.db.datasource.TransationManager"> <label name="dataSource" ref="DataSource" /> </book>
依赖asm源码,目前提供的方法有:
对象方法参数名的获取
增强式反射
如果您不想在pom.xml中写那么多的NF模块依赖,就直接引入NF模块即可。
Noson详细文档
Nocat详细文档
Noaoc详细文档
Nomvc详细文档
Nolog详细文档
Seeker详细文档
Nodb详细文档
Noasm详细文档
也许您需要引入父模块:
<dependency> <groupId>com.gitee.ainilili</groupId> <artifactId>noframework</artifactId> <version>${version}</version> <type>pom</type> </dependency>
如果想引入所有模块,您只需要引入nf依赖即可:
nf
<dependency> <groupId>com.gitee.ainilili</groupId> <artifactId>nf</artifactId> <version>${version}</version> </dependency>
如果您想单独引用:
<dependency> <groupId>com.gitee.ainilili</groupId> <artifactId>${module-name}</artifactId> <version>${version}</version> </dependency>
这里的${module-name}是模块名称,例如引入noson v1.0.1模块:
${module-name}
noson v1.0.1
<dependency> <groupId>com.gitee.ainilili</groupId> <artifactId>noson</artifactId> <version>1.0.5</version> </dependency>
另外,有些模块是被其他模块依赖的,具体依赖可以到http://mvnrepository.com/
使用Git工具将项目Clone到本地,之后使用您的IDE为您的项目引入模块到环境中,或者您可以手动打包成jar然后引入!
Clone
NF提供一个简单的项目CoffeeTime用来演示NF实战的过程,将项目通过Git工具Clone到本地,然后以Maven Project的方式导入到您的IDE中即可。
Maven Project
CoffeeTime 启动入口:org.nico.ct.CtApplication
org.nico.ct.CtApplication
TP:为了方便大家运行,数据库链接均使用笔者云服务器外网IP,希望大家不要做坏事,虽然服务器没什么价值,但是仍会给笔者带来一些困扰~
下面就以CoffeeTime来演示一下NF框架的使用。
项目结构如下:
新建一个Maven项目,并在pom中添加NF依赖及其他常用的 jar
<dependencies> <dependency> <groupId>com.gitee.ainilili</groupId> <artifactId>nf</artifactId> <version>1.0.5</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> </dependencies>
首先是 Nocat 的配置文件cat.xml:
<?xml version="1.0" encoding="UTF-8"?> <app> <cat:welcomes> <welcome>index.html</welcome> <welcome>index.jsp</welcome> <welcome>index.asp</welcome> <welcome>index.php</welcome> </cat:welcomes> <cat:configs> <!-- 定义访问资源的路径, / 代表项目工作路径 --> <property field="server_resource_path" value="/web" /> <property field="server_port" value="8080" /> <property field="server_charset" value="utf-8" /> <property field="server_revice_buffer_size" value="104857600" /> <property field="server_so_timeout" value="0" /> </cat:configs> <cat:listeners> <listener> <handler>org.nico.aoc.listener.NoaocListener</handler> <payload> { "xmls":[ "cat-mysql.xml", "cat-redis.xml" ], "packs":[ "org.nico.ct" ], "compents":[ "org.nico.cat.mvc.compent.MVCCompent" ] } </payload> </listener> <listener> <handler>org.nico.cat.mvc.listener.ListenerForNocat</handler> <payload> {"scanpack":"org.nico.ct.controller"} </payload> </listener> </cat:listeners> <cat:filters> <filter> <uri>/v1/authc/**</uri> <handler>org.nico.ct.section.AuthFilter</handler> </filter> </cat:filters> <cat:apis> <api> <uri>/v1/**</uri> <handler>org.nico.cat.mvc.router.RouterForNocat</handler> </api> </cat:apis> </app>
配置 Noaoc 对 Mysql 及 Redis 的集成文件
cat-mysql.xml
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <param key="jdbcUrl" value="jdbc:mysql://localhost:3306/ct?useUnicode=true&characterEncoding=utf8&useSSL=false" /> <param key="user" value="root" /> <param key="password" value="root" /> <param key="driverClass" value="com.mysql.jdbc.Driver" /> <param key="maxPoolSize" value="100" /> <param key="minPoolSize" value="10" /> <!-- <param key="maxIdleTime" value="0" /> --> </book> <book id="MysqlSession" class="org.nico.db.session.branch.MysqlSession"> <param key="autoCommit" value="false" /> <label name="dataSource" ref="DataSource" /> </book> <book id="MysqlDBHelper" class="org.nico.db.helper.impl.MysqlDBHelper"> <param key="printLog" value="false" /> <label name="session" ref="MysqlSession" /> </book> <book id="TransationManager" class="org.nico.db.datasource.TransationManager"> <label name="dataSource" ref="DataSource" /> </book> <aspect id="TransationSection" class="org.nico.ct.section.TransationSection"> <aop execution="expression(org.nico.ct.service.impl.*.*(..))"> <before proxy-method="before" /> <around proxy-method="around" /> <after proxy-method="after" /> <wrong proxy-method="wrong" /> </aop> </aspect> </books>
cat-redis.xml
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="JedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <param key="maxTotal" value="200" /> <param key="maxIdle" value="50" /> <param key="testOnBorrow" value="true" /> <param key="testOnReturn" value="true" /> </book> <book id="JedisPool" class="redis.clients.jedis.JedisPool"> <label name="poolConfig" ref="JedisPoolConfig" /> <param key="host" value="localhost" /> <param key="port" value="6379" /> <param key="timeout" value="30000" /> <param key="password" value="iamct" /> <param key="database" value="0" /> </book> <book id="JedisUtils" class="org.nico.ct.util.JedisUtils"> <label name="jedisPool" ref="JedisPool" /> </book> </books>
Nolog的配置 logno.properties:
nico.log.path = noblog.log nico.log.level = DEBUG nico.log.format = ${time} [\t${threadId}\t] ${logType} ${className}\uFF1A${line} - ${message} nico.log.print.stack.trace = on #nico.log.type = LOG4J
BaseDao.java
DaoImpl.java,@Dao用于声明一个Bean
ServerImpl配置,@Label用于注入Bean,@Service用于声明一个Service
Controller基础配置 @RestCinema用于声明一个Controller,直接返回Json @Lobby用于定制路由 path入参 @PathParam声明该参数来源于path body及url传参 @Body用于声明参数来源于Body @QueryParam用于声明参数来源于url 参数验证 @Verify声明一个需要进一步验证的实体类 @NotNull不允许为空 @Length限制长度 @Match正则验证 @Range范围验证
Controller基础配置
@RestCinema用于声明一个Controller,直接返回Json
@Lobby用于定制路由 path入参
@PathParam声明该参数来源于path body及url传参
@Body用于声明参数来源于Body
@QueryParam用于声明参数来源于url 参数验证
@Verify声明一个需要进一步验证的实体类
@NotNull不允许为空
@Length限制长度
@Match正则验证
@Range范围验证
数据库事务配置
package org.nico.ct.section; import java.sql.SQLException; import org.nico.aoc.aspect.AspectProxy; import org.nico.aoc.aspect.point.AspectPoint; import org.nico.aoc.aspect.point.ProcessingAspectPoint; import org.nico.aoc.scan.annotations.After; import org.nico.aoc.scan.annotations.Around; import org.nico.aoc.scan.annotations.Before; import org.nico.aoc.scan.annotations.Label; import org.nico.aoc.scan.annotations.Wrong; import org.nico.db.datasource.TransationManager; //@Aspect //这里不使用注解,使用XML配置增加清晰明了 public class TransationSection implements AspectProxy{ @Label private TransationManager tm; @Override @Before(value = "expression(org.nico.ct.service.impl.*.*(..))") public void before(AspectPoint point) { try { tm.beginTransaction(); } catch (SQLException e) { e.printStackTrace(); } } @Override @Around(value = "expression(org.nico.ct.service.impl.*.*(..))") public Object around(ProcessingAspectPoint point) throws Throwable { Object result = point.process(); return result; } @Override @After(value = "expression(org.nico.ct.service.impl.*.*(..))") public void after(AspectPoint point) { try { tm.commitTransaction(); tm.relaseConnection(); } catch (SQLException e) { } } @Override @Wrong(value = "expression(org.nico.ct.service.impl.*.*(..))") public void wrong(ProcessingAspectPoint point, Throwable e) throws Throwable{ tm.rollbackTransaction(); throw e; } }
登录验证
视频直播流媒体支持
如果您发现项目中存在BUG或者设计不合理的地方,非常希望能够提``Issues```给我,让NF框架越来越完美
使用NF写完CoffeeTime
使用NF写完CoffeeBlog
完善Nocat上传模块
增加RPC模块
Noaoc增加定时
优化Nodb
以后再定
Email - ainililia@163.com
ainililia@163.com
QQ - 473048656
473048656
交流群 - 177563526
177563526