指尖上的艺术

学习的热情,不应为季节的变化而改变


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索
close

RxJava源码浅析之理解操作符

发表于 2018-02-08   |   分类于 Code

操作符是为了解决对Observable对象的变换的问题,用于在Observable和最终的Subscriber之间控制、修改Observable发出的事件。

本文通过Filter和Skip操作符的源码来理解操作符的作用,最后可学会自定义操作符。

Filter

Filter中主要是通过OnSubscribeFilter和FilterSubscriber代理原始的Observable和Subscriber完成筛选。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Observable<T> {
public final Observable<T> filter(Func1<? super T, Boolean> predicate) {
//创建OnSubscribeFilter,将原始的Observable传入做代理工作
return unsafeCreate(new OnSubscribeFilter<T>(this, predicate));
}
}

class OnSubscribeFilter<T> {
final Observable<T> source;

final Func1<? super T, Boolean> predicate;

public OnSubscribeFilter(Observable<T> source, Func1<? super T, Boolean> predicate) {
this.source = source;
this.predicate = predicate;
}

@Override
public void call(final Subscriber<? super T> child) {
//创建FilterSubscriber代理
FilterSubscriber<T> parent = new FilterSubscriber<T>(child, predicate);
//将FilterSubscriber的生命周期与真是的Subscriber绑定
child.add(parent);
//将FilterSubscriber订阅在原始的Observable上
source.unsafeSubscribe(parent);
}

/**
* 主要完成Subscriber的代理下发工作
*/
static final class FilterSubscriber<T> extends Subscriber<T> {
@Override
public void onNext(T t) {
boolean result = predicate.call(t);
if (result) {
actual.onNext(t);
}
}

@Override
public void onError(Throwable e) {
actual.onError(e);
}

@Override
public void onCompleted() {
actual.onCompleted();
}
}
}

通过Filter可以知道通过定义一个新的OnSubscribe可以完成对原始OnSubscribe的修改、控制。
除了定义一个全新的OnSubscribe外还可以通过Operator的方式来完成。

阅读全文 »

RxJava源码浅析之工作原理

发表于 2018-02-08   |   分类于 Code

通过 Observable 中的静态方法先创建 OnSubscribe 然后创建 Observe 并将 OnSubscribe 传入 Observable ,完成 Observable 的创建;
在冷启动中,subscribe 时会调用 Observable 中 OnSubscribe 的 call 方法开始工作。

被观察者的创建过程

通过 Observable 的创建操作符创建被观察者,其底层实现主要是(以 from 为例):

1
2
3
4
5
6
7
8
class Observable<T> {
/**
* OnSubscribeFromIterable是现实了OnSubscribe的被观察者,其中包含了业务主要的逻辑。
*/
public static <T> Observable<T> from(Iterable<? extends T> iterable) {
return unsafeCreate(new OnSubscribeFromIterable<T>(iterable));
}
}
1
2
3
4
5
6
7
8
class Observable<T> {
/*
* unsafeCreate创建Observable,并持有OnSubscribe。
*/
public static <T> Observable<T> unsafeCreate(OnSubscribe<T> f) {
return new Observable<T>(f);
}
}
阅读全文 »

RxJava源码浅析之介绍

发表于 2018-02-08   |   分类于 Code

简介

一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序库。

  • 异步
  • 简洁
  • 可扩展的观察者模式

第一次看到上面话理解起来比较抽象,通俗的说就是RxJava是一个运行在Java虚拟机上面通过可以观察的基于事件的序列来完成异步任务的库。

本系列博文均在 RxJava1.2.9 下

RxJava1.x版本将在2018年3月31日停止任何更新,所以,本系列博文仅仅了解RxJava的一些原理。可作为学习2.x的一个过渡。

RxJava四个基本概念:

在学习RxJava之前一定要理解以下几个对象,否则无法理解源码。

对象 说明
Observable 被观察者
Subscriber(Observer) 订阅者(观察者)
subscribe 订阅

Observable 和 Observer 通过 subscribe 实现订阅与被订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。

1
2
3
4
5
                      onNext(param)
onCompleted()
+------------+ onError(error) +----------+
| Observable |---------------------------->| Observer |
+------------+ +----------+
阅读全文 »

“使用 Dockerfile 定制镜像”

发表于 2017-06-08

理解Docker三大组件之镜像

发表于 2017-06-06

概念

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

操作系统分为内核和用户空间,对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。

镜像的分层存储

因为完整的镜像体积过于庞大,Docker你用Union FS技术将镜像进行分层存储;与ISO不同,Docker镜像是一个虚拟概念,由一组文件系统组成或者说是多层文件系统联合组成。

镜像是一层一层构建的,前一层是后一层的基础,如果删除前一层,仅仅是标记为删除,在容器中看不见,但还是会存在镜像中,所以构建镜像时需额外小心。

获取镜像

docker pull [选项] [Docker Registry地址]<仓库名>:<标签>

  • Docker Registry地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
  • 仓库名:<用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
1
$ docker pull nginx

运行镜像

我们现在可以通过创建一个容器并运行镜像。

