Whistleblower reveals Google’s plans for censored search in China

传谷歌搜索将接受审查重新进入中国

Illustration by Alex Castro / The Verge

Google is reportedly planning to relaunch its search engine in China, complete with censored results to meet the demands of the Chinese government. The company originally shut down its Chinese search engine in 2010, citing government attempts to “limit free speech on the web.” But according to a report from The Interceptthe US tech giant now wants to return to the world’s biggest single market for internet users.

According to internal documents provided to The Intercept by a whistleblower, Google has been developing a censored version of its search engine under the codename “Dragonfly” since the beginning of 2017. The search engine is being built as an Android mobile app and will reportedly “blacklist sensitive queries” and filter out all websites blocked by China’s web censors (including Wikipedia and BBC News). The censorship will extend to Google’s image search, spell check, and suggested search features.

The web is heavily censored in China, with the country’s so-called Great Firewall stopping citizens from accessing many sites. Information on topics like religion, police brutality, freedom of speech, and democracy are heavily filtered, while specific search topics (like the 1989 Tiananmen Square protests and Taiwanese independence) are censored completely. Advocacy groups report that censorship in the country has increased under President Xi Jinping, extending beyond the web to social media and chat apps.

The whistleblower who spoke to The Intercept said they did so because they were “against large companies and governments collaborating in the oppression of their people.” They also suggested that “what is done in China will become a template for many other nations.”

Patrick Poon, a researcher with Amnesty International, agreed with this assessment. Poon told The Intercept that if Google launches a censored version of its search engine in China it will “set a terrible precedent” for other companies. “The biggest search engine in the world obeying the censorship in China is a victory for the Chinese government — it sends a signal that nobody will bother to challenge the censorship any more,” said Poon.

In a statement given to The Verge, a spokesperson said: “We provide a number of mobile apps in China, such as Google Translate and Files Go, help Chinese developers, and have made significant investments in Chinese companies like JD.com. But we don’t comment on speculation about future plans.”

According to The Intercept, Google faces a number of substantial barriers before it can launch its new search app in China, including approval from officials in Beijing and “confidence within Google” that the app will be better than its main rival in China, Baidu.

Google previously offered a censored version of its search engine in China between 2006 and 2010, before pulling out of the country after facing criticism in the US. (Politicians said the company was acting as a “functionary of the Chinese government.”) In recent months, though, the company has been attempting to reintegrate itself into the Chinese commercial market. It launched an AI research lab in Beijing last December, a mobile file management app in January, and an AI-powered doodle game just last month.

Although this suggests Google is eager to get a slice of China’s huge market of some 750 million web users, ambitions to relaunch its search engine may yet go nowhere. Reports in past years of plans to bring the Google Play mobile store to China, for example, have so far come to nothing, and Google regularly plans out projects it ultimately rejects.

Notably, relations between China and the US have worsened in recent weeks due to trade tariffs imposed by President Trump. The Intercept reports that despite this Google staff have been told to be ready to launch the app at short notice. The company’s search engine chief, Ben Gomes, reportedly told employees last month that they must be prepared in case “suddenly the world changes or [President Trump] decides his new best friend is Xi Jinping.”

来源:https://www.theverge.com/2018/8/1/17638480/google-china-search-engine-censored-report

vimrc配置(带注释版)

“=========================================================================
” DesCRiption: 适合自己使用的vimrc文件,for Linux/Windows, GUI/Console

” Last Change: 2010年08月02日 15时13分

” Version:     1.80

“=========================================================================
set nocompatible            ” 关闭 vi 兼容模式
syntax on                   ” 自动语法高亮
colorscheme molokai         ” 设定配色方案
set number                  ” 显示行号
set cursorline              ” 突出显示当前行
set ruler                   ” 打开状态栏标尺
set shiftwidth=4            ” 设定 << 和 >> 命令移动时的宽度为 4
set softtabstop=4           ” 使得按退格键时可以一次删掉 4 个空格
set tabstop=4               ” 设定 tab 长度为 4
set nobackup                ” 覆盖文件时不备份
set autochdir               ” 自动切换当前目录为当前文件所在的目录
filetype plugin indent on   ” 开启插件
set backupcopy=yes          ” 设置备份时的行为为覆盖
set ignorecase smartcase    ” 搜索时忽略大小写,但在有一个或以上大写字母时仍保持对大小写敏感
set nowrapscan              ” 禁止在搜索到文件两端时重新搜索
set incsearch               ” 输入搜索内容时就显示搜索结果
set hlsearch                ” 搜索时高亮显示被找到的文本
set noerrorbells            ” 关闭错误信息响铃
set novisualbell            ” 关闭使用可视响铃代替呼叫
set t_vb=                   ” 置空错误铃声的终端代码
” set showmatch               ” 插入括号时,短暂地跳转到匹配的对应括号
” set matchtime=2             ” 短暂跳转到匹配括号的时间
set magic                   ” 设置魔术
set hidden                  ” 允许在有未保存的修改时切换缓冲区,此时的修改由 vim 负责保存
set guioptions-=T           ” 隐藏工具栏
set guioptions-=m           ” 隐藏菜单栏
set smartindent             ” 开启新行时使用智能自动缩进
set backspace=indent,eol,start
” 不设定在插入状态无法用退格键和 Delete 键删除回车符
set cmdheight=1             ” 设定命令行的行数为 1
set laststatus=2            ” 显示状态栏 (默认值为 1, 无法显示状态栏)
set statusline=\ %<%F[%1*%M%*%n%R%H]%=\ %y\ %0(%{&fileformat}\ %{&encoding}\ %c:%l/%L%)\
” 设置在状态行显示的信息
set foldenable              ” 开始折叠
set foldmethod=syntax       ” 设置语法折叠
set foldcolumn=0            ” 设置折叠区域的宽度
setlocal foldlevel=1        ” 设置折叠层数为
” set foldclose=all           ” 设置为自动关闭折叠
” nnoremap <space> @=((foldclosed(line(‘.’)) < 0) ? ‘zc’ : ‘zo’)<CR>
” 用空格键来开关折叠

” return OS type, eg: windows, or linux, mac, et.st..
function! MySys()
if has(“win16”) || has(“win32”) || has(“win64”) || has(“win95”)
return “windows”
elseif has(“unix”)
return “linux”
endif
endfunction
” 用户目录变量$VIMFILES
if MySys() == “windows”
let $VIMFILES = $VIM.’/vimfiles’
elseif MySys() == “linux”
let $VIMFILES = $HOME.’/.vim’
endif
” 设定doc文档目录
let helptags=$VIMFILES.’/doc’
” 设置字体 以及中文支持
if has(“win32”)
set guifont=Inconsolata:h12:cANSI
endif
” 配置多语言环境
if has(“multi_byte”)
” UTF-8 编码
set encoding=utf-8
set termencoding=utf-8
set formatoptions+=mM
set fencs=utf-8,gbk
if v:lang =~? ‘^zh\|ja\|ko
set ambiwidth=double
endif
if has(“win32”)
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
language messages zh_CN.utf-8
endif
else
echoerr “Sorry, this version of (g)vim was not compiled with +multi_byte”
endif
” Buffers操作快捷方式!
nnoremap <C-RETURN> :bnext<CR>
nnoremap <C-S-RETURN> :bprevious<CR>
” Tab操作快捷方式!
nnoremap <C-TAB> :tabnext<CR>
nnoremap <C-S-TAB> :tabprev<CR>
“关于tab的快捷键
” map tn :tabnext<cr>
” map tp :tabprevious<cr>
” map td :tabnew .<cr>
” map te :tabedit
” map tc :tabclose<cr>
“窗口分割时,进行切换的按键热键需要连接两次,比如从下方窗口移动
“光标到上方窗口,需要<c-w><c-w>k,非常麻烦,现在重映射为<c-k>,切换的
“时候会变得非常方便.
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
“一些不错的映射转换语法(如果在一个文件中混合了不同语言时有用)
nnoremap <leader>1 :set filetype=xhtml<CR>
nnoremap <leader>2 :set filetype=css<CR>
nnoremap <leader>3 :set filetype=javascript<CR>
nnoremap <leader>4 :set filetype=php<CR>
” set fileformats=unix,dos,mac
” nmap <leader>fd :se fileformat=dos<CR>
” nmap <leader>fu :se fileformat=unix<CR>
” use Ctrl+[l|n|p|cc] to list|next|previous|jump to count the result
” map <C-x>l <ESC>:cl<CR>
” map <C-x>n <ESC>:cn<CR>
” map <C-x>p <ESC>:cp<CR>
” map <C-x>c <ESC>:cc<CR>

” 让 Tohtml 产生有 CSS 语法的 html
” syntax/2html.vim,可以用:runtime! syntax/2html.vim
let html_use_css=1
” Python 文件的一般设置,比如不要 tab 等
autocmd FileType python set tabstop=4 shiftwidth=4 expandtab
autocmd FileType python map <F12> :!python %<CR>
” 选中状态下 Ctrl+c 复制
vmap <C-c> “+y
” 打开javascript折叠
let b:javascript_fold=1
” 打开javascript对dom、html和css的支持
let javascript_enable_domhtmlcss=1
” 设置字典 ~/.vim/dict/文件的路径
autocmd filetype javascript set dictionary=$VIMFILES/dict/javascript.dict
autocmd filetype css set dictionary=$VIMFILES/dict/css.dict
autocmd filetype php set dictionary=$VIMFILES/dict/php.dict
“—————————————————————–
” plugin – bufexplorer.vim Buffers切换
” \be 全屏方式查看全部打开的文件列表
” \bv 左右方式查看   \bs 上下方式查看
“—————————————————————–
“—————————————————————–
” plugin – taglist.vim  查看函数列表,需要ctags程序
” F4 打开隐藏taglist窗口
“—————————————————————–
if MySys() == “windows”                ” 设定windows系统中ctags程序的位置
let Tlist_Ctags_Cmd = ‘”‘.$VIMRUNTIME.’/ctags.exe”‘
elseif MySys() == “linux”              ” 设定windows系统中ctags程序的位置
let Tlist_Ctags_Cmd = ‘/usr/bin/ctags’
endif
nnoremap <silent><F4> :TlistToggle<CR>
let Tlist_Show_One_File = 1            ” 不同时显示多个文件的tag,只显示当前文件的
let Tlist_Exit_OnlyWindow = 1          ” 如果taglist窗口是最后一个窗口,则退出vim
let Tlist_Use_Right_Window = 1         ” 在右侧窗口中显示taglist窗口
let Tlist_File_Fold_Auto_Close=1       ” 自动折叠当前非编辑文件的方法列表
let Tlist_Auto_Open = 0
let Tlist_Auto_Update = 1
let Tlist_Hightlight_Tag_On_BufEnter = 1
let Tlist_Enable_Fold_Column = 0
let Tlist_Process_File_Always = 1
let Tlist_Display_Prototype = 0
let Tlist_Compact_Format = 1

“—————————————————————–
” plugin – mark.vim 给各种tags标记不同的颜色,便于观看调式的插件。
” \m  mark or unmark the word under (or before) the cursor
” \r  manually input a regular expression. 用于搜索.
” \n  clear this mark (i.e. the mark under the cursor), or clear all highlighted marks .
” \*  当前MarkWord的下一个     \#  当前MarkWord的上一个
” \/  所有MarkWords的下一个    \?  所有MarkWords的上一个
“—————————————————————–

“—————————————————————–
” plugin – NERD_tree.vim 以树状方式浏览系统中的文件和目录
” :ERDtree 打开NERD_tree         :NERDtreeClose    关闭NERD_tree
” o 打开关闭文件或者目录         t 在标签页中打开
” T 在后台标签页中打开           ! 执行此文件
” p 到上层目录                   P 到根目录
” K 到第一个节点                 J 到最后一个节点
” u 打开上层目录                 m 显示文件系统菜单(添加、删除、移动操作)
” r 递归刷新当前目录             R 递归刷新当前根目录
“—————————————————————–
” F3 NERDTree 切换
map <F3> :NERDTreeToggle<CR>
imap <F3> <ESC>:NERDTreeToggle<CR>

“—————————————————————–
” plugin – NERD_commenter.vim   注释代码用的,
” [count],cc 光标以下count行逐行添加注释(7,cc)
” [count],cu 光标以下count行逐行取消注释(7,cu)
” [count],cm 光标以下count行尝试添加块注释(7,cm)
” ,cA 在行尾插入 /* */,并且进入插入模式。 这个命令方便写注释。
” 注:count参数可选,无则默认为选中行或当前行
“—————————————————————–
let NERDSpaceDelims=1       ” 让注释符与语句之间留一个空格
let NERDCompactSexyComs=1   ” 多行注释时样子更好看

