About neohope

一直在努力,还没想过要放弃...

Jetty源码分析01

一、Jetty的ScopedHandler的doStart方法,最后一步是将线程私有变量__outerScope设置成null,为什么需要这样做呢?

protected void doStart() throws Exception
{
    try{
        _outerScope=__outerScope.get();
        if (_outerScope==null){
           //本次处理的第一个scope handler
           //告知后续scope handler,_outerScope选我
            __outerScope.set(this);
        }
        super.doStart();
        _nextScope= getChildHandlerByClass(ScopedHandler.class);
    }
    finally
    {
        if (_outerScope==null){
           //本次处理结束
           //为了下次同一个线程处理是,
           //还能正常的设置第一个scope handler
           //必须把threadlocal变量设为null
            __outerScope.set(null);
        }
    }
}

二、Jetty中,ScopedHandler中nextHandle调用顺序是如何的?

//此外,这一节里有一个non scoped handler X,一开始没太看懂调阅顺序。
//后来发现是这样的:
public final void nextHandle(String target...)...
{
    if (_nextScope!=null && _nextScope==_handler){
        //上面条件可以保证下一个handler是scope handler
        _nextScope.doHandle(target,baseRequest,request, response);
    }
    else if (_handler!=null){
        //non scpoe handler调用下一个handler的
        super.handle(target,baseRequest,request,response);
    }
}

感觉类成员的命名不太合适,
比如__outerScope和_outerScope
比如_handler其实一直指向的是下一个handler,是不是该为_nextHandler更好一些?

通过ADB删除小米电视安装应用

小米电视越来越慢,就想多删除一些应用:
注意:预装应用删除后,除了升级系统,并没有好的恢复方法,使用命令需谨慎

#首先在小米电视上打开远程调试,让ADB可以远程连接
开启开发者模式:设置-》关于-》产品型号-》遥控连续按5下OK键
设备安全设置:设置-》账号与安全-》允许安装未知来源的应用-》允许ADB调试
查看网络IP:设置-》网络-》找到电视使用的局域网IP

#远程连接小米电视
adb connect IP

#显示已连接设备
adb devices

#安装APK包
adb install -r PATH_TO_APK/MyAPK.apk

#列出已安装的包
adb shell pm list packages

#删除具体应用(不同版本包名有差异)
应用商店
adb shell pm uninstall com.xiaomi.mitv.appstore
小米商城
adb shell pm uninstall com.xiaomi.mitv.shop
小米支付
adb shell pm uninstall com.xiaomi.mitv.payment
小米钱包
adb shell pm uninstall com.mipay.wallet.tv
天气
adb shell pm uninstall com.xiaomi.tweather
时尚画报
adb shell pm uninstall com.xiaomi.tv.gallery
相册
adb shell pm uninstall  com.mitv.gallery
照片屏幕保护程序
adb shell pm uninstall  com.android.dreams.phototable
游戏中心
adb shell pm uninstall com.xiaomi.mibox.gamecenter
日历
adb shell pm uninstall com.xiaomi.mitv.calendar
提醒
adb shell pm uninstall com.mitv.alarmcenter
用户手册
adb shell pm uninstall com.xiaomi.mitv.handbook
热点新闻
adb shell pm uninstall com.duokan.videodaily
新闻
adb shell pm uninstall  com.xiaomi.mitvnews
米家
adb shell pm uninstall com.xiaomi.smarthome.tv
小米盒子设置
adb shell pm uninstall com.xiaomi.mitv.settings

#重启设备
adb shell reboot
adb shell reboot -p

Java的各种容器

对比一下,Servlet容器、Spring容器和SpringMVC容器。

Servlet容器,是用于管理Servlet生命周期的。
Spring容器,是用于管理Spring Bean生命周期的。
SpringMVC容器,适用于管理SpringMVC Bean生命周期的。

Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:
1、对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext
2、ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置

3、如果Listener中配有spring的ContextLoaderListener
3.1、ContextLoaderListener就会收到webapp的各种状态信息。
3.3、在ServletContext初始化时,ContextLoaderListener也就会将Spring IOC容器进行初始化,管理Spring相关的Bean。
3.4、ContextLoaderListener会将Spring IOC容器存放到ServletContext中

4、如果Servlet中配有SpringMVC的DispatcherServlet
4.1、DispatcherServlet初始化时(其一次请求到达)。
4.2、其中,DispatcherServlet会初始化自己的SpringMVC容器,用来管理Spring MVC相关的Bean。
4.3、SpringMVC容器可以通过ServletContext获取Spring容器,并将Spring容器设置为自己的根容器。而子容器可以访问父容器,从而在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。
4.2、初始化完毕后,DispatcherServlet开始处理MVC中的请求映射关系。

