基于Java语言开发的一套轻量级框架,亲手实现JSON/XML解析、服务容器、服务框架、字节码工具等解决方案,学习成本低,即插即用,扩展性高,更加轻量级!
NoFramework是笔者在闲暇之余写的一个网络爬虫项目Seeker
一路延续发展到后来的No
系列的框架的诞生。一路走来,不知不觉已经快一年了,这期间有些项目有的被重写过,有的架构也发生了大的改变,还有的一直在调优过程中转变着解决方案,在付出时间的同时,获得的回报是独立思考过程带给自己的对底层细节的了解。
很多人很疑惑于它的作用,在这里诠释一下:
它可以代替tomcat、spring、mybatis来帮助开发者进行web服务搭建!
您使用这套框架的好处是:
可直接与作者沟通交流
可参与框架的开发
能够感受到使用国产框架的魅力
Java界的很多框架原理都很简单,我所熟知的框架中不出意外的会利用到:
ThreadLocal
Dynamic Proxy
Reflect
Genericity
AQS&CAS
所以实现一套框架看起来很简单,因为需要的技术也并不怎么高大上,并且还有一堆现成的开源可以直接拿来用的。但是在实现的过程中确实有很多意想不到的难点,如果您有兴趣可以亲自简单实现个Spring并在测试环境下小用一下,保证能达到需求的情况下,这个过程应该会使您对我刚才的话感悟颇深。
回归主题,在将近一年的时间里,我从最基本的Json、XML解析
到服务容器
再到服务框架
最终满足了一个小型网站的基本开发。当然有些模块还有很多不足,也有很多待优化的功能,这些笔者都会坚持下来接着去完成。也许最终这些代码变得毫无意义,但是我仍然会坚持的去完成它,并将它打造的越来越好!
No Framework,简称NF,为Java Web开发提供整套服务框架解决方案。
Maven (groupId:com.gitee.ainilili)
项目名 | 版本号 | 功能 |
---|---|---|
noframework | 1.0.6 | 子模块的parent依赖 |
项目名 | 版本号 | 功能 |
---|---|---|
noson | 1.0.6 | Json序列化&反序列化 |
nocat | 1.0.6 | 基于Java的Web容器 |
noaoc | 1.0.6 | IOC&AOP |
nomvc | 1.0.6 | MVC |
nolog | 1.0.6 | 日志及工具包 |
seeker | 1.0.6 | Xml解析 |
nodb | 1.0.6 | ORM |
noasm | 1.0.6 | ASM工具 |
nomvc-support-for-nocat | 1.0.6 | 提供对Nocat的MVC支持 |
nomvc-support-for-tomcat | 1.0.6 | 提供对Tomcat的MVC支持 |
noaoc-listener-for-nocat | 1.0.6 | Noaoc加载监听器 |
nf | 1.0.6 | 提供其他模块的依赖 |
在学习使用之前,如果您有兴趣,可以先看看它们是具体作用~
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
为端口的服务。
Noaoc使用及其少的代码量实现了Spring核心的两大模块IOC
和AOP
,并且同时支持xml及注解的配置。
Noaoc负责整个大家族中的类依赖管理,并提供及其灵活的对外扩展能力,这就大大方便了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
模块负责方法入参的验证。
Nomvc对外提供两个扩展模块:
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的依赖。
Nolog入口文件名为logno.properties
,之后将会简单介绍Nolog的配置参数及使用。
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模块即可。
也许您需要引入父模块:
<dependency>
<groupId>com.gitee.ainilili</groupId>
<artifactId>noframework</artifactId>
<version>${version}</version>
<type>pom</type>
</dependency>
如果想引入所有模块,您只需要引入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
模块:
<dependency>
<groupId>com.gitee.ainilili</groupId>
<artifactId>noson</artifactId>
<version>1.0.5</version>
</dependency>
另外,有些模块是被其他模块依赖的,具体依赖可以到http://mvnrepository.com/
使用Git工具将项目Clone
到本地,之后使用您的IDE为您的项目引入模块到环境中,或者您可以手动打包成jar然后引入!
NF提供一个简单的项目CoffeeTime用来演示NF实战的过程,将项目通过Git工具Clone到本地,然后以Maven Project
的方式导入到您的IDE中即可。
CoffeeTime 启动入口: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
@Body用于声明参数来源于Body
@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
QQ - 473048656
交流群 - 177563526
控制台报了这么个错:org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping found for HTTP request with URI [/springmvc_response/js/jquery-2.1.0.min.js] in DispatcherServlet with name 'dispa
在运行点过项目是报No module named 'rest_framework’错误是因为没有安装rest_framework 只需要安装一下即可 但要注意不能直接 pip install rest_framework 而要 pip install djangorestframework 相应的报同样的错误No module named 'corsheaders’就大同小异了,解决方法同上
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ribbonService': Unsatisfied dependency expressed through field 'restTemplate': No qualifying
使用 RestTemplate 调用接口文件上传是报错,No HttpMessageConverter for org.springframework.util.LinkedMultiValueMap and content type "multipart 详细报错信息如下 org.springframework.web.client.RestClientException: No HttpMes
错误信息: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘org.springframework.transaction.PlatformTransactionManager’ available 错误原因及解决方法: 项目中同时出现多个数据源和相关的事务管理
SpringBoot请求接口报错 Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.wuxianggujun.wuxiangblog.pojo.Result] with preset Content-Type 'null'] 这是我的实
SSM整合报错,跳转页面发生500错误 org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifyi org.springframework.beans.factory.UnsatisfiedDependencyException: Error crea 解决fangfa,web.xml中绑定配置文件是绑定
[XCode错误]XCode编译出错异常:ld: framework not found Kernel clang: error: linker command failed with e 展开 异常:XCode编译出错异常:ld: framework not found Kernel clang: error: linker command failed with e....... 解决办法:
报错内容:No module named 'rest_framework’即没有安装rest_framework 解决方案:pip install djangorestframework !!注意:不可以是pip install rest_framework
配置类代码: package com.woniu.config; import com.alibaba.druid.pool.ha.selector.RandomDataSourceRecoverThread; import org.springframework.context.annotation.*; import org.springframework.jdbc.datasource.D
我的问题原因是: 分页方法上@RequestParam给了参数sort,我用这个String参数来标志某个页面,但是jpa用sort来排序,也就是说占用了它本身的参数,所以报错
SpringBoot 启动报错: No qualifying bean of type 'org.springframework.web.client.RestTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.spri
实现类忘记加注解@service,找了我一下午,代码从git上拉,不知道被谁注释掉了,以此记录一下
解决办法 pip install djangorestframework-jwt
问题内容: 是否有一个提供发布/订阅模式的Java轻量级框架? 一些理想的功能 支持泛型 向发布者注册多个订阅者 API主要是接口和一些有用的实现 完全不需要内存,持久性和事务保证。 我了解JMS,但这对我来说太过分了。发布/订阅的数据是文件系统扫描的结果,扫描结果被馈送到另一个组件进行处理,然后在将其馈给另一个组件之前进行处理,依此类推。 编辑:所有在同一过程中。bean的PropertyCha
本文向大家介绍轻量级javascript 框架Backbone使用指南,包括了轻量级javascript 框架Backbone使用指南的使用技巧和注意事项,需要的朋友参考一下 Backbone 是一款基于模型-视图-控制器 MVC 模式的轻量级javascript 框架 ,可以用来帮助开发人员创建单页Web应用。 借助Backbone 我们可以使用REST的方式来最小化客户端和服务器间的数据传输,
本文向大家介绍前端轻量级MVC框架CanJS详解,包括了前端轻量级MVC框架CanJS详解的使用技巧和注意事项,需要的朋友参考一下 选择正确的库 创建一个JS APP没有好的工具是很有难度的,jQuery只是操作DOM的库,没有提供任何创建APP的基础,这就是为什么我们要一个类似CanJS的专门的库。 CanJS 是一个轻量级的MVC库,提供你创建一个JS APP所需的工具。 CanJS 是一个轻
本文向大家介绍浅谈Android轻量级的数据缓存框架RxCache,包括了浅谈Android轻量级的数据缓存框架RxCache的使用技巧和注意事项,需要的朋友参考一下 请求网络数据是在安卓开发中使用最频繁的一个功能,网络请求的体验决定了用户对整个APP的感觉,因此合理地使用缓存对网络请求的数据进行处理极为重要。合理的进行缓存和网络请求,可以为APP带来更优秀的体验。图片的缓存有Picasso、Gl
问题内容: 我一直在使用jQuery在基于Web的应用程序中完成整个AJAX魔术。但是,我来到了一个决定,我并不需要所有这些神奇功能jQuery有,除了它的AJAX功能(例如,,,和)。 您能推荐轻量级的跨浏览器AJAX库/框架(最大10 kb)吗? 问题答案: 您可以通过删除不需要的模块来缩小jQuery的大小,只需修改Makefile文件即可。
本文向大家介绍详解Spring Batch 轻量级批处理框架实践,包括了详解Spring Batch 轻量级批处理框架实践的使用技巧和注意事项,需要的朋友参考一下 实践内容 从 MariaDB 一张表内读 10 万条记录,经处理后写到 MongoDB 。 具体实现 1、新建 Spring Boot 应用,依赖如下: 2、创建一张表,并生成 10 万条数据 3、创建 Person 类 4、创建一个中
主要内容:使用普通函数创建 goroutine,使用匿名函数创建goroutine在编写 Socket 网络程序时,需要提前准备一个线程池为每一个 Socket 的收发包分配一个线程。开发人员需要在线程数量和 CPU 数量间建立一个对应关系,以保证每个任务能及时地被分配到 CPU 上进行处理,同时避免多个任务频繁地在线程间切换执行而损失效率。 虽然,线程池为逻辑编写者提供了线程分配的抽象机制。但是,如果面对随时随地可能发生的并发和线程处理需求,线程池就不是非常直观和方便了。能否
Jenkins Pipeline插件有一个称为“轻量级签出”的功能,其中主服务器仅从repo中提取Jenkinsfile,而不是整个repo。配置屏幕中有一个相应的复选框。我想在多分支管道中进行轻量级签出,但我在多分支配置屏幕中没有看到复选框。有什么想法如何实现这一点吗?我注意到一些关闭的问题表明此功能可用,但我无法找到任何有关如何实现它的细节。 相关资料: https://issues.jenk