“—————————————————————–
” plugin – DoxygenToolkit.vim  由注释生成文档,并且能够快速生成函数标准注释
“—————————————————————–
let g:DoxygenToolkit_authorName=”Asins – asinsimple AT gmail DOT com”
let g:DoxygenToolkit_briefTag_funcName=”yes”
map <leader>da :DoxAuthor<CR>
map <leader>df :Dox<CR>
map <leader>db :DoxBlock<CR>
map <leader>dc a /*  */<LEFT><LEFT><LEFT>

“—————————————————————–
” plugin – ZenCoding.vim 很酷的插件,HTML代码生成
” 插件最新版:http://github.com/mattn/zencoding-vim
” 常用命令可看:http://nootn.com/blog/Tool/23/
“—————————————————————–
“—————————————————————–
” plugin – checksyntax.vim    JavaScript常见语法错误检查
” 默认快捷方式为 F5
“—————————————————————–
let g:checksyntax_auto = 0 ” 不自动检查
“—————————————————————–
” plugin – NeoComplCache.vim    自动补全插件
“—————————————————————–
let g:AutoComplPop_NotEnableAtStartup = 1
let g:NeoComplCache_EnableAtStartup = 1
let g:NeoComplCache_SmartCase = 1
let g:NeoComplCache_TagsAutoUpdate = 1
let g:NeoComplCache_EnableInfo = 1
let g:NeoComplCache_EnableCamelCaseCompletion = 1
let g:NeoComplCache_MinSyntaxLength = 3
let g:NeoComplCache_EnableSkipCompletion = 1
let g:NeoComplCache_SkipInputTime = ‘0.5’
let g:NeoComplCache_SnippetsDir = $VIMFILES.’/snippets’
” <TAB> completion.
inoremap <expr><TAB> pumvisible() ? “\<C-n>” : “\<TAB>”
” snippets expand key
imap <silent> <C-e> <Plug>(neocomplcache_snippets_expand)
smap <silent> <C-e> <Plug>(neocomplcache_snippets_expand)
“—————————————————————–
” plugin – matchit.vim   对%命令进行扩展使得能在嵌套标签和语句之间跳转
” % 正向匹配      g% 反向匹配
” [% 定位块首     ]% 定位块尾
“—————————————————————–
“—————————————————————–
” plugin – vcscommand.vim   对%命令进行扩展使得能在嵌套标签和语句之间跳转
” SVN/git管理工具
“—————————————————————–
“—————————————————————–
” plugin – a.vim

“—————————————————————–

[转载自:http://www.cnblogs.com/zourrou/archive/2011/04/16/2018493.html]

使用反向ssh从外网访问内网主机的方法详解

由于我们自己使用的电脑未必有外网ip,因此我们需要一个有固定外网ip的服务器(随便搞个腾讯云,阿里云的小机子就行),然后用这台服务器与内网的机子进行通信,我们到时候要先登陆自己的服务器,然后再利用这个服务器去访问内网的主机。
1、准备好有固定ip的服务器A,以及待访问的内网机器B。两者都开着sshd服务,端口号默认都是22。顺便做好ssh免密码登陆。
2、内网主机B主动连接服务器A,执行以下命令:
 >$ ssh -NfR 10000:localhost:22 username@servername -p 22
这条命令的意思是在后台执行(-f),不实际连接而是做port forwarding(-N),做反向ssh(-R),将远程服务器的10000端口映射成连接本机(B)与该服务器的反向ssh的端口。
附:这里有必要加强一下记忆,这个端口号一不小心就容易搞混

man文档中的参数命令是这样的:

-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket

bind_address以及其后面的port是指远程主机的ip以及端口,host以及其后的hostport是指本机的ip和端口。由于ssh命令本身需要远程主机的ip(上上条命令中的servername),因此这个bind_address原则上是可以省略的。
执行完这条命令,我们可以在服务器A上看到他的10000端口已经开始监听:
~]$ ss -ant | grep 10000
LISTEN 0 128 127.0.0.1:10000 *:*
3、在上面的操作中,这个1111端口就已经映射成了内网主机B的22端口了,现在我们只要ssh到自己的这个端口就行了。在服务器A中执行:
 >$ ssh username@localhost -p 10000
这样就成功的登陆了内网的主机了。
功能优化
上面的做法其实有一个问题,就是反向ssh可能会不稳定,主机B对服务器A的端口映射可能会断掉,那么这时候就需要主机B重新链接,而显然远在外地的我无法登陆B

这其实有一个非常简单的解决方案,就是用autossh替代步骤2中的ssh:
C:\ > autossh -M 2222 -NfR 10000:localhost:22 username@servername -p 22
后面的参数跟ssh都一样,只是多了一个-M参数,这个参数的意思就是用本机的2222端口来监听ssh,每当他断了就重新把他连起来。。。不过man文档中也说了,这个端口又叫echo port,他其实是有一对端口的形式出现,第二个端口就是这个端口号加一。因此我们要保证这个端口号和这个端口号加一的端口号不被占用。

有时,我们会想在局域网外访问局域网内的机器。这时,我们可以使用SSH的反向连接来实现。
设备A:位于局域网内,可以访问代理服务器B。 假设该设备IP:A.A.A.A,用户名userA
设备B:位于局域网外,作为访问设备A的代理服务器,不可访问A。假设该设备IP:B.B.B.B,用户名userB
设备C:想要访问A的设备,可以访问B,无法直接访问A。假设该设备IP:C.C.C.C,用户名userC

目标:设备C可以通过SSH访问局域网内设备C

条件:三台设备都需要包含SSH客户端,A,B设备需要包含SSH服务端。

在A设备上建立A设备到B设备的反向代理:

ssh -fCNR <port_b1>:localhost:22 userB@B.B.B.B

例如:ssh -fCNR 10000:localhost:22 userB@B.B.B.B (此时B设备上已经可以通过ssh -p 10000 userA@localhost连接到设备A)

<port_b1>:建立在B机器上,用来代理设备A机器22端口的端口。

userB@B.B.B.B :B机器的用户名和IP地址。

在B设备上建立B设备到A设备的正向代理:(这样做的目的是为了实现和外网的通信)

ssh -fCNL *:<port_b2>:localhost:<port_b1> userB@localhost

例如:ssh -fCNL *:10001:localhost:10000 userB@localhost

<port_b2>:用作本地转发的端口,用来和外网通信,并将数据转发到<port_b1>,实现从其他机器可以访问。

*代表可以接受来自任意机器的访问。

现在C机器上可以通过B机器SSH到A机器

ssh -p<port_b2> userA@B.B.B.B

参数介绍

-f 后台运行-C 允许压缩数据-N 不执行任何命令-R 将端口绑定到远程服务器,反向代理-L 将端口绑定到本地客户端,正向代理

STUN协议,探测NAT类型

1, STUN客户端(101:10)向STUN服务器(404:40)发送请求,要求得到自身经NAT映射后的地址(202:20):
      a,收不到服务器回复,则认为UDP被防火墙阻断,不能通信,网络类型:Blocked.
      b,收到服务器回复(地址要嘛是映射地址要嘛就是源地址),对比本地地址,如果相同(直接返回的就是源地址101:10),则认为无NAT设备(没经过NAT映射转换),进入第2步,否则认为有NAT设备,进入3步.
   2,(已确认无NAT设备)STUN客户端向STUN服务器发送请求,要求服务器从其他IP和PORT(505:50)向客户端回复包:
      a,收不到服务器从其他IP地址的回复,认为包被前置防火墙阻断,网络类型:Symmetric UDPFirewall.(如果没有NAT的话是无论如何都能收到回复的,只有一点受到防火墙的阻断,有时候杀毒软件也阻断)

b,收到则认为客户端处在一个开放的网络上,网络类型:Opened.

   3,(已确认存在NAT设备)STUN客户端(101:10)向STUN服务器(404:40)发送请求,要求服务器从其他IP和PORT(505:50)向客户端回复包:

a,收不到服务器从其他IP地址(包括IP和Port)的回复,认为包被前置NAT设备阻断,进入第4步.(如果不是前置的就相当于全开Opened或Full ConeNat类型,无论那个IP和端口都能接收到回复)
      b,收到则认为NAT设备类型为Full Cone,即网络类型:Full Cone NAT.(此没有什么限制的基本和没有NAT一样Opened)
  4, STUN客户端(101:10)向STUN服务器(404:40)的另外一个IP地址(505:40,端口不能改变)发送请求,要求得到自身经NAT映射后的地址(202:20,如果不是对称的应该返回这个映射地址),并对比之(与第一步中返回的映射地址比对)
      a,地址不相同,则网络类型:Symmetric NAT.(如果是对称类型,则101:10在向一个不同的IP地址(505,端口不变)发送请求时会映射一个新的端口,此处相当于生成一个202:21,比对不相同)
      b,相同则认为是Restricted NAT(受限的),进入第5步,进一步确认类型.
5, (已确认RestrictedNAT设备)STUN客户端(101:10)向STUN服务器(404:40)发送请求,要求服务器从相同IP(404)的其他PORT(41)向客户端回复包:
      a,收不到服务器从其他PORT地址的回复,认为包被前置NAT设备阻断,网络类型:Port Restricted coneNAT.(端口改变了,端口受限相当于我一个人A(101)向B(404)要右手(40端口)的苹果,而B左手(41端口)有个香蕉,A只要B的右手苹果,而B给了A一个左手的香蕉,A肯定是不要的,相当于收不到回复)
      b,收到则认为网络类型: Restricted cone NAT.(IP受限,对端口没什么要求,只要是404

这个IP就行,无论用那个端口都行)

以上实现过程作为服务器只有双IP的服务器才能实现,针对我们这些电脑只有一个IP的开发者来说,我们就得通过两台电脑来模拟实现双IP了,这地方上面请求的服务器地址就得改变一下了,个人认为这里的Server1:404地址的端口必须和Server2:505地址的端口一样,才能实现,端口相同也不会影响测试效果的.

来源:http://blog.csdn.net/hack8/article/details/6593768

客户端主机所在网络可以分为以下类型:

1, Opened: 即主机拥有公网IP,并且没有防火墙,可自由与外部通信.

2, Full Cone NAT: 主机前有NAT设备,

NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,并且从任意外部地址发送到该NAT设备UDP端口B的包都会被转到主机端口A.

3, Restricted cone NAT: 主机前有NAT设备,

 NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,但只有从之前该主机发出包的目的IP发出到该NAT设备UDP端口B的包才会被转到主机端口A.

4, Port Restricted cone NAT: 主机前有NAT设备,

  NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,但只有从之前该主机发出包的目的IP/

历经 4 年半的开发,Sublime Text 3.0 正式版终发布

Sublime Text 3.0 正式发布:提供 Linux 软件包仓库支持

历经 4 年半的开发,Sublime Text 3.0  正式版终于发布了!3.0 带来了崭新的 UI 主题,新的颜色主题以及新的图标。此外,在格式高亮方面有较大改进,也支持 Windows 上的触摸板输入、支持 macOS 的 Touch Bar,以及为 Linux 提供了软件包仓库支持!

相对于 Sublime Text 2 而言,新版编辑器几乎每一个方面都有改进,所以即便是主要变更列表也显得太长了,具体可以关注这个页面

3.0 版的新特性包括:定义跳转、新的语义高亮引擎、新的用户界面和丰富的 API。改进拼写检查和自动缩进,自动换行能也更好的处理源代码,对高分屏支持更好,任意跳转也更加智能。

在 Sublime Text 3 中最令人骄傲的一点是性能:它比历史上发布过的任何一个 Sublime Text 2 版本都要快得多,启动快、打开文件快、甚至内容滚动都快。虽然它的体积比 2 要大,但是却更轻快。

J2EE框架 Spring

J2EE框架 Spring 推荐

J2EE框架 面向方面AOP/IoC Web框架
Apache
Java
跨平台

Spring Framework 是一个开源的Java/Java EE全功能栈(full-stack)的应用程序框架,以Apache许可证形式发布,也有.NET平台上的移植版本。该框架基于 Expert One-on-One Java EE Design and Development(ISBN 0-7645-4385-7)一书中的代码,最初由 Rod Johnson 和 Juergen Hoeller等开发。Spring Framework 提供了一个简易的开发方式,这种开发方式,将避免那些可能致使底层代码变得繁杂混乱的大量的属性文件和帮助类。