我面试的时候,有段时间经常会问一个很坑问题,Servlet默认是单例模式的,Spring的Bean默认是单例模式的,那Spring MVC是如何处理并发请求的呢?

Servlet容器、Spring容器、SpringMVC容器之间的关系

之前在极客时间上回答老师的问题:

Servlet容器,是用于管理Servlet生命周期的。
Spring容器,是用于管理Spring Bean生命周期的。
SpringMVC容器,适用于管理SpringMVC Bean生命周期的。

Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:
1、对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext
2、ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置

3、如果Listener中配有Spring的ContextLoaderListener
3.1、ContextLoaderListener就会收到webapp的各种状态信息。
3.3、在ServletContext初始化时,ContextLoaderListener也就会将Spring IOC容器进行初始化,管理Spring相关的Bean。
3.4、ContextLoaderListener会将Spring IOC容器存放到ServletContext中

4、如果Servlet中配有SpringMVC的DispatcherServlet
4.1、DispatcherServlet初始化时(其一次请求到达)。
4.2、其中,DispatcherServlet会初始化自己的SpringMVC容器,用来管理Spring MVC相关的Bean。
4.3、SpringMVC容器可以通过ServletContext获取Spring容器,并将Spring容器设置为自己的根容器。而子容器可以访问父容器,从而在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。
4.2、初始化完毕后,DispatcherServlet开始处理MVC中的请求映射关系。

区块链应用场景

一、区块链应用场景
大家都很清楚,区块链的一个重要应用就是代币发性。如比特币,可以用于转账支付,网络交易、股票交易、跨境结算等。但除此之外,区块链也有不少可以落地的场景,咱们一起看一下。

1、资产交易记录
大宗商品交易、房地产交易记录、能源交易、碳交易、虚拟资产交易等

2、数据资产保护及验证
专利保护、著作权保护、商标保护、学术论文、数字资产保护
数字资产认证:文字、图片、音乐、视频所属权
数字资产使用记录:张三去看医生,医生需要调阅其他医院的就诊记录
数字资产保护:张三的商品浏览信息被用来做机器学习优化了算法,张三应该收到一笔数据使用费
数据防篡改:待交易数据内容摘要放到链上,数据资产交易后,可以通过摘要验证数据是否是交易的那笔数据

3、信息溯源
商品溯源与防伪:商品产地、物流等信息
众筹管理:众筹合约、众筹资金使用情况
公益管理:献血后血液去向、捐款去向
失信记录管理、公开投票记录

4、政务管理
政务审批
招投标管理
税务管理:发票管理
居民权益发放:扶贫

5、信息公正
证照管理:毕业证书、专业认证
公证管理: 司法鉴证、身份证明、财产证明

6、电子合同管理
保险理赔、商业合同、遗嘱等

二、对区块链未来的展望:
1、区块链会在不少场景下逐步落地,但其无法篡改性,恐怕也是其难以落地的愿意之一;

2、各国ZF以及大企业,在自己的管理范围内,会推行容易管控的联盟链,而不是公链;通过区块链发币,多国ZF也会长期打压;

3、当前公链的共识方式,消耗了过多的资源,而且交易吞吐量受限,难以满足日益增长的交易需求;这部分需要一次技术突破,才能支持后续发展;

4、如何保证数据隐私的情况下,还能用好数据,发挥好区块链的作用,会是一个很有趣的话题;

5、区块链并没有完全去中心化,中心依然存在,更像是分布式。以Pow为例,各大矿主的话语权比某个人的计算机高的多,这些矿场就是中心。而到了权益证明、带委托的权益证明,还是权益高的人就是中心;

6、有人说区块链是元宇宙基础设施,有一定道理;但现在的元宇宙还处于上古时期,到元宇宙蓬勃发展时,区块链的形式也会发生很大的变化;

7、量子技术的发展,会对区块链的不可修改性提出很大的挑战,当然这个还处于刚开天辟地的阶段,需要更久的发展;

Ubuntu18.0.4LTS蓝牙鼠标无法重连

Ubuntu18.0.4LTS安装后,蓝牙鼠标经常无法重连,休眠、重启后,都需要重新配对连接。现在咱们来解决这个问题。

1、首先删掉配对的鼠标

2、打开Terminal

bluetoothctl

# 查看蓝牙控制器,一般只有一个
>>> list

# 选择蓝牙控制器
>>> select 01:23:45:67:89:AB

# 查看控制器情况
>>> show

# 启动
>>> power on

# 扫描,记录蓝牙鼠标地址
>>> scan on

# 关闭扫描
>>> scan off

# 开启agent
>>> agent on

# 配对
>>> pair 34:88:5D:87:C0:A6

# 连接
>>> connect 34:88:5D:87:C0:A6

