下面是我直播的文字版,直播地址: https://segmentfault.com/l/15...
代码: https://github.com/zhoumengka...
整个项目咱们我又细分了6个版原本演进,但愿更加便于你们对比学习。
我在收集你们是否愿意学习 java 的时候,获得了以下反馈:php
java == 太复杂 java == 各类乱七八糟的配置 java == 面向 ide 编程
其实咱们在学习的时候 java 的时候彻底不用接触那些高大上的工具,也能够尽可能减小各类配置文件,好比下面咱们只有个pom.xml
配置文件。
还有的同窗说还学 java 干吗,不都应该去学 go 吗?其实语言真的不重要,咱们须要掌握的是快速学习利用一门语言的学习方法,这也是本课的真正目的。html
就像盲人摸象同样,他要想弄清楚大象的真实面貌可能要摸好久,就比如咱们拿着放大镜在学习 java 同样,java 通过这么多年的发展,能够说很是庞大。若是咱们要知道大象长什么样,就应该放下手中的放大镜,向后退远点,反而可以很是清晰的看到它的全貌。学习一门新的语言也同样,有不少不少网上的教程,很是的大而全,通常得系统的学习30~60小时以后才能正式的接触项目开发。基础很重要,可是学习了太多的基础会让你们失去学习的乐趣和自信心。不少知识点其实能够项目以后再补。按需去学,反而是自我驱动着去学习的最佳方式。前端
好比 hashmap 的哈希分布、哈希碰撞、动态扩容,这些都是咱们后期深刻提升须要理解的内容,初期,咱们只须要知道能拿 hashmap 作什么就行。java
好比咱们作 Web 后端 api 开发,首先是经常使用的循环/迭代、条件判断、增删改为。那么能不能快速用 java 实现一遍这些咱们用 php 作起来很是顺手的事呢?
这样有助于咱们快速提高自信心。mysql
PHP 里如何实现,从新用 java 实现一遍就好了。nginx
当本身实现了一些小 demo 再去参考别人的项目。若是一开始就直接看别人的项目,可能彻底不知作别人在干吗。好比别人用了ConcurrentHashMap
,就再去思考为何我用HashMap
他却用ConcurrentHashMap
,带着问题,带着思考去看开源代码。git
完成了一些简单的项目了以后就能够再回过头来系统的学习了。这时候就会有不同的收获。github
最后就是当项目须要调优,性能提高的时候,再各个击破,深刻学习,更有针对性,更有目标性。web
咱们用 netty 来提供高性能的 web 服务服务。使用简单方便(netty 并不简单),不依赖其余软件。而后思考完成一个简单的 web api 服务器须要哪些必不可少的组成部分。(其实在思考这的时候,你必需要要对作简单的架构必须熟记于心)。redis
我简单归纳了下:
HashSet 是一个没有重复元素的集合。它是由HashMap实现的,不保证元素的顺序,也就是说所说元素插入的顺序与输出的顺序不一致。这实际上是个人老朋友了,redis 里常常用,好比我们能够它来实现一个黑名单,这样查找的速度就很是快,也不用去远程查询 redis 了,直接在当前内存中查询。
ArrayList 基于数组来实现集合的功能,其内部维护了一个可变长的对象数组,集合内全部对象存储于这个数组中,并实现该数组长度的动态伸缩。
这不就是咱们的 PHP 里面经常使用的索引数组么?
HashMap 以哈希表数据结构实现,查找对象时经过哈希函数计算其位置,它是为快速查询而设计的。特色就是快,非线程安全。
这不就是咱们的 PHP 里面经常使用的关联数组么?
http://www.cnblogs.com/ITtang...
http://www.jianshu.com/p/b54f...
http://www.cnblogs.com/xiaoxi...
Maven的基本原理很简单,采用远程仓库和本地仓库以及一个核心的配置文件pom.xml,pom.xml中定义的jar文件从远程仓库下载到本地仓库,各个项目使用同一个本地仓库的jar,同一个版本的jar只需下载一次,并且避免每一个应用都去拷贝jar。
这和 php 的包管理工具 composer 很像,或者是 composer 是参考着 maven 而设计的。maven 的功能更强大,composer 须要每一个项目都要导入一遍,maven 却像 git 同样,有一个本地仓库,第三方包也不会直接引用到项目中,而是在编译的时候才会引入(是否是很方便)。另外一方面,maven 不只仅是包管理工具,并且是一个项目管理工具,集成了编译、打包、单元测试等功能。
下面是最简单的一个演示,依赖了 netty 、junit 两个包。而后使用maven-compiler-plugin
指定了编译时候的版本规则。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>mengkang.net</groupId> <artifactId>demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>5.0.0.Alpha2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
我复制了 netty 官方的 demo 地址以下:
https://github.com/zhoumengkang/netty-http-demo/tree/v1.0
当咱们运行api.mengkang.net.netty.HttpServer.main
方法,服务器就跑起来了,当在浏览器里访问 http://localhost:9009/ 就会返回Hello World
。
方法 | 用途 |
---|---|
api.mengkang.net.netty.HttpServer#main | 服务器启动的入口 |
api.mengkang.net.netty.HttpServerInitializer#initChannel | 初始化 Channel |
api.mengkang.net.netty.HttpServerHandler#channelRead | 进行网络 I/O |
这是第一步,netty 这里就充当了一个 web server 的角色。而咱们就能够直接在 netty 提供的接口的基础上作编程,而不须要想 nginx + php-fpm 还须要一次反向代理,性能高了许多。(swoole 的方式就很像 netty 了)。
具体需求:提供一个 api 能够用户指定用户的信息
定义接口:
http://localhost:10000/users/{id} http://localhost:10000/?method=user.get&id={id}
可能如今你们早已习惯了前者 restful 的 api 接口。
由于这里须要一次路由的映射和 http method 的匹配,考虑到学习的成本呢,我没有选择这种方式。
咱们今天的目标是以最简单有效的方式实现咱们的功能。
咱们首先从最简单的方式来实现(其实没有路由的 api 反而是最快的,毕竟须要作的判断少嘛)。
后面你们有兴趣能够参考我写的一个 restful api 的 demo netty-restful-server
具体代码
https://github.com/zhoumengkang/netty-http-demo/tree/v2.0
这一版本中作一个过渡版本,暂时控制器还不解析过多的参数。只完成一个$_GET['method']
参数的解析。
主要的任务是经过获取的$_GET['method']
去执行UserController
里面的get
方法。
方法 | 用途 |
---|---|
api.mengkang.net.RequestHandler#response | 从 HttpServerHandler 处接管网络请求 |
api.mengkang.net.RequestHandler#invoke | 执行反射调用 |
api.mengkang.net.api.UserController#get | 模拟输出一个用户的信息 |
Class<?> classname; Method methodName; Object result = null; classname = Class.forName("api.mengkang.net.api." + clazz + "Controller"); Object inst = classname.newInstance(); methodName = classname.getMethod(function); result = methodName.invoke(inst);
具体代码
https://github.com/zhoumengkang/netty-http-demo/tree/v3.0
方法 | 用途 |
---|---|
api.mengkang.net.Request | 封装一个通用 api 请求对象,包含客户端请求的$_GET,$_POST,ip 等 |
api.mengkang.net.RequestHandler#requestFetch | 把请求解析成 api.mengkang.net.Request 对象 |
api.mengkang.net.RequestHandler#invoke | 把 api.mengkang.net.Request 传递给 Controller |
反射实例化对象使用了构造函数 ,这样就把请求的对象Request
实例传到 Controller 中去了。Controller 中的方法就能取到$_GET
,$_POST
,以及相似 php://input
的数据了。
Class<?> classname; Object classObject; Constructor constructor; Method methodName; Object result = null; classname = Class.forName("api.mengkang.net.api." + clazz + "Controller"); constructor = classname.getConstructor(Request.class); classObject = constructor.newInstance(request); methodName = classname.getMethod(function); result = methodName.invoke(classObject);
具体代码
https://github.com/zhoumengkang/netty-http-demo/tree/v3.1
类 | 用途 |
---|---|
api.mengkang.net.Response | 封装一个通用 api 响应对象 |
api.mengkang.net.ErrorCode | 错误代码统一规范起来 |
api.mengkang.net.netty.HttpServerHandler | http 头信息 改成 json |
这样就更像一个正规的 api 服务了。
增长 User 对象, 增长 UserModel 来处理 User 对象的返回, 完善了错误返回机制.
类 | 用途 |
---|---|
api.mengkang.net.entity.User | 描述用户对象,用于user.get 接口的数据返回 |
api.mengkang.net.model.UserModel | 供UserController 调用,简单分层 |
api.mengkang.net.ErrorCode | 完善了错误类型 |
api.mengkang.net.api.UserController | 完善了错误类型的判断,返回给前端错误更友好 |
类 | 用途 |
---|---|
api/mengkang/net/utils/mysql | 新增本身封装的简单的数据链接池的操做工具 |
api.mengkang.net.dao.UserDao | 作数据库链接的查询,返回给UserModel |
中间引入三个包,来作数据库的查询和数据库的链接池
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.18</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.6</version> </dependency>
最后整个项目结构以下
├── main │ ├── java │ │ └── api │ │ └── mengkang │ │ └── net │ │ ├── Config.java │ │ ├── ErrorCode.java │ │ ├── Request.java │ │ ├── RequestHandler.java │ │ ├── Response.java │ │ ├── api │ │ │ ├── BaseController.java │ │ │ └── UserController.java │ │ ├── dao │ │ │ └── UserDao.java │ │ ├── entity │ │ │ └── User.java │ │ ├── model │ │ │ └── UserModel.java │ │ ├── netty │ │ │ ├── HttpServer.java │ │ │ ├── HttpServerHandler.java │ │ │ └── HttpServerInitializer.java │ │ └── utils │ │ └── mysql │ │ ├── DMLTypes.java │ │ ├── DbFiled.java │ │ ├── JdbcPool.java │ │ ├── MySelect.java │ │ └── Mysql.java │ └── resources │ ├── api.properties │ ├── read.db.properties │ └── write.db.properties