1
$ docker run -it --rm nginx bash
  • -i 交互式操作
  • -t 终端
  • –rm 退出容器后,自动删除该容器

利用 commit 理解镜像构成

镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础。

以nginx镜像创建一个webserver的容器

1
$ docker run --name webserver -d -p 80:80 nginx

进入已启动的webserver容器的交互式shell终端,修改nginx默认的index.html内容

1
2
3
4
$ docker exec -it webserver bash
root@3729b97e8226:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
root@3729b97e8226:/# exit
exit

查看webserver容器当前存储层的改动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker diff webserver
C /root
A /root/.bash_history
C /run
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp

此时,可以通过 docker commit 命令将webserver容器在原有镜像的基础上,再叠加容器存储层构建成一个新的镜像

docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

1
2
3
4
5
6
$ docker commit \
--author "FingerArt <george@chengguo.io>" \
--message "修改了默认网页" \
webserver \
nginx:v2
sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214
1
2
3
4
5
# 可查看到生成的 nginx:v2 镜像
$ docker images nginx

# 查看 nginx:v2 相比 nginx:latest 历史记录
$ docker history nginx:v2

此时你可以通过 docker run 来创建容器。

慎用 docker commit

前面通过 docker diff webserver 命令看到的信息中,出了改动了nginx的默认index.html文件外,还生成了一些缓存等文件, docker commit 进行了黑箱操作,生成了黑箱镜像,将不该添加的文件添加进了镜像中,如果删除上层的东西,却仍然存在镜像中,都将导致生成的镜像臃肿。
所以,除了一些特殊的场景,如黑客入侵保留现场等,都不要使用 docker commit 来制作镜像。

注:文章中可能有很多错误,也有可能出现无法使用的情况,因为此技术博文是我的学习笔记,我只是记载一些看到或者想到东西,所以我不推荐你来按照该博文的内容进行直接使用。

解决mac下在线安装Visual Studio 无法连接到网络

发表于 2017-06-04

准备要接手C#的项目了,自然需要好的工具(Visual Studio)。在微软的官网下载的安装包是一个在线的安装程序,在安装的第一步(检查网络环境),出现无法连接到网络,有网络并且Shadowsocks也是开着全局的。

一、安装proxychains4

1
brew install proxychains-ng

二、配置

1
vim /usr/local/etc/proxychains.conf

三、使用proxychains4安装

1
2
3
proxychains4 open /Volumes/Visual\ Studio\ Installer/Install\ Visual\ Studio.app

//open 所在路径的应用

注:文章中可能有很多错误,也有可能出现无法使用的情况,因为此技术博文是我的学习笔记,我只是记载一些看到或者想到东西,所以我不推荐你来按照该博文的内容进行直接使用。

Docker 新手入门

发表于 2017-05-25

该文章以Mac为例。

安装

请至Docker官网下载Mac版:https://www.docker.com/docker-mac

阅读全文 »

ITextPdf 签名集成问题

发表于 2017-03-17

因项目的需要需要使用对pdf进行签名,但使用ITextPdf进行签名遇到一些错误,官方说的不够明确,在此记录一下,供后面遇到该问题的朋友参考。

Q1

引用的 ITextPdf 下

java.lang.ClassNotFoundException: org.bouncycastle.*

如果你遇到了这个错误你需要添加另外一个用于签名的库:bouncycastle (bcprov-jdk15on-156.jar、bcpkix-jdk15on-156.jar、bcmail-jdk15on-156.jar)

这里请不要引用错了ITextG库

阅读全文 »

IntelliJ-插件开发指南

发表于 2017-02-16

待续……

关于ThinkPHP5 子域名路由问题

发表于 2016-12-01

准备在一个CRM的项目,本想使用Laravel框架的,但是并不怎么熟练,加上时间紧迫,最后决定使用ThinkPHP。

因为TP5是新出的一个版本,改动有些大,在看完文档中的路由(域名检测)部分后,就希望能做到这样的效果:

定义某个api路由规则时,可以根据 api.domain.com 子域名来检测;非 api.domain.com 子域名访问其他模块。但是根据文档配置后却会报 模块不存在

再三查看文档后决定没错,后来跟进源码查看关键位置

1
2
3
4
5
6
7
8
9
10
//thinkphp/library/think/Route.php

182 if (isset($rule['__domain__'])) {
183 self::domain($rule['__domain__']);
184 unset($rule['__domain__']);
185 }

119 self::$rules['domain'][$domain]['[bind]'] = [$rule, $option, $pattern];

1132 if(isset($option['domain']) && !in_array($option['domain'], [$_SERVER['HTTP_HOST'], self::$subDomain])) // 域名检测

会发现通过如下设置即可完成:

1
2
3
4
5
6
7
//route.php

'__domain__'=>[
'api' => 'api/User/index',
],

'user' => ['api/User/create', ['method' => 'get', 'domain'=>'api']],
12…8
George

George

George's blog

74 日志
3 分类
33 标签
RSS
GitHub 微博
© 2018 George
由 Hexo 强力驱动
主题 - NexT.Pisces