# 信任设备
>>> trust 34:88:5D:87:C0:A6

# 退出

3、 再试一下,是不是好了

windows下无法启动pip

尤其是在有多版本Python共存的情况下,修改windows修改环境变量后,经常会导致pip无法启动的情况。
此时,不仅是pip,Python/Scripts目录下的所有脚本都无法启动,并会有如下错误:

Fatal error in launcher: Unable to create process using '"'

其根本原因,其实十分简单,pip无法找到python.exe可执行程序,你可以看pip的源码来确认这一点。
有几种方法可以解决这个问题:

1、环境变量法,更适合单Ptyhon环境
将python.exe路径,增加到PATH环境变量中即可解决问题

2、脚本启动法,适合多个Ptyhon环境

set PATH=PATH_TO_PYTHON\;PATH_TO_PYTHON\Scripts;%PATH%
python -m pip install XXX

3、用1或2,更新pip,可以解决问题(对单Python环境更适用)

python -m pip install --upgrade pip

4、修改pip二进制文件
用十六进制编辑工具打开pip.exe
修改python.exe路径
保存

5、用PE编辑器修改pip二进制文件
同方法4

6、解压
用解压工具解压pip,
得到__main__.py
重命名为pip.py
运行

python pip.py install XXX

知识图谱03:JENA

1、下载apache-jena-fuseki和apache-jena
https://jena.apache.org/download/index.cgi

2、将上一篇教程的nt文件转换为tdb格式

cd apache-jena-3.9.0\bat
tdbloader.bat --loc="PATH_TO_TDB\tdb" "PATH_TO_NT\movies_mapping.nt"

3、切换到apache-jena-fuseki-3.9.0目录,启动一次服务,然后退出

4、将教程1里面的Movies.owl,拷贝到apache-jena-fuseki-3.9.0\run\databases路径下面,并重命名为Movies.ttl

5、创建配置文件apache-jena-fuseki-3.9.0\run\configuration\fuseki_conf.ttl

@prefix fuseki: <http://jena.apache.org/fuseki#> . 
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . 
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . 
@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> . 
@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> . 
@prefix : <http://base/#> . 

<#service> rdf:type fuseki:Service ; 
    fuseki:name "movies" ;
    fuseki:serviceQuery "sparql" ;
    fuseki:dataset <#dataset> ; 
    fuseki:serviceReadGraphStore      "get" ;
    fuseki:serviceReadWriteGraphStore "data" ;
    fuseki:serviceUpdate              "update" ;
    fuseki:serviceUpload              "upload"
    . 

<#dataset> rdf:type ja:RDFDataset ;
	ja:defaultGraph <#modelInf> ;
	.

<#modelInf> 
    rdf:type ja:InfModel ;
    #ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>]  
    ja:reasoner [ 
        ja:reasonerURL <http://jena.hpl.hp.com/2003/GenericRuleReasoner> ; 
        ja:rulesFrom <file:///D:/ProjectsMy/KG/apache-jena-fuseki-3.9.0/run/databases/Rules.ttl> ] ; 
    ja:baseModel <#baseModel> ; 
    . 

<#baseModel> rdf:type tdb:GraphTDB ; 
    tdb:location "D:/ProjectsMy/KG/workspace/data/tdb" ; 
    tdb:unionDefaultGraph true ; 
    .

6、创建规则文件apache-jena-fuseki-3.9.0\run\databases\Movies.ttl
这个规则规定了,演过喜剧的演员,叫做喜剧演员(Comedian)

@prefix xsd: <XML Schema> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <https://www.neohope.com/hansen/ontologies/2018/movies#> .

[ruleComedian: (?aPerson :hasActedIn ?aMovie) (?aMovie :hasGenre ?aGenre) (?aGenre :genreName '喜剧') -> (?aPerson rdf:type :Comedian)]
[ruleInverse: (?aPerson :hasActedIn ?aMove) -> (?aMovie :hasActor ?aPerson)]

7、启动apache-jena-fuseki-3.9.0

8、访问http://localhost:3030/

9、进行查询,上一篇的例子也都可以用
http://localhost:3030/dataset.html?tab=query&ds=/movies

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix : <https://www.neohope.com/hansen/ontologies/2018/movies#>

SELECT ?name WHERE {
?aComedian rdf:type :Comedian.
?aComedian :personName ?name.
}
LIMIT 10

10、通过python访问
https://github.com/neohope/kg-demo-for-movie/tree/master/src/query-jena.py

参考链接:
https://zhuanlan.zhihu.com/knowledgegraph
https://github.com/SimmerChan/KG-demo-for-movie

PS:
参考教程中,原作者通过结巴分词+正则匹配+Jena,实现了一个简单的问答系统,感兴趣的话,大家可以看下。