Spring 中包含的关键特性:

  • 强大的基于 JavaBeans 的采用控制翻转(Inversion of Control,IoC)原则的配置管理,使得应用程序的组建更加快捷简易。
  • 一个可用于从 applet 到 Java EE 等不同运行环境的核心 Bean 工厂。
  • 数据库事务的一般化抽象层,允许宣告式(Declarative)事务管理器,简化事务的划分使之与底层无关。
  • 内建的针对 JTA 和 单个 JDBC 数据源的一般化策略,使 Spring 的事务支持不要求 Java EE 环境,这与一般的 JTA 或者 EJB CMT 相反。
  • JDBC 抽象层提供了有针对性的异常等级(不再从SQL异常中提取原始代码), 简化了错误处理, 大大减少了程序员的编码量. 再次利用JDBC时,你无需再写出另一个 ‘终止’ (finally) 模块. 并且面向JDBC的异常与Spring 通用数据访问对象 (Data Access Object) 异常等级相一致.
  • 以资源容器,DAO 实现和事务策略等形式与 Hibernate,JDO 和 iBATIS SQL Maps 集成。利用众多的翻转控制方便特性来全面支持, 解决了许多典型的Hibernate集成问题. 所有这些全部遵从Spring通用事务处理和通用数据访问对象异常等级规范.
  • 灵活的基于核心 Spring 功能的 MVC 网页应用程序框架。开发者通过策略接口将拥有对该框架的高度控制,因而该框架将适应于多种呈现(View)技术,例如 JSP,FreeMarker,Velocity,Tiles,iText 以及 POI。值得注意的是,Spring 中间层可以轻易地结合于任何基于 MVC 框架的网页层,例如 Struts,WebWork,或 Tapestry。
  • 提供诸如事务管理等服务的面向方面编程框架。

在设计应用程序Model时,MVC 模式(例如Struts)通常难于给出一个简洁明了的框架结构。Spring却具有能够让这部分工作变得简单的能力。程序开发员们可以使用Spring的 JDBC 抽象层重新设计那些复杂的框架结构。

高性能PHP框架 Phalcon

BSD
PHP,C
跨平台

PhalconPHP 是一个使用 C 扩展开发的 PHP Web 框架,提供高性能和低资源占用。

Phalcon 是一个开源的、全堆栈的 PHP 5 框架,使用 C 扩展编写,专门为高性能优化。无需学习和使用 C 语言,所有函数都以 PHP 类的方式曾现。Phalcon 是一个松耦合的框架。

使用时需在 php.ini 中添加:extension=phalcon.so

参考:https://www.oschina.net/p/phalcon

卡巴斯基悲催:美国全力封杀全球第一杀软

虽然在AV-TEST最新杀软评测中,卡巴斯基得到了满分成为第一,但美国依然不允许它出现在政府采购名录中,而这个封杀的事态还在加剧。

据外媒CNET报道称,除了美国的政府机构外,FBI也在悄悄暗示那些私营机构停止使用卡巴斯基,情况十分严重。

报道中提到,能源行业以及使用工业控制系统等企业,都在被警告的名单中,而按照美国的意思,就是先让该国企业尽可能快的从其系统中移除卡巴斯基。

虽然卡巴严正否认自己进行涉嫌收集不法信息的“间谍”活动,甚至可以交出软件源代码,但目前的情况是,这丝毫没有打动当局控制者,而消息中还透露,俄罗斯也正努力移除美国科技公司如微软的操作系统。

对于微软来说,这件事他们暗地里非常开心,因为这样可以让更多的用户来换用Windows Defender,尤其是随着创意者更新全面升级的“新安全中心”。

来自:驱动之家

转自:https://www.oschina.net/news/87919/kaspersky-banned-by-american-government

IceGrid应用配置[转]

1. 概述

1.1 配置目标

本文档是描述Ice中间件中的IceGrid服务的应用配置,通过使用IceGrid服务来实现:
1. 服务器端服务分布式部署。
2. 服务器端服务按需激活。
3. 服务器端服务多节点负载均衡。
4. 注册服务主/从热备(Master/Slaves)
5. 集成IceBox服务

1.2 实验环境

1. 硬件:hp服务器,3台
2. 操作环境:Red Hat 5
3. 服务器程序:ServerApp.jar
4. 说明:实际应用中,服务器节点可任意扩充、操作系统可被更换、服务器程序可用实际项目的服务程序替换,本文档所描述的配置方式具有通用性,适用但不局限于当前实验环境。

1.3 局限

本文档不详细描述IceGrid服务的运行机制和实现原理,不详细介绍服务器端和客户端程序的实现,主要描述IceGrid服务应用的配置步骤、主要配置项及验证配置结果等。

2. 配置过程

2.1 服务器端配置

配置步骤:
1. 创建主注册服务(Master)的配置文件config_master.grid,文件名称可以任意
2. 创建从注册服务(Slave)的配置文件 config_slave.grid, 文件名称可以任意
3. 创建各节点服务的配置文件config.node,文件名称可以任意
4. 创建分布式应用配置文件app.xml,文件名称可以任意,但格式最好定义成xml
5. 运行Ice提供的工具,启动我们的分布式应用,主要有如下两个工具:icegridnode和icegridadmin。详细启动过程如下:
1) icegridnode–Ice.Config=config_master.grid 启动主注册服务
2) icegridnode–Ice.Config=config_slave.grid 启动从注册服务
3) icegridadmin–Ice.Config= config_master.grid -e “application add app.xml” 部署分布式服务
icegridadmin –Ice.Config= config_master.grid-e “application update app.xml” 重新部署分布式服务
4) icegridnode–Ice.Config=config.node 将各节点注册到注册服务的注册表中
配置文件清单:
假设有n个节点(n > 0), 其中从注册服务有x个,(x > 0)
config_master.grid ———- 主注册服务配置文件 ——— 1份
config_slave.grid ———– 从注册服务配置文件 ——— x份
config.node —————– 节点配置文件 ————– n份
app.xml ———————- 部署配置文件 ————– 1份
通常情况下,由于注册服务占用资源很少,所以一般都会和一个节点集成在一起,并且可以和节点服务在一个进程中运行。因此,如果假设服务部署到n个服务器,通常情况下配置文件清单如下:
config_master.grid– 主注册服务配置文件 — 1份 — 主注册服务信息+节点信息
config_slave.grid— 从注册服务配置文件 — x份 — 从注册服务信息+节点信息
config.node——— 节点配置文件 —- n-1-x份 — 节点信息
app.xml————- 部署配置文件 ——– 1份 — 部署信息
其中app.xml要和config_master.grid放在一台服务器上,下面的各章节将详细介绍各配置文件。

2.1.1 主注册服务配置

config_master.grid的内容:

#
# The IceGrid InstanceName
#
IceGrid.InstanceName=YunIceGrid # 1
#
# The IceGridlocator proxy.
#
Ice.Default.Locator=YunIceGrid/Locator:default-h liyunde.com -p 4061:default -h ice.liyunde.com -p 4061 #2
#
# IceGridregistry configuration.
#
IceGrid.Registry.Client.Endpoints=default-p 4061 #3
IceGrid.Registry.Server.Endpoints=default #4
IceGrid.Registry.Internal.Endpoints=default #5
IceGrid.Registry.Data=master #6
IceGrid.Registry.PermissionsVerifier=YunIceGrid/NullPermissionsVerifier #7
IceGrid.Registry.AdminPermissionsVerifier=YunIceGrid/NullPermissionsVerifier#8
IceGrid.Registry.SSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier#9
IceGrid.Registry.AdminSSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier #10
#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB #11
#IceGrid.SQL.DatabaseType=QSQLITE #12
#IceGrid.SQL.DatabaseName=register/Registry.db #13
#
#
#Ice Error andStandard output Set
#
#Ice.StdErr=master/stderr.txt #14
#Ice.StdOut= master/stdout.txt #15
#
#Trace Registryproperties
#
Ice.ProgramName=Master #16
IceGrid.Registry.Trace.Node=3 #17
IceGrid.Registry.Trace.Replica=3 #18
#
# IceGrid nodeconfiguration.
#
IceGrid.Node.Name=node_1 #19
IceGrid.Node.Endpoints=default #20
IceGrid.Node.Data=node_1 #21
IceGrid.Node.CollocateRegistry=1 #22
#IceGrid.Node.Output=node_1 #23
#IceGrid.Node.RedirectErrToOut=1 #24
# Traceproperties.
#
IceGrid.Node.Trace.Activator=1 #25
#IceGrid.Node.Trace.Adapter=2 #26
#IceGrid.Node.Trace.Server=3 #27
#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid #28
IceGridAdmin.Password=mygrid #29

配置项说明:
#1 为这个应用实例指定一个唯一的标识
# 2 注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到
# 3 客户端访问注册服务器的端点信息
# 4 服务访问注册服务器的端点信息,通常是default
# 5 内部访问端点信息,通常是default,节点用这个端口和注册服务通信
# 6 注册服务的数据目录的路径
# 7 设定防火墙安全代理,从而控制客户端访问注册表时可用的权限
# 8 设定防火墙安全代理,从而控制注册表管理者可用的权限
# 9 设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制
# 10 设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制
# 11 指定Ice对象序列化的机制,如果不设置,默认用Freeze机制
# 12 指定使用数据库的类型
#13 指定使用数据库的名称
#14 指定标准错误输出文件
#15 指定标准输出文件
#16 指定主注册服务的名称
#17 指定主注册服务跟踪节点信息的级别(0~3),默认为0
#18 指定主/从热备注册服务的跟踪级别(0~3),默认为0
# 19 定义节点的名称,必须唯一
# 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
# 21 节点的数据目录的路径
# 22 定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置
# 23 节点标准输出信息重定向蹈的目录路径,会自动生成输出文件
# 24 节点上的服务程序的标准错误重定向到标准输出
# 25 激活器跟踪级别,通常有0,1,2,3级,默认是0
# 26 对象适配器跟踪级别,通常有0,1,2,3级,默认是0
# 27 服务跟踪级别,通常有0,1,2,3级,默认是0
# 28 IceGrid管理器登录该应用的用户名
# 29 IceGrid管理器登录该应用的密码
未涉及的属性还有一些,如果需要请参考官方文档。

2.1.2 从注册服务配置

config_slave.grid的内容:
#
# The IceGridlocator proxy.
#
Ice.Default.Locator=YunIceGrid/Locator:default-h 10.0.2.241 -p 4061:default -h 10.0.2.242-p 4061 #1
#
# IceGridregistry configuration.
#
IceGrid.Registry.Client.Endpoints=default-p 4061 #2
IceGrid.Registry.Server.Endpoints=default #3
IceGrid.Registry.Internal.Endpoints=default #4
IceGrid.Registry.Data=slave_1 #5
IceGrid.Registry.ReplicaName=slave_1 #6
IceGrid.Registry.PermissionsVerifier=YunIceGrid/NullPermissionsVerifier #7
IceGrid.Registry.AdminPermissionsVerifier=YunIceGrid/NullPermissionsVerifier#8
IceGrid.Registry.SSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier#9
IceGrid.Registry.AdminSSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier #10
#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB #11
#IceGrid.SQL.DatabaseType=QSQLITE #12
#IceGrid.SQL.DatabaseName=register/Registry.db #13
#
#Ice Error andStandard output Set
#
#Ice.StdErr=slave_1/stderr.txt #14
#Ice.StdOut=slave_1/stdout.txt #15
#
#Trace Registryproperties
#
Ice.ProgramName=Slave_1 #16
IceGrid.Registry.Trace.Node=3 #17
IceGrid.Registry.Trace.Replica=3 #18
#
# IceGrid nodeconfiguration.
#
IceGrid.Node.Name=node_2 #19
IceGrid.Node.Endpoints=default #20
IceGrid.Node.Data=node_2 #21
IceGrid.Node.CollocateRegistry=1 #22
#IceGrid.Node.Output=node_2 #23
#IceGrid.Node.RedirectErrToOut=1 #24
# Traceproperties.
#
IceGrid.Node.Trace.Activator=1 #25
#IceGrid.Node.Trace.Adapter=2 #26
#IceGrid.Node.Trace.Server=3 #27
#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid #28
IceGridAdmin.Password=mygrid #29
配置项说明:
其实这个文件和主注册配置文件基本一样,差别只有一点:
1. 没有指定应用实例名,因为在主注册服务中已经有了定义
2. 多了第6行,IceGrid.Registry.ReplicaName=slave_1,指定从注册服务的名称
其它的基本就没有差别了,大部分属性项在config_master.grid里面都有定义,为了方便阅读,下面也将用到的各项给出说明:
# 1 注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到
# 2 客户端访问注册服务器的端点信息
# 3 服务访问注册服务器的端点信息,通常是default
#4 内部访问端点信息,通常是default,节点用这个端口和注册服务通信
# 5 注册服务的数据目录的路径
# 6 指定从注册服务的名称
# 7 设定防火墙安全代理,从而控制客户端访问注册表时可用的权限
#8 设定防火墙安全代理,从而控制注册表管理者可用的权限
# 9 设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制
#10 设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制
# 11 指定Ice对象序列化的机制,如果不设置,默认用Freeze机制
# 12 指定使用数据库的类型
#13 指定使用数据库的名称
#14 指定标准错误输出文件
#15 指定标准输出文件
#16 指定从注册服务运行时程序名称
#17 指定从注册服务跟踪节点信息的级别(0~3),默认为0
#18 指定主/从热备注册服务的跟踪级别(0~3),默认为0
# 19 定义节点的名称,必须唯一
# 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
# 21 节点的数据目录的路径
# 22 定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置
# 23 节点标准输出信息重定向蹈的目录路径,会自动生成输出文件
# 24 节点上的服务程序的标准错误重定向到标准输出
# 25 激活器跟踪级别,通常有0,1,2,3级,默认是0
# 26 对象适配器跟踪级别,通常有0,1,2,3级,默认是0
# 27 服务跟踪级别,通常有0,1,2,3级,默认是0
# 28 IceGrid管理器登录该应用的用户名
# 29 IceGrid管理器登录该应用的密码

2.1.3 应用部署配置

app.xml配置文件内容:

1<icegrid>

2 <application name=“RTDSSystem”>

3 <server-template id=“RTDSSystemServer”>

4 <parameter name=“index”/>

5 <server id=“RTDSSystemServer-${index}”exe=Java activation=“on-demand”>

6 <adapter name=“RTDataSysytem” endpoints=“tcp” replica-group=“ReplicatedRTDataSysytemAdp”/>

7 <option>-jar</option>

8 <option>ServerApp.jar</option>

9 </server>

10 </server-template>

11

12 <replica-group id=“ReplicatedRTDataSysytemAdp”>

13 <load-balancing type=“round-robin”/>

14 <object identity=“RTDataSource” type=“::RTDataSystem::RTDataSource”/>

15 </replica-group>

16

17 <node name=“node_1”>

18 <server-instance template=“RTDSSystemServer” index=“1”/>

19 <server-instance template=“RTDSSystemServer” index=“11”/>

20 <server-instance template=“RTDSSystemServer” index=“111”/>

21 </node>

22 <node name=“node_2”>

23 <server-instance template=“RTDSSystemServer” index=“2”/>

24 <!–server-instancetemplate=”RTDSSystemServer” index=”22″/–>

25 <!–server-instancetemplate=”RTDSSystemServer” index=”222″/–>

26 </node>

27 <node name=“node_3”>

28 <server-instance template=“RTDSSystemServer” index=“3”/>

29 <!–server-instancetemplate=”RTDSSystemServer” index=”33″/–>

30 <!–server-instancetemplate=”RTDSSystemServer” index=”333″/–>

31 </node>

32 </application>

33</icegrid>

配置文件结构分析:

IceGrid里,部署是一个在注册服务中表述一个应用(Application)的过程,而部署配置文件就是来描述这些配置信息的文件,这个配置文件是用xml标记性语言来描述的。通常一个部署应该包含如下信息:

1. 应用标签(application),name属性定义这个应用的名字

2. 服务(server), 一个逻辑上的服务器,能够通过exe命令而启动的一个服务程序。activation属性,是设置服务的启动方式,on-demand是最常用的方式,另外还有always等启动方式;option标签是exe执行命令命令行的参数;

3. 适配器(adpter),定义服务器端的适配器。

name属性唯一标志这个适配器;

endpoints属性指定端点信息;

replica-group属性标示该适配器是个可复制组集群,并指定这个可复制组的名称;

register-process属性定义了是否这个节点是否可以被icegrid关闭;

4. 节点(node),它应该代表了一个物理上的节点。

name属性指定节点的名字,并且是唯一的。

5. 可复制组(replica-group),一组对象适配器的集合。

id属性唯一标识一个可复制组;

load-balancing子项中type属性指定负载均衡策略,icegrid提供了四种负载均衡策略: Random (随机方式)

Adaptive(适配方式)

Round Robin(最近最少使用)

Ordered(顺序方式)

object子项定义适配器绑定的服务对象信息。其中identity属性指定对象的标识,type属性指定了对象的层次结构类型。这两个属性都可以唯一的标识一个服务对象。

6. 服务模板(server-temple),服务模板是对服务的一个抽象,避免了重复定义。这样,在节点中描述服务时只需要实例化它的服务模板就可以了。

id属性唯一标识一个服务模板;

parameter子项定义服务模板的参数,可包含多个,主要实例化服务时用;

server子项就是上面2中的服务定义;

另外还有一些特殊的服务模板,比如:icebox服务模板,它的定义和通用的服务模板的定义不太一样。

解析app.xml文件:

通过对配置文件结构的分析,来解析一下app.xml。

第1行,标识这是一个icegrid的配置文件;

第2行,标识应用的名称为RTDSSystem,这个名称是唯一的;

第3~10行,定义了一个服务模板RTDSSystemServer,并有一个参数index;

其中5~9定义了这个模板包含的服务定义,第6行是这个服务包含的对象适配器

的定义;

第12~15行,是对可复制组的定义,包括服务对象的定义和负载均衡策略;

第17~21行,是对节点node_1的定义,指定了节点的名称,包含的服务(3个服务);

第22~26行,是对节点node_2的定义

第27~31行,是对节点node_3的定义

最后两行是闭合标签,至此一个icegrid的分布式部署配置文件就完成了。

部署配置文件的扩展:

app.xml中对服务模板、适配器、服务对象等的配置都是一个,事实上这些可以在文件中定义多个,比如可以有多个服务模板,一个服务里可以有多个适配器,可以有多个可复制组,一个节点里可以有多个不同类型的服务等。

另外,app.xml可以包含其它的xml。

2.1.4 节点配置

config.grid文件的内容:

# The IceGridlocator proxy.
#
Ice.Default.Locator=YunIceGrid/Locator:default-h 10.0.2.241 -p 4061:default -h 10.0.2.242-p 4061 #1
#
# IceGrid nodeconfiguration.
#
IceGrid.Node.Name=node_2 #2
IceGrid.Node.Endpoints=default #3
IceGrid.Node.Data=node_2 #4
IceGrid.Node.Output=node_2 #5
IceGrid.Node.RedirectErrToOut=1 #6
# Trace properties.
#
IceGrid.Node.Trace.Activator=1 #7
#IceGrid.Node.Trace.Adapter=2 #8
#IceGrid.Node.Trace.Server=3 #9

配置项说明:
事实上,这个文件里面的配置项,在config_slave.grid中都有描述,但这里也列出来,方便阅读。
#1 注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到
#2 定义节点的名称,必须唯一
#3 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
#4 节点的数据目录的路径
#5 节点标准输出信息重定向的目录路径,会自动生成输出文件
#6 节点上的服务程序的标准错误重定向到标准输出
#7 激活器跟踪级别,通常有0,1,2,3级,默认是0
#8 对象适配器跟踪级别,通常有0,1,2,3级,默认是0
#9 服务跟踪级别,通常有0,1,2,3级,默认是0

2.2 客户端配置

客户端的配置很简单,和分布式相关的配置就一项,添加如下:
#
# The IceGridlocator proxy.
#注册服务的端点信息(主注册服务和所有的从注册服务),用于定位
Ice.Default.Locator=YunIceGrid/Locator:default-h 10.0.2.241 -p 4061:default -h 10.0.2.242-p 4061

3. 结果验证

3.1 程序方式

1. 启动服务器
1) icegridnode–Ice.Config=config_master.grid 启动主注册服务和节点1
2) icegridnode–Ice.Config=config_slave.grid 启动从注册服务和节点2
3) icegridadmin–Ice.Config=config_master.grid -e “application add app.xml” 部署分布式服务
4) icegridnode–Ice.Config=config.node 启动节点3
2. 启动客户端,进行多次远程调用,根据执行情况就可以判断服务器端是否配置成功。

3.2 工具方式

用Ice官方提供的可视化管理工具IceGridGUI.jar来验证和管理icegrid的部署。
打开dos窗口,在命令行下进入C:\Program Files\ZeroC\Ice-3.4.1\bin目录下,然后运行“java –jar IceGridGUI.jar”,弹出IceGrid Admin的主界面

1. 高级应用配置

4.1 集成IceBox

在文档《IceBox开发和配置》(当前是1.0版)中,介绍了一个IceBox服务程序的开发方法和单独应用中配置和管理的过程。在实际的应用中,IceBox服务通常集成到IceGrid中,并通过IceGrid进行激活和部署。
本章节中IceBox服务是集成在IceGrid中,并通过IceGrid进行部署,所以IceBox服务的配置信息不再同《IceBox开发和配置》中一样在config.icebox中描述,而是直接配置在部署文件app.xml中。那也就是说,IceGrid集成IceBox服务,只需要在app.xml文件中添加Icebox服务相关的配置信息就可以了。事实上,有关Ice所有的配置信息(除IceGrid自身的配置信息),都可以添加到app.xml中,并通过icegrid部署后生效。
下面各节详细描述IceBox服务的集成过程。

4.1.1 IceBox服务程序编写

请参考文档《IceBox开发和配置》,这里不再详述。由于IceBox服务相关的配置信息都放在了app.xml中,并且服务是通过IceGrid按需激活的,因此这里程序代码略有调整。下面列出IceBox服务的实现代码:
文件名:ServerService.java

import main.java.DataSource;

import IceBox.Service;

public class ServerService implements IceBox.Service {

/**

* @param name 配置文件中的service名称

* @param communicator对象,由IceBox.ServiceManager负责创建和销毁。

* 可能同时被其他服务共享使用(由配置文件决定),object Adapter的名

* 称必须是唯一的;

* @param args 配置文件中的参数列表

* @Override

**/

public void start(String name,Ice.Communicator communicator,

String[] args){

//创建objectAdapter,名称有配置文件决定

Adapter =communicator.createObjectAdapter(

“RTDataSystem-“+name);

//创建servant

StringRTDataSourceIdentity = communicator.getProperties().

getProperty(“RTDataSource.Identity”);

DataSourceobjDataSrc = new DataSource(“dataSource”);

Adapter.add(objDataSrc,

communicator.stringToIdentity(RTDataSourceIdentity));

Adapter.activate();

}

/**

*

* @param args

* @Override

*

**/

public void stop()

{

Adapter.destroy();

}

private Ice.ObjectAdapter Adapter;

}

4.1.2 IceGrid集成IceBox服务

IceGrid集成IceBox只和部署文件(app.xml)有关,IceBox服务(service)的粒度和普通的server是一样的,因此IceBoxservice的部署和普通的server非常类似,它同样有模板、服务(service)和实例化的概念,可以将IceBox service理解为一个特殊的server。
为了能更清楚的描述这个集成配置的过程,在IceGrid配置的基础上,添加IceBox服务。具体目标如下:
1. 集成ServerService服务(service),并且ServerService服务(service)使用的服务对象和之前server的服务对象使用同一个(type–::RTDataSystem::RTDataSource)
2. 在节点1(node_1)上添加IceBox服务功能(IceBox-Node1),这个IceBox服务包含了5个ServerService服务;同样的在节点2(node_2)上也添加一个IceBox服务功能(IceBox-Node2),也包含了5个ServerService服务
3. 这些IceBox服务中分布的多个服务(service)和之前已经存在的服务(server)一起通过IceGrid实现负载均衡
为了实现上述的功能,需要添加IceBox服务的相关配置,首先看一下此时app.xml的变化,变化和添加部分用浅灰阴影标出。
app.xml
<?xml version=”1.0″encoding=”UTF-8″ ?>
<icegrid>
<applicationname=”RTDSSystem“>
<server-templateid=”RTDSSystemServer“>
<parameter name=”index“/>
<server id=”RTDSSystemServer-${index}” exe=”java“activation=”on-demand“>
<adapter name=”RTDataSysytem“endpoints=”tcp
replica-group=”RTDataSystemGroup“/>
<option>jar</option>
<option>ServerApp.jar</option>
</server>
</server-template>
<!— begin服务模板定义–>
1 <service-templateid=”RTDSystemService“>
2 <parameter name=”name“/>
3 <service name=”${name}” entry=”ServerService“>
4 <description>A simple service named after ${name}</description>
5 <properties>
6 <property name=”RTDataSource.Identity” value=”RTDataSource“/>
7 </properties>
8 <adapter name=”RTDataSystem-${name}” endpoints=”tcp
id=”RTDataSystem-${name}” replica-group=”RTDataSystemGroup
server-lifetime=”false“/>
11 </service>
12 </service-template>
<!– end服务模板定义–>
<replica-groupid=”RTDataSystemGroup“>
<load-balancingtype=”round-robin“/>
<!–load-balancingtype=”ordered” /–>
<!–load-balancingtype=”adaptive” /–>
<!–load-balancingtype=”random” n-replicas=”0″/–>
<object identity=”RTDataSource” type=”::RTDataSystem::RTDataSource“/>
</replica-group>
<node name=”node_1“>
<server-instancetemplate=”RTDSSystemServer” index=”1“/>
<server-instancetemplate=”RTDSSystemServer” index=”11“/>
<server-instancetemplate=”RTDSSystemServer” index=”111“/>
<!— begin IceBox服务配置 IceBox-Node1–>
1 <icebox id=”IceBox-Node1” activation=”on-demand“exe=”java”>
2 <description>Asample IceBox server IceBox-Node1</description>
3 <option>IceBox.Server</option>
4 <properties>
5 <property name=”IceBox.InstanceName” value=”${server}“/>
6 <property name=”Ice.Admin.Endpoints” value=”tcp -h 10.0.2.241“/>
7 <property name=”IceBox.Trace.ServiceObserver” value=”1“/>
8 </properties>
9 <service-instance template=”RTDSystemService” name=”one“/>
10 <service-instancetemplate=”RTDSystemService” name=”two“/>
11 <service-instancetemplate=”RTDSystemService” name=”three“/>
12 <service-instancetemplate=”RTDSystemService” name=”four“/>
13 <service-instancetemplate=”RTDSystemService” name=”five“/>
14 </icebox>
<!— end IceBox服务配置 IceBox-Node1–>
</node>
<node name=”node_2“>
<server-instancetemplate=”RTDSSystemServer” index=”2“/>
<server-instancetemplate=”RTDSSystemServer” index=”22“/>
<server-instancetemplate=”RTDSSystemServer” index=”222“/>
<!— begin IceBox服务配置 IceBox-Node2–>
1 <icebox id=”IceBox-Node2” activation=”on-demand“exe=”java“>
2 <description>Asample IceBox server IceBox-Node2</description>
3 <option>IceBox.Server</option>
4 <properties>
5 <property name=”IceBox.InstanceName” value=”${server}“/>
6 <property name=”Ice.Admin.Endpoints” value=”tcp -h 10.0.2.242“/>
7 <property name=”IceBox.Trace.ServiceObserver” value=”1“/>
8 </properties>
9 <service-instancetemplate=”RTDSystemService” name=”2-one”/>
10 <service-instancetemplate=”RTDSystemService” name=”2-two“/>
11 <service-instancetemplate=”RTDSystemService” name=”2-three“/>
12 <service-instancetemplate=”RTDSystemService” name=”2-four“/>
13 <service-instancetemplate=”RTDSystemService” name=”2-five“/>
14 </icebox>
<!— begin IceBox服务配置 IceBox-Node2–>
</node>
<node name=”node_3“>
<server-instancetemplate=”RTDSSystemServer” index=”3“/>
</node>
</application>
</icegrid>
app.xml中增加的IceBox服务相关的配置部分如下:
n 服务摸板(Service Template):
可以对比一下servertemplate的定义,两者基本上没有什么区别,最大的不同是
Server template中server是指定一个可执行的程序,而service中指定的是动态加载
的组件入口。以下解释上述配置中的服务模板的定义:
第1行指定定义模板的id,唯一标志一个服务模板,第12是闭合标签;
第2行定义了一个参数name,默认值是“name”;
第3~11行定义了模板中使用的服务(service),并在该service中指定了名称、
入口、描述信息、配置属性,定义了一个对象适配器;
第4行,是该服务的描述信息;
第5~7行,是属性定义列表,这里定义了一个属性RTDataSource.Identity,并
指定其值为RTDataSource;
第8行,定义了一个对象适配器,指定了其name、endpoints、id、replica-group
等属性信息,这个基本上和server中adapter的定义没有什么区别
以上内容就是service模板的定义。
n IceBox服务(IceBox-Node1):
icebox服务的定义被包含在分布的服务器节点中,主要包括三部分的信息:
1. IceBox服务的启动配置信息
2. IceBox的属性配置信息
3. Service服务实例化列表
下面解释这块内容:
第1~3行,指定了IceBox服务的名称,启动方式,启动执行程序等
第4~8行,指定了IceBox服务的属性配置列表,这里定义了IceBox服务的实
例名称、管理器访问端点以及service被跟踪的级别
第9~13行,实例化了5个service服务
至此,一个包含了5个serverservice服务的IceBox服务被集成在node1中。
n IceBox服务(IceBox-Node2)
同IceBox服务(IceBox-Node1)中描述,只是具体value有所不同,这里不再解释。

4.1.3 测试验证

验证方式同第3章,这里不再赘述。部署完成后,就可以通过IceGridGUI.jar程序来进行管理
参考来源:http://blog.csdn.net/educast/article/details/9414789

苹果下架中国区主流VPN应用

苹果下架中国区主流VPN应用

雷锋网(公众号:雷锋网)消息,根据纽约时报的报道,苹果下架了中国区App Store的一些主流VPN应用。

据报道,一些公司收到了来自苹果的通知,称他们的APP已从中国区应用市场下架。

一个名为ExpressVPN的应用在其博客上称,苹果给出的解释是产品违反了中国法律,应用中包含一些非法的内容。这家公司还称,他们发现所有的主流iOS端VPN应用都被下架了。

苹果下架中国区主流VPN应用

ExpressVPN收到的通知

另一家名为Star VPN的应用也称收到了同样的通知。

雷锋网以VPN为关键词搜索中国区苹果商店,发现还是有很多应用可以下载。不过上述两家的应用确实搜不到。

之前有消息称,明年2月国内会停止所有VPN服务,不过后来工信部称,规范对象主要是未经电信主管部门批准,无国际通信业务经营资质企业和个人。

苹果越来越重视中国市场。不久前雷锋网报道,苹果将在贵州建其在中国的首个数据中心。另外,一个多星期前,苹果还宣布任命原苹果无线技术副总裁葛越女士担任大中华区董事总经理,全面负责中国的业务和团队,而且这一职位为新设立的。

雷锋网原创文章,未经授权禁止转载。详情见转载须知

来源:https://www.leiphone.com/news/201707/nB4mZxwvxz3iYaPy.html

此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求

此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求

FirFox打开80以外的端口,会弹出以下提示:

“此地址使用了一个通常用于网络浏览以外的端口。出于安全原因,Firefox 取消了该请求。”。

其实是使用了不安全的端口,解决方法如下:

1.在Firefox地址栏输入about:config

2.在右键新建一个字符串键 network.security.ports.banned.override

将需访问网站的端口号添加到,值就是那个端口号即可。
如有多个,就半角逗号隔开,例:81,88,98

在能保证安全的前提下,还简化成这样写1025-65535。

这样,就可以浏览指定范围任意端口的网站了。

chrome 参考:http://my.liyunde.com/chrome-err_unsafe_port/

chrome 谷歌浏览器出现 错误代码:ERR_UNSAFE_PORT 的解决办法

1、问题描述:

使用谷歌浏览器访问一个WEB项目,该项目设置的端口号为6000,结果不能访问:
 
2、问题所在:
出现此类问题的原因不是服务器端的问题,而是谷歌浏览器(FF浏览器也有)对一些特殊的端口进行了限制,具体有哪些端口进行了访问限制,请参见本文末。
 
3、问题解决:
最简单的办法就是直接修改搭建项目的端口号,避开这些谷歌限制的端口号。
 
谷歌浏览器限制的一些端口号:
1:    // tcpmux
7:    // echo
9:    // discard
11:   // systat
13:   // daytime
15:   // netstat
17:   // qotd
19:   // chargen
20:   // ftp data
21:   // ftp access
22:   // ssh
23:   // telnet
25:   // smtp
37:   // time
42:   // name
43:   // nicname
53:   // domain
77:   // priv-rjs
79:   // finger
87:   // ttylink
95:   // supdup
101:  // hostriame
102:  // iso-tsap
103:  // gppitnp
104:  // acr-nema
109:  // pop2
110:  // pop3
111:  // sunrpc
113:  // auth
115:  // sftp
117:  // uucp-path
119:  // nntp
123:  // NTP
135:  // loc-srv /epmap
139:  // netbios
143:  // imap2
179:  // BGP
389:  // ldap
465:  // smtp+ssl
512:  // print / exec
513:  // login
514:  // shell
515:  // printer
526:  // tempo
530:  // courier
531:  // chat
532:  // netnews
540:  // uucp
556:  // remotefs
563:  // nntp+ssl
587:  // stmp?
601:  // ??
636:  // ldap+ssl
993:  // ldap+ssl
995:  // pop3+ssl
2049: // nfs
3659: // apple-sasl / PasswordServer
4045: // lockd
6000: // X11
6665: // Alternate IRC [Apple addition]
6666: // Alternate IRC [Apple addition]
6667: // Standard IRC [Apple addition]
6668: // Alternate IRC [Apple addition]
6669: // Alternate IRC [Apple addition]

Log4j2.xml Eclipse 添加自动提示

参考:https://issues.apache.org/jira/browse/LOG4J2-411

Support of XSD/DTD linked to the configuration file

It would be very nice, if the the XML configuration uses an dedicated namespace, e.g. http://logging.apache.org/log4j/2.0/config.
This feature allows using XML catalogs to locate the schema locally, e.g. with Eclipse IDE.
The Log4j-events.xsd contains already such a declaration:

targetNamespace="http://logging.apache.org/log4j/2.0/events"

Then the configuration XML file needs only a small extension:

log4j2.xml
<?xml version="1.0" encoding="utf-8"?>
<Configuration status="WARN" xmlns="http://logging.apache.org/log4j/2.0/config">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
    </Console>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

Java9新功能之HTTP2和REPL

本文转自:云栖社区云

【摘要】对Java 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。 在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生…

对Java 9的炒作将不再局限于模块化(modularity),Java 9正在搜罗大量额外的功能模块,这些功能模块正作为Java增强提案(JEP)提交,并在OpenJDK (Java SE的参考实现项目)中实现。

在这篇文章中,我们将重点关注一些或将在Java 9整个生命周期中,对开发者的工作生活影响最大的JEP,包括新的HTTP/2支持和JShell REPL(读取-求值-打印-循环),后者带来了基于shell的交互式Java开发环境和探索性开发API。

HTTP/2

HTTP/2标准是HTTP协议的最新版本。当前版本HTTP/1.1始于1999年,存在着非常严重的问题,包括:

对头阻塞

在HTTP/1.1中,响应接收的顺序和请求发送的顺序相同。这意味着,例如,当查看一个包含许多小图像的大HTML页面时,图像资源将不得不在HTML页面资源之后排队,在浏览器完全加载完HTML页面之前,图像资源无法被发送。这就是“对头阻塞”,会导致许多潜在的页面渲染问题。

在HTTP/2中,响应数据可以按块(chunk)传输,甚至可以交叉传输,因此真正实现了请求和响应的多路复用。

一个站点的连接数限制

在HTTP/1.1标准中有这样的描述:“一个单用户的客户端不能与任何服务器保持2个以上的连接”。这个限制和对头阻塞问题一起,严重限制了页面的性能。

HTTP/2打破这种限制并认为连接是持久的,只有当用户跳转后或者发生技术性故障事件时,连接才会关闭。对多路复用的使用将有助于降低页面性能瓶颈。

HTTP控制头的开销

当前的HTTP版本使用简单的、基于文本的HTTP头信息来控制通信。这样做的优点是非常简单且易于理解,调试也很简单,只需通过连接指定端口并输入一些文本。然而,使用基于文本的协议会让小的响应包不成比例地膨胀。此外,大量的HTTP响应几乎没有或者根本没有有效负载(比如,HEAD请求只是要确定资源是否发生变化)。为实际上只包含最后修改时间的响应,使用完全基于文本的头信息(大约有700个字节,在HTTP1.1中,它们不能被压缩,尽管很容易做到)是当前HTTP标准中,不可思议的浪费。

另一个思路是对HTTP头信息使用二进制编码。这种方式能够极大地提高较小请求的速度且占用的网络带宽非常小。这正是HTTP/2已经选择的方法,虽然以协议精神制定标准应该选择基于文本的协议,但是二进制的效率有令人信服的理由,让我们这样做。

HTTP/2带来的期望

HTTP/2标准是由IETF HTTP工作组创建的,该组织由来自Mozilla、Google、 Microsoft、Apple,以及其他公司的代表和工程师组成,由来自CDN领军公司Akamai的高级工程师Mark Nottingham任主 席。因此,HTTP/2是一个为优化大型、高流量的网站而生的版本,它在实现简单、易于调试的基础上,确保了性能和网络带宽消耗。

该组织主 席总结了一些HTTP/2的关键属性:

相同的HTTP API成本更低的请求网络和服务器端友好缓存推送思维革命更多加密方式

带给Java的意义

自从1.0版本开始,Java就支持HTTP,但是多数代码出自完全不同的时代。例如,Java对HTTP的支持是围绕相对协议无关的框架(URL类)设计的,因此在网站成为主导地位的90年代,这种实现显得很不清晰。

Java对HTTP的支持是基于当时最好的设计思想,但是时过境迁,最重要的是Java对HTTP原始的支持出来时,HTTPS还没有出现。因此,Java的API将HTTPS作为一种移花接木,导致了不能简化的复杂性。

在现代社会,HTTPS开始变得无所不在,让HTTP日渐成为落后的技术。甚至,美国政府现在都通过了完全迁到HTTPS-only的计划。

JDK内核对HTTP的支持已经无法跟上现实网络的发展步伐。实际上,甚至JDK8也只不过是交付了一个支持HTTP/1.0的客户端,然而,大多数的开发者早已转而使用第三方客户端库了,比如Apache的HttpComponents。

所有这一切意味着,对HTTP/2的支持将是Java未来十年的核心功能。这也让我们重新审视我们的固有思维,重新写一套API并提供重新来过的机会。HTTP/2将是未来数年内,每位开发者主要面对的API。

新的API不再坚持协议中立性,使开发者可以完全抛弃过去的使用方式。这套API只关注HTTP协议,但是要进一步理解的是HTTP/2并没有从根本上改变原有的语义。因此,这套API是HTTP协议独立的,同时提供了对新协议中帧和连接处理的支持。

在新的API中,一个简单的HTTP请求,可以这样创建和处理:

HttpResponse response = HttpRequest .create(new URI(“http://www.infoq.com”)) .body(noBody()) .GET().send(); int responseCode = response.responseCode(); String responseBody = response.body(asString()); System.out.println(responseBody);

这种符合流畅风格/建造者模式(fluent/builder)的API,与现存的遗留系统相比,对开发者来说,更具现代感和舒适感。

虽然当前的代码库只支持HTTP/1.1,但是已经包含了新的API。这使得在对HTTP/2支持完成对过程中,开发者可以实验性地使用和验证新的API。

相关代码已经进入OpenJDK沙箱仓库中,并很快登陆JDK 9的主干。到那个时候,新的API将开始自动构建到Oracle的二进制beta版本中。现在,对HTTP/2的支持已经可用,并将在未来数月内最终完成。

在此期间,你可以使用Mercurial迁出源代码,并根据AdoptOpenJDK构建指导编译你迁出地代码,这样你就可以实验性地使用新的API了。

第一批完成的功能之一是当前版本力不能及的异步API。这个功能让长期运行的请求,可以通过sendAsync()方法,切换到VM管理的后台线程中:

HttpRequest req = HttpRequest .create(new URI(“http://www.infoq.com”)) .body(noBody()) .GET(); CompletableFuture<HttpResponse> aResp = req.sendAsync(); Thread.sleep(10); if (!aResp.isDone()) { aResp.cancel(true); System.out.println(“Failed to reply quickly…”); return; } HttpResponse response = aResp.get();

相比HTTP/1.1的实现,新的API带给开发者最多的是方便性,因为HTTP/1.1没有提供对已经发送到服务器端的请求的取消机制,而HTTP/2可以让客户端向已经被服务器端处理的请求,发送取消命令。

JShell

很多语言都为探索性开发提供了交互式环境。在某些情况下(特别是Clojure和其他Lisp方言),交互式环境占据了开发者的大部分编码时间,甚至是全部。其他语言,比如Scala或者JRuby也广泛使用REPL。

当然,此前Java曾经推出过Beanshell脚本语言,但是它没有实现完全标准化,而且近年来,该项目已经处于不活跃状态。在Java 8(以及jjs REPL)中引入的Nashorn Java实现打开了更广泛地考虑REPL并将交互式开发成为可能的大门。

一项努力将现代REPL引入Java 9的工作,以JEP 222作为开始,收录在OpenJDK的Kulla项目中。Kulla这个名字来自古巴比伦神话,是建造之神。该项目的主旨是提供最近距离的“完整Java”体验。该项目没有引入新的非Java语义,并禁用了Java语言中对交互式开发没有用处的语义(比如上层的访问控制修改或同步的语义)。

与所有REPL一样,JShell提供了命令行,而不是类似IDE的体验。语句和表达式能够在执行状态上下文中,被立即求值,而不是非得打包到类中。方法也是自由浮动的,而不必属于某个特定的类。相反,JShell使用代码片断“snippets”来提供上层执行环境。

与HTTP/2 API相似,JShell已经在独立的项目开发,以免在快速发展的时期影响主干构建的稳定性。JShell预计在2015年8月期间合并到主干。

现在,开发者可以参考AdoptOpenJDK说明指导,从头构建Kulla(源代码可以从Mercurial地址获得)。

对于一些上手实验,最简单的可能是使用一个独立的试验jar。这些jar包是社区专为不想从头构建的开发者构建好的。

这些试验jar包可以从AdoptOpenJDK CloudBees的CI构建实例中获得。

要使用它们,你需要安装Java 9 beta版(或者OpenJDK 9的构建版本)。然后下载jar文件,重命名为kulla.jar,然后在命令行输入如下:

$ java -jar kulla.jar | Welcome to JShell — Version 0.610 | Type /help for help ->

这是REPL的标准界面,和往常一样,命令是从单个字符开始并最终发出的。

JShell有一个相当完整(但仍在发展)的帮助语法,可以通过如下命令轻松获得:

-> /help Type a Java language expression, statement, or declaration. Or type one of the following commands: /l or /list [all] — list the source you have typed /seteditor <executable> — set the external editor command to use /e or /edit <name or id> — edit a source entry referenced by name or id /d or /drop <name or id> — delete a source entry referenced by name or id /s or /save [all|history] <file> — save the source you have typed /o or /open <file> — open a file as source input /v or /vars — list the declared variables and their values /m or /methods — list the declared methods and their signatures /c or /classes — list the declared classes /x or /exit — exit the REPL /r or /reset — reset everything in the REPL /f or /feedback <level> — feedback information: off, concise, normal, verbose, default, or ? /p or /prompt — toggle display of a prompt /cp or /classpath <path> — add a path to the classpath /h or /history — history of what you have typed /setstart <file> — read file and set as the new start-up definitions /savestart <file> — save the default start-up definitions to the file /? or /help — this help message /! — re-run last snippet /<n> — re-run n-th snippet /-<n> — re-run n-th previous snippet Supported shortcuts include: — show possible completions for the current text Shift- — for current method or constructor invocation, show a synopsis of the method/constructor

JShell支持TAB键自动补全, 因此我们可以很容易找到println()或者其他我们想使用的方法:

-> System.out.print print( printf( println(

传统的表达式求值也很容易,但是相比其他动态类型语言,Java的静态类型特征会更严格一点。JShell会自动创建临时变量来保存表达式的值,并确保它们保持在上下文域内供以后使用:

-> 3 * (4 + 5) | Expression value is: 27 | assigned to temporary variable $1 of type int -> System.out.println($1); 27

我们还可以使用/list命令,查看到目前为止输入的所有源代码:

-> /list 9 : 3 * (4 + 5) 10 : System.out.println($1);

使用/vars命令显示所有的变量(包括显式定义的和临时的),以及他们当前持有的值:

-> String s = “Dydh da” | Added variable s of type String with initial value “Dydh da” -> /vars | int $1 = 27 | String s = “Dydh da”

除了支持简单的代码行,REPL还允许非常简单地创建类和其它用户定义的类型。例如,可以用如下短短一行来创建类(请注意,开始和结束括号是必需的):

-> class Pet {} | Added class Pet -> class Cat extends Pet {} | Added class Cat

JShell代码非常简洁、自由浮动的性质意味着我们可以非常简单地使用REPL来演示Java语言的功能。例如,让我们来看看著名的类型问题,即Java数组的协变问题:

-> Pet[] pets = new Pet[1] | Added variable pets of type Pet[] with initial value [LPet;@2be94b0f -> Cat[] cats = new Cat[1] | Added variable cats of type Cat[] with initial value [LCat;@3ac42916 -> pets = cats | Variable pets has been assigned the value [LCat;@3ac42916 -> pets[0] = new Pet() | java.lang.ArrayStoreException thrown: REPL.$REPL13$Pet | at (#20:1)

这样的功能使JShell成为一种伟大的教学或研究工具,而且最接近Scala REPL的体验。使用/classpath切换,可以加载额外的jar包,从而可以在REPL直接使用互动式探索性API。

参与

主要的IDE已开始提供支持JDK 9早期版本的构建——包括Netbeans和Eclipse Mars。[urlhttps://www.jetbrains.com/idea/download/?spm=5176.blog26632.yqblogcon1.14.tXFWPP=””]IntelliJ 14.1[/url]据称支持JDK9,但目前还不清楚对新的模块化JDK扩展的支持力度。

到目前为止,这些IDE还不支持HTTP/2和JShell,因为这些功能还没有登陆OpenJDK的主干,但是开发者应该很期望它们能够早日出现在标准的JDK beta版本中,并且有IDE插件可以紧随其后。这些API仍在开发中,项目的领导者正在积极寻求最终用户的使用和参与。

The JDK 9 Outreach programme is also underway to encourage developers to test their code and applications on JDK 9 before it arrives. HTTP/2 & JShell aren’t the only new features being worked on – other new JDK 9 functionality under development as JEPs includes

JDK 9的宣传计划也正在鼓励开发者测试他们的代码并在JDK 9上运行应用程序。正在开发的新功能不止包括HTTP/2和JShell—— 其他作为JEP,JDK 9正在开发的新功能还包括:

102 Process API的更新(Process API Updates)165 编译器控制(Compiler Control)227 Unicode 7.0245 验证虚拟机代码行标记参数(Validate JVM Command-Line Flag Arguments)248: G1作为默认的垃圾回收器(Make G1 the Default Garbage Collector)TLS的一系列更新(TLS Updates) (JEP 219, 244, 249)

目前正在审议(以及考虑应该放在哪个Java版本)的所有JEP的完整列表可以在这里找到。

开发高效率 Git命令 Cherry-Pick 摘樱桃

在实际的项目开发中(使用Git版本控制),在所难免会遇到没有切换分支开发、需要在另一个分支修改bug然后合并到当前分支的情况。之前遇到这种第一反应就是将分支合并过去来解决问题。如果你那些提交当中也穿插了其他人的提交而且他们的提交不可以合并到另一个分支,那么使用分支的合并将明显变得困难。下面分享给大家一个非常好用Git的命令Cherry-Pick来处理这些情况,从而提高开发的效率。

git Cherry-Pick 命令可以选择某一个分支中的一个或几个commit(s)来进行操作。你可以理解merge的个性定制版本

多次使用时要按提交的顺序进行合并,不然会导致某些文件发生冲突。这也是 容易 踩的坑。

  1. 当你的需求还没有完成的时候,其他人应该切换到另一分支开发的时候,你可以先在当前分支继续开发完,然后再选择Cherry-Pick命令合并过去就可以了。
  2. 当你需要将某个人的commits合并到另一开分时候,可以选择Cherry-Pick命令。(在实际的项目开发中,在所难免有人会提交错分支)
  3. 当你切换到某条分支修改Bug后,需要将修改提交合并另一分支,可以选择Cherry-Pick命令。

Linux Kernel 3.18 LTS 终止支持 请升至 4.9 或 4.4 分支

在发布最后一个维护版本更新之后,Linux 稳定版内核维护者 Greg Kroah-Hartman 宣布 Linux Kernel 3.18 分支走到了生命的尽头。而 3.18 LTS 原计划于今年 1 月终止支持。

Linux Kernel 3.18.48 LTS 是该分支的最后版本,根据短日志显示该版本共计调整了 50 个文件,插入 159 处删除 351 处。升级网络堆栈的同时改善了 Bluetooth, Bridge, IPv4, IPv6, CAIF 和 Netfilter,并升级了 USB, SCSI, ATA, media, GPU, ATM, HID, MTD, SPI 和网络(有线和无线)驱动。新发布的 3.18.48 还修正了 3.18.47 和 3.18.27 中的一个 bug。

LTS 版通常会提供大约两年的支持时间,3.18 是在 2014 年 12 月发布的。如果你当前还在使用该内核分支,那么现在你应该升级至更新的 LTS 版本,例如 Linux Kernel 4.9 或者 4.4,这两个版本要比 3.18 更加的安全和强悍。不过 Linux Kernel 3.18 主要被 Google 和其他供应商应用于一些 Android 设备、部分 Chromebook 上,Kroah-Hartman 建议用户拒绝购买仍然使用 3.18 LTS 的供应商的设备。如果无法升级内核开发者也提供了一些建议。

“如果你在使用 Linux Kernel 3.18 中有困难,那么我可以给你提供一些帮助。首先,你需要和硬件供应商反馈,要求尽快升级否则不再购买他们的产品。如果供应商还是不升级,请致信我们让我们出面和厂商进行沟通,出现这个问题的肯定不止你一个人。”

来源:http://www.oschina.net/news/81799/linux-kernel-3-18-48-released

Eloquent ORM Laravel 5.3 创建 配置与使用

1、简介

Laravel 自带的 Eloquent ORM 提供了一个美观、简单的与数据库打交道的 ActiveRecord 实现,每张数据表都对应一个与该表进行交互的“模型”,模型允许你在表中进行数据查询,以及插入、更新、删除等操作。

在开始之前,确保在config/database.php文件中配置好了数据库连接。更多关于数据库配置的信息,请查看文档。

2、定义模型

作为开始,让我们创建一个 Eloquent 模型,模型通常位于app目录下,你也可以将其放在其他可以被composer.json文件自动加载的地方。所有Eloquent模型都继承自 Illuminate\Database\Eloquent\Model类。

创建模型实例最简单的办法就是使用 Artisan 命令make:model

php artisan make:model User

如果你想要在生成模型时生成数据库迁移,可以使用--migration-m选项:

php artisan make:model User --migration
php artisan make:model User -m

Eloquent 模型约定

现在,让我们来看一个 Flight 模型类例子,我们将用该类获取和存取数据表flights中的信息:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    //
}

表名

注意我们并没有告诉 Eloquent 我们的Flight模型使用哪张表。默认规则是模型类名的复数作为与其对应的表名,除非在模型类中明确指定了其它名称。所以,在本例中,Eloquent 认为Flight模型存储记录在flights表中。你也可以在模型中定义table属性来指定自定义的表名:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 关联到模型的数据表
     *
     * @var string
     */
    protected $table = 'my_flights';
}

主键

Eloquent 默认每张表的主键名为id,你可以在模型类中定义一个$primaryKey属性来覆盖该约定。

此外,Eloquent默认主键字段是自增的整型数据,这意味着主键将会被自动转化为int类型,如果你想要使用非自增或非数字类型主键,必须在对应模型中设置$incrementing属性为false

时间戳

默认情况下,Eloquent 期望created_atupdated_at已经存在于数据表中,如果你不想要这些 Laravel 自动管理的列,在模型类中设置$timestamps属性为false

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 表明模型是否应该被打上时间戳
     *
     * @var bool
     */
    public $timestamps = false;
}

如果你需要自定义时间戳格式,设置模型中的$dateFormat属性。该属性决定日期被如何存储到数据库中,以及模型被序列化为数组或 JSON 时日期的格式:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 模型日期列的存储格式
     *
     * @var string
     */
    protected $dateFormat = 'U';
}

数据库连接
 
默认情况下,所有的 Eloquent 模型使用应用配置中的默认数据库连接,如果你想要为模型指定不同的连接,可以通过$connection 属性来设置:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * The connection name for the model.
     *
     * @var string
     */
    protected $connection = 'connection-name';
}

3、获取模型

创建完模型及其关联的数据表后,就要准备从数据库中获取数据。将Eloquent模型看作功能强大的查询构建器,你可以使用它来流畅的查询与其关联的数据表。例如:

<?php

use App\Flight;

$flights = App\Flight::all();

foreach ($flights as $flight) {
    echo $flight->name;
}

添加额外约束

Eloquent 的all方法返回模型表的所有结果,由于每一个Eloquent模型都是一个查询构建器,你还可以添加约束条件到查询,然后使用get方法获取对应结果:

$flights = App\Flight::where('active', 1)
               ->orderBy('name', 'desc')
               ->take(10)
               ->get();

注意:由于 Eloquent 模型本质上就是查询构建器,你可以在Eloquent查询中使用查询构建器的所有方法。

集合

对 Eloquent 中获取多个结果的方法(比如allget)而言,其返回值是Illuminate\Database\Eloquent\Collection的一个实例,Collection类提供了多个有用的函数来处理Eloquent结果集:

$flights = $flights->reject(function ($flight) {
    return $flight->cancelled;
});

当然,你也可以像数组一样循环遍历该集合:

foreach ($flights as $flight) {
    echo $flight->name;
}

组块结果集

如果你需要处理成千上万个 Eloquent 结果,可以使用chunk命令。chunk方法会获取一个“组块”的 Eloquent 模型,并将其填充到给定闭包进行处理。使用chunk方法能够在处理大量数据集合时有效减少内存消耗:

Flight::chunk(200, function ($flights) {
    foreach ($flights as $flight) {
        //
    }
});

传递给该方法的第一个参数是你想要获取的“组块”数目,闭包作为第二个参数被调用用于处理每个从数据库获取的区块数据。

使用游标

cursor
方法允许你使用游标迭代处理数据库记录,一次只执行单个查询,在处理大批量数据时,cursor方法可大幅减少内存消耗:

foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
    //
}

4、获取单个模型/聚合

当然,除了从给定表中获取所有记录之外,还可以使用findfirst获取单个记录。这些方法返回单个模型实例而不是返回模型集合:

// 通过主键获取模型...
$flight = App\Flight::find(1);
// 获取匹配查询条件的第一个模型...
$flight = App\Flight::where('active', 1)->first();

还可以通过传递主键数组来调用find方法,这将会返回匹配记录集合:

$flights = App\Flight::find([1, 2, 3]);

Not Found 异常

有时候你可能想要在模型找不到的时候抛出异常,这在路由或控制器中非常有用,findOrFailfirstOrFail方法会获取查询到的第一个结果。然而,如果没有任何查询结果,Illuminate\Database\Eloquent\ModelNotFoundException异常将会被抛出:

$model = App\Flight::findOrFail(1);
$model = App\Flight::where('legs', '>', 100)->firstOrFail();

如果异常没有被捕获,那么HTTP 404 响应将会被发送给用户,所以在使用这些方法的时候没有必要对返回404响应编写明确的检查:

Route::get('/api/flights/{id}', function ($id) {
    return App\Flight::findOrFail($id);
});

获取聚合

当然,你还可以使用查询构建器聚合方法,例如countsummax,以及其它查询构建器提供的聚合方法。这些方法返回计算后的结果而不是整个模型实例:

$count = App\Flight::where('active', 1)->count();
$max = App\Flight::where('active', 1)->max('price');

5、插入/更新模型

插入

想要在数据库中插入新的记录,只需创建一个新的模型实例,设置模型的属性,然后调用save方法:

<?php

namespace App\Http\Controllers;

use App\Flight;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class FlightController extends Controller{
    /**
     * 创建一个新的航班实例
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate the request...

        $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();
    }
}

在这个例子中,我们只是简单分配HTTP请求中的name参数值给App\Flight模型实例的那么属性,当我们调用save方法时,一条记录将会被插入数据库。created_atupdated_at时间戳在save方法被调用时会自动被设置,所以没必要手动设置它们。

更新

save方法还可以用于更新数据库中已存在的模型。要更新一个模型,应该先获取它,设置你想要更新的属性,然后调用save方法。同样,updated_at时间戳会被自动更新,所以没必要手动设置其值:

$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();

更新操作还可以同时修改给定查询提供的多个模型实例,在本例中,所有有效且destination=San Diego的航班都被标记为延迟:

App\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]);

update方法要求以数组形式传递键值对参数,代表着数据表中应该被更新的列。

注:通过Eloquent进行批量更新时,savedupdated模型事件将不会在更新模型时触发。这是因为在进行批量更新时并没有从数据库获取模型。

批量赋值

还可以使用create方法保存一个新的模型。该方法返回被插入的模型实例。但是,在此之前,你需要指定模型的fillableguarded属性,因为所有Eloquent模型都通过批量赋值(Mass Assignment)进行保护。

当用户通过 HTTP 请求传递一个不被期望的参数值时就会出现安全隐患,然后该参数以不被期望的方式修改数据库中的列值。例如,恶意用户通过 HTTP 请求发送一个is_admin参数,然后该参数映射到模型的create方法,从而允许用户将自己变成管理员。

所以,你应该在模型中定义哪些属性是可以进行赋值的,使用模型上的$fillable属性即可实现。例如,我们设置Flight模型上的name属性可以被赋值:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 可以被批量赋值的属性.
     *
     * @var array
     */
    protected $fillable = ['name'];
}

设置完可以被赋值的属性之后,我们就可以使用create方法在数据库中插入一条新的记录。create方法返回保存后的模型实例:

$flight = App\Flight::create(['name' => 'Flight 10']);

黑名单属性

$fillable就像是可以被赋值属性的“白名单”,还可以选择使用$guarded$guarded属性包含你不想被赋值的属性数组。所以不被包含在其中的属性都是可以被赋值的,因此,$guarded功能就像“黑名单”。当然,这两个属性你只能同时使用其中一个——而不能一起使用,因为它们是互斥的:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model{
    /**
     * 不能被批量赋值的属性
     *
     * @var array
     */
    protected $guarded = ['price'];
}

如果你想要让所有属性都是可批量赋值的,可以将$guarded属性设置为空数组:

/**
 * The attributes that aren't mass assignable.
 *
 * @var array
 */
protected $guarded = [];

其它创建方法

还有其它两种可以用来创建模型的方法:firstOrCreatefirstOrNewfirstOrCreate方法先尝试通过给定列/值对在数据库中查找记录,如果没有找到的话则通过给定属性创建一个新的记录。

firstOrNew方法和firstOrCreate方法一样先尝试在数据库中查找匹配的记录,如果没有找到,则返回一个的模型实例。注意通过firstOrNew方法返回的模型实例并没有持久化到数据库中,你还需要调用save方法手动持久化:

// 通过属性获取航班, 如果不存在则创建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// 通过属性获取航班, 如果不存在初始化一个新的实例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);

6、删除模型

要删除一个模型,调用模型实例上的delete方法:

$flight = App\Flight::find(1);
$flight->delete();

通过主键删除模型

在上面的例子中,我们在调用delete方法之前从数据库中获取该模型,然而,如果你知道模型的主键的话,可以调用destroy方法直接删除而不需要获取它:

App\Flight::destroy(1);
App\Flight::destroy([1, 2, 3]);
App\Flight::destroy(1, 2, 3);

通过查询删除模型

当然,你还可以通过查询删除多个模型,在本例中,我们删除所有被标记为无效的航班:

$deletedRows = App\Flight::where('active', 0)->delete();

注:通过Eloquent进行批量删除时,deletingdeleted模型事件在删除模型时不会被触发,这是因为在进行模型删除时不会获取模型。

软删除

除了从数据库删除记录外,Eloquent还可以对模型进行“软删除”。当模型被软删除后,它们并没有真的从数据库删除,而是在模型上设置一个deleted_at属性并插入数据库,如果模型有一个非空deleted_at值,那么该模型已经被软删除了。要启用模型的软删除功能,可以使用模型上的Illuminate\Database\Eloquent\SoftDeletestrait并添加deleted_at列到$dates属性:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model{
    use SoftDeletes;

    /**
     * 应该被调整为日期的属性
     *
     * @var array
     */
    protected $dates = ['deleted_at'];
}

当然,应该添加deleted_at列到数据表。Laravel Schema构建器包含一个帮助函数来创建该列:

Schema::table('flights', function ($table) {
    $table->softDeletes();
});

现在,当调用模型的delete方法时,deleted_at列将被设置为当前日期和时间,并且,当查询一个使用软删除的模型时,被软删除的模型将会自动从查询结果中排除。

判断给定模型实例是否被软删除,可以使用trashed方法:

if ($flight->trashed()) {
    //
}

查询被软删除的模型

包含软删除模型

正如上面提到的,软删除模型将会自动从查询结果中排除,但是,如果你想要软删除模型出现在查询结果中,可以使用withTrashed方法:

$flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();

withTrashed方法也可以用于关联查询中:

$flight->history()->withTrashed()->get();

只获取软删除模型

onlyTrashed方法之获取软删除模型:

$flights = App\Flight::onlyTrashed()
                ->where('airline_id', 1)
                ->get();

恢复软删除模型

有时候你希望恢复一个被软删除的模型,可以使用restore方法:

$flight->restore();

你还可以在查询中使用restore方法来快速恢复多个模型:

App\Flight::withTrashed()
        ->where('airline_id', 1)
        ->restore();

withTrashed方法一样,restore方法也可以用于关联查询:

$flight->history()->restore();

永久删除模型

有时候你真的需要从数据库中删除一个模型,可以使用forceDelete方法:

// 强制删除单个模型实例...
$flight->forceDelete();
// 强制删除所有关联模型...
$flight->history()->forceDelete();

7、查询作用域

全局作用域

全局作用域允许我们为给定模型的所有查询添加条件约束。Laravel 自带的软删除功能就使用了全局作用域来从数据库中拉出所有没有被删除的模型。编写自定义的全局作用域可以提供一种方便的、简单的方式来确保给定模型的每个查询都有特定的条件约束。

编写全局作用域

自定义全局作用域很简单,首先定义一个实现 Illuminate\Database\Eloquent\Scope 接口的类,该接口要求你实现一个方法:apply。需要的话可以在 apply 方法中添加 where 条件到查询:

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class AgeScope implements Scope{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        return $builder->where('age', '>', 200);
    }
}

注:Laravel应用默认并没有为作用域预定义文件夹,所以你可以按照自己的喜好在app目录下创建Scopes目录。

应用全局作用域

要将全局作用域分配给模型,需要重写给定模型的 boot 方法并使用 addGlobalScope 方法:

<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new AgeScope);
    }
}

添加作用域后,如果使用 User::all() 查询则会生成如下SQL语句:

select * from `users` where `age` > 200

匿名的全局作用域

Eloquent还允许我们使用闭包定义全局作用域,这在实现简单作用域的时候特别有用,这样的话,我们就没必要定义一个单独的类了:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class User extends Model{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('age', function(Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

我们还可以通过以下方式移除全局作用:

User::withoutGlobalScope('age')->get();

移除全局作用域

如果想要在给定查询中移除指定全局作用域,可以使用 withoutGlobalScope

User::withoutGlobalScope(AgeScope::class)->get();

如果你想要移除某几个或全部全局作用域,可以使用 withoutGlobalScopes 方法:

User::withoutGlobalScopes()->get();
User::withoutGlobalScopes([FirstScope::class, SecondScope::class])->get();

本地作用域

本地作用域允许我们定义通用的约束集合以便在应用中复用。例如,你可能经常需要获取最受欢迎的用户,要定义这样的一个作用域,只需简单在对应Eloquent模型方法前加上一个scope前缀。

作用域总是返回查询构建器实例:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 只包含活跃用户的查询作用域
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * 只包含激活用户的查询作用域
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

使用本地作用域

作用域被定义好了之后,就可以在查询模型的时候调用作用域方法,但调用时不需要加上scope前缀,你甚至可以在同时调用多个作用域,例如:

$users = App\User::popular()->active()->orderBy('created_at')->get();

动态作用域

有时候你可能想要定义一个可以接收参数的作用域,你只需要将额外的参数添加到你的作用域即可。作用域参数应该被定义在$query参数之后:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 只包含给用类型用户的查询作用域
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }
}

现在,你可以在调用作用域时传递参数了:

$users = App\User::ofType('admin')->get();

8、事件

Eloquent模型可以触发事件,允许你在模型生命周期中的多个时间点调用如下这些方法:creatingcreatedupdatingupdatedsavingsaved,deletingdeletedrestoringrestored。事件允许你在一个指定模型类每次保存或更新的时候执行代码。

基本使用

一个新模型被首次保存的时候,creatingcreated事件会被触发。如果一个模型已经在数据库中存在并调用save方法,updating/updated事件会被触发,无论是创建还是更新,saving/saved事件都会被调用。

举个例子,我们在服务提供者中定义一个Eloquent事件监听器,在事件监听器中,我们会调用给定模型的isValid方法,如果模型无效会返回false。如果从Eloquent事件监听器中返回false则取消save/update操作:

<?php

namespace App\Providers;

use App\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider{
    /**
     * 启动所有应用服务
     *
     * @return void
     */
    public function boot()
    {
        User::creating(function ($user) {
            return $user->isValid();
        });
    }

    /**
     * 注册服务提供者.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

观察者

如果你在给定模型中监听多个事件,可以使用观察者来对所有监听器进行分组,观察者类拥有反射你想要监听的Eloquent事件对应的方法名,每个方法接收模型作为唯一参数。Laravel并没有为监听器提供默认目录,所以你可以创建任意目录来存放观察者类:

<?php

namespace App\Observers;

use App\User;

class UserObserver
{
    /**
     * Listen to the User created event.
     *
     * @param  User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Listen to the User deleting event.
     *
     * @param  User  $user
     * @return void
     */
    public function deleting(User $user)
    {
        //
    }
}

要监听观察者,使用你想要观察模型的observe方法,你可以在某个服务提供者的boot方法中注册观察者,在本例中,我们在AppServiceProvider中注册观察者:

<?php

namespace App\Providers;

use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Firebug 宣布不再维护,讲不出再见!

Firebug 在其官方网站上宣布 —— “Firebug 扩展不再进行开发或维护,我们邀请您使用 Firefox 的内置开发工具以代替”。

Firebug 是 Firefox 下的一款开发类插件,现属于 Firefox 的五星级强力推荐插件之一。它集 HTML 查看和编辑、Javascript 控制台、网络状况监视器于一体,是开发 JavaScript、CSS、HTML 和 Ajax 的得力助手。Firebug 如同一把精巧的瑞士军刀,从各个不同的角度剖析 Web 页面内部的细节层面,给 Web 开发者带来很大的便利。

来自:http://getfirebug.com/

Adding SQLCipher to Xcode Projects IOS MAC

Adding SQLCipher to Xcode Projects

SQLite is already a popular API for persistent data storage in iOS apps so the upside for development is obvious. As a programmer you work with a stable, well-documented API that happens to have many good wrappers available in Objective-C, such as FMDB and Encrypted Core Data. All security concerns are cleanly decoupled from application code and managed by the underlying framework.

The framework code of the SQLCipher project is open source, so users can be confident that an application isn’t using insecure or proprietary security code. In addition, SQLCipher can also be compiled on Android, Linux, OS X and Windows for those developing cross-platform applications.

Using SQLCipher in an iOS app is fairly straightforward. This document describes integrating SQLCipher into an existing iOS project using the Community Edition source code build process. This tutorial assumes some familiarity with basic iOS app development and a working install of Xcode (6.1.1). The same basic steps can be applied to OS X projects as well.

? Hot Tip: Commercial Edition static libraries are available for you to drop right into your project if you’d like to skip all this and receive personalized support from our crack development team! Binaries and helpful projects integrations are available for all supported platforms. Learn more »

Prerequisites

Xcode with an iOS or OS X SDK installed. Visit the Apple Developer site for more information on downloading the latest Xcode and iOS and OS X SDKs.

OpenSSL

OpenSSL is no longer required for building SQLCipher on iOS and OS X, as the project by default uses Apple’s CommonCrypto framework for hardware-accelerated encryption. You can still build SQLCipher with other crypto providers like OpenSSL if you’d prefer, or you can write your own.

SQLCipher

Fire up the Terminal app, switch into your project’s root directory and checkout the SQLCipher project code using Git:

$ cd ~/Documents/code/SQLCipherApp
$ git clone https://github.com/sqlcipher/sqlcipher.git

Xcode Project Configuration

The SQLCipher source provides a sqlcipher.xcodeproj project file that we’ll add to your project to build a static library that you’ll link from your main application target.

Add Project Reference

Open your iOS app’s project or workspace in Xcode, open the Project Navigator (command+1), and click on the top-level Project icon for your iOS app. Right click on the project and choose “Add Files to “My App”” (the label will vary depending on your app’s name). Since we cloned SQLCipher directly into the same folder as your iOS app you should see a sqlcipher folder in your root project folder. Open this folder and select sqlcipher.xcodeproj:

Add Files to 'My App'

Project References

Project Settings

Navigate to your Project settings (make sure you don’t select the application target level). Select the Build Settings pane. In the search field, type in “Header Search Paths”. Double-click on the field under the target column and add the following path: $(PROJECT_DIR)/sqlcipher/src:

Next, add a setting to ensure that SQLCipher is the first library linked with your application in the “Other Linker Flags” setting. Start typing “Other Linker Flags” into the search field until the setting appears, double click to edit it, and add the following value: $(BUILT_PRODUCTS_DIR)/libsqlcipher.a

You will next edit one other setting on your Project to ensure the SQLCipher builds correctly—”Other C Flags.” Start typing “Other C Flags” into the search field until the setting appears, double click to edit it, and in the pop-up add the following value: -DSQLITE_HAS_CODEC

Target Settings

Next, navigate to the Target Level settings. Add a Target dependency to each of your application targets to ensure that SQLCipher is compiled before the application code. In Xcode’s Project Navigator (command+1), select your app’s Project file and in the Editor pane select Build Phases and your app’s main target (not the project file).

Expand Target Dependencies and click on the + button at the end of the list. In the browser that opens, select the sqlcipher static library target:

Add Target Dependency

Expand Link Binary With Libraries, click on the +button at the end of the list, and select the libsqlcipher.a library.

Link Binary With Libraries

Finally, also under Link With Libraries, add Security.framework.

? Hot Tip: If libsqlite3.dylib or another SQLite framework is listed in your Link Binary With Libraries list be sure to remove it!

Repeat these steps for any other targets in your project that will depend on SQLCipher, i.e. unit tests.

Integration Code

Now that the SQLCipher library is incorporated into the project you can start using the library immediately. Telling SQLCipher to encrypt a database is easy:

  • Open the database
  • Use the sqlite3_key function to provide key material. In most cases this should occur as the first operation after opening the database.
  • Run a query to verify the database can be opened (i.e. by querying the schema)
  • As a precautionary measure, run a query to ensure that the application is using SQLCipher on the active connection
#import <sqlite3.h>

...
NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
                          stringByAppendingPathComponent: @"sqlcipher.db"];
sqlite3 *db;
bool sqlcipher_valid = NO;

if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) {
    const char* key = [@"BIGSecret" UTF8String];
    sqlite3_key(db, key, strlen(key));
    if (sqlite3_exec(db, (const char*) "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
      if(sqlite3_prepare_v2(database, "PRAGMA cipher_version;", -1, &stmt, NULL) == SQLITE_OK) {
        if(sqlite3_step(stmt)== SQLITE_ROW) {
          const unsigned char *ver = sqlite3_column_text(stmt, 0);
          if(ver != NULL) {
            sqlcipher_valid = YES;

            // password is correct (or database initialize), and verified to be using sqlcipher

          }
        }
        sqlite3_finalize(stmt);
      }
    }
    sqlite3_close(db);
}

In most cases SQLCipher uses PBKDF2, a salted and iterated key derivation function, to obtain the encryption key. Alternately, an application can tell SQLCipher to use a specific binary key in blob notation (note that SQLCipher requires exactly 256 bits of key material), i.e.

PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";

Once the key is set SQLCipher will automatically encrypt all data in the database! Note that if you don’t set a key then SQLCipher will operate identically to a standard SQLite database.

Testing and Verification

There are a number of ways that you can verify SQLCipher is working as expected in your applications before its release to users.

After the application is wired up to use SQLCipher, take a peek at the resulting data files to make sure everything is in order. An ordinary SQLite database will look something like the following under hexdump. Note that the file type, schema, and data are clearly readable.

% hexdump -C plaintext.db
00000000  53 51 4c 69 74 65 20 66  6f 72 6d 61 74 20 33 00  |SQLite format 3.|
00000010  04 00 01 01 00 40 20 20  00 00 00 04 00 00 00 00  |.....@  ........|
...
000003b0  00 00 00 00 24 02 06 17  11 11 01 35 74 61 62 6c  |....$......5tabl|
000003c0  65 74 32 74 32 03 43 52  45 41 54 45 20 54 41 42  |et2t2.CREATE TAB|
000003d0  4c 45 20 74 32 28 61 2c  62 29 24 01 06 17 11 11  |LE t2(a,b)$.....|
000003e0  01 35 74 61 62 6c 65 74  31 74 31 02 43 52 45 41  |.5tablet1t1.CREA|
000003f0  54 45 20 54 41 42 4c 45  20 74 31 28 61 2c 62 29  |TE TABLE t1(a,b)|
...
000007d0  00 00 00 14 02 03 01 2d  02 74 77 6f 20 66 6f 72  |.......-.two for|
000007e0  20 74 68 65 20 73 68 6f  77 15 01 03 01 2f 01 6f  | the show..../.o|
000007f0  6e 65 20 66 6f 72 20 74  68 65 20 6d 6f 6e 65 79  |ne for the money|

Fire up the SQLCipher application in simulator and look for the application database files under /Users/sjlombardo/Library/Application Support/iPhone Simulator/5.0/Applications/<Instance ID>/Documents. Try running hexdump on the application database. With SQLCipher the output should looks completely random, with no discerning characteristics at all.

% hexdump -C sqlcipher.db
00000000  1b 31 3c e3 aa 71 ae 39  6d 06 f6 21 63 85 a6 ae  |.1<..q.9m..!c...|
00000010  ca 70 91 3e f5 a5 03 e5  b3 32 67 2e 82 18 97 5a  |.p.>.....2g....Z|
00000020  34 d8 65 95 eb 17 10 47  a7 5e 23 20 21 21 d4 d1  |4.e....G.^# !!..|
...
000007d0  af e8 21 ea 0d 4f 44 fe  15 b7 c2 94 7b ee ca 0b  |..!..OD.....{...|
000007e0  29 8b 72 93 1d 21 e9 91  d4 3c 99 fc aa 64 d2 55  |).r..!...<...d.U|
000007f0  d5 e9 3f 91 18 a9 c5 4b  25 cb 84 86 82 0a 08 7f  |..?....K%.......|
00000800

Other sensible testing steps include:

  • Attempt to open a database with a correct key and verify that the operation succeeds
  • Attempt to open a database with an incorrect key and verify that the operation fails
  • Attempt to open a database without any key, and verify the operation fails
  • Programtically inspect the first 16 bytes of the database file and ensure that it contains random data (i.e. not the string SQLite Format 3\0)

来源:https://www.zetetic.net/sqlcipher/ios-tutorial/