React实战笔记—如何动态加载查询条件
如图需要动态加载第五个查询条件
由于框架原因,没法使用父组件直接调用子组件的方式。
下面给我这边的解决方案–>通过页面加载完成之后再根据最新数据强制渲染一次的方式,
代码如下:
1 | //页面渲染之前加载数据 |
这样就可以以动态方式加载查询条件了,如下
读过几年书,尘世间一枚不起眼的小书童
如图需要动态加载第五个查询条件
由于框架原因,没法使用父组件直接调用子组件的方式。
下面给我这边的解决方案–>通过页面加载完成之后再根据最新数据强制渲染一次的方式,
代码如下:
1 | //页面渲染之前加载数据 |
这样就可以以动态方式加载查询条件了,如下
1 | yum remove vsftpd |
先删除已安装的软件,再重新安装完整的vsftpd;
然后添加一个ftp用户和密码
1 | useradd ftpuser |
防火墙开21端口
1 | vim /etc/sysconfig/iptables |
(在有 22 -j ACCEPT 的下面复制一行,端口改成21,wq保存并退出)
重启 iptables
1 | service iptables restart |
修改 selinux(外网可以访问,但无法返回目录,因为selinux)
1 | getsebool -a | grep ftp(查看状态) |
关闭匿名访问
1 | vim /etc/vsftpd/vsftpd.conf(anonymous_enable=NO) |
开机启动 vsftpd 服务
1 | chkconfig vsftpd on |
接下来就可以通过filezilla使用ftp协议访问了如图:
另外这里附上FtpUtil.java工具类,首先如果你是gradle项目需要引入如下依赖包
1 | compile 'commons-fileupload:commons-fileupload:1.3.1' |
代码如下,自行调试即可:
1 | package com.yyicbc.utils; |
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment
1 | [root@localhost software]# java -version |
1 | [root@localhost software]# rpm -qa | grep java |
1 | [root@localhost software]# rpm -e --nodeps tzdata-java-2016g-2.el7.noarch |
或者使用
1 | [root@localhost jvm]# yum remove *openjdk* |
之后再次输入rpm -qa | grep java 查看卸载情况:
1 | [root@localhost software]# rpm -qa | grep java |
首先到jdk官网上下载你想要的jdk版本,下载完成之后将需要安装的jdk安装包放到Linux系统指定的文件夹下,并且命令进入该文件夹下:
1 | [root@localhost software]# ll |
解压 jdk-8u131-linux-x64.tar.gz安装包
1 | [root@localhost software]# mkdir -p /usr/lib/jvm |
1 | [root@localhost software]# vim /etc/profile |
在最前面添加:
1 | export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_131 |
1 | [root@localhost software]# source /etc/profile |
这样可以使配置不用重启即可立即生效。
1 | [root@localhost software]# java -version |
显示:
1 | java version "1.8.0_131" |
到这里,整个安装过程就结束了。
先去到伪zk集群的文件夹付所在目录
1 | touch zkStartAll.sh |
编写内容,其实就是依次进入文件夹启动单机实例
1 | cd /usr/local/zookeeper1/bin |
给文件授权,运行文件
1 | chmod u+wxr startAllZk.sh |
结果就是集群成功启动
1 | [root@nginxslaver local]# ./startAllZk.sh |
redis伪集群启动方式类似
用来记录项目中需要配置但是容易忘记的一些记录
Slogan:学过几年技术,尘世间一枚不起眼的迷途小书童
一句话简单总结,我个人认为RMI就是RPC的java版本实现,当然他们本身底层也有很大的区别,比如序列化协议,网络通讯模型等等,今天我们就来简单的学习一下NC使用的RMI技术;
废话不多说我们直接上代码,我这里区分了服务端与客户端,见下图:
HelloService接口存根
1 | package RPC; |
上述接口的实现类HelloServiceImpl
1 | package RPC; |
服务器启动接口类
1 | package RPC; |
服务器实现类
1 | package RPC; |
5.服务端main方法
1 | package RPC; |
以上我们服务端代码就完成了,简单而言就是通过一个main方法来启动我们的服务器,服务器启动的时候回向服务容器中注册我们的服务;(tips:这里我只是注册了一个服务实现类本身,如果结合之前我说过的日志记录以及事务处理等等,需要将服务实现类本身换成动态代理类),我这里并没有实现服务器的多线程处理,如果需要同时为多个客户端服务,需要将sk = ss.accept();获取到的Socket对象放进一个新的Thread进行操作,也就是说每当有一个client连接到服务器,服务器就新建一个Thread对该客户端进行服务!NC服务端就是采用的这种方式,同步阻塞IO,伪异步线程池;
HClient
1 | package rpcclient; |
客户端服务存根HelloService(这也就解释了我们的NC的接口代码为什么要放在public下面,因为客户端需要这个类的信息)
1 | package rpcclient; |
以上就是我们的客户端代码,我们客户端只放了一个服务方法存根HelloService,那么我们是如何做到向服务端发送请求的了?答案就是动态代理,我们在获取HelloService对象的时候其实就是对该接口的匿名内部类实现进行了动态代理,然后再通过动态代理去向服务端发送请求,服务端拿到我们的请求方法名和请求参数等等去容器中寻找实现类并将执行结果返回到客户端,至此一次完整的RMI请求结束;
1、启动服务端main方法如下图:
2、启动客户端连接服务器,发出请求得到结果:
Slogan:学过几年技术,尘世间一枚不起眼的迷途小书童
开始本章内容之前,本人希望你已经看过了该系列的第一篇UAP应该知道的那些事儿–1!这对你充分理解本章的内容起到了很大的作用,废话不多说我们开始本章的内容!
在平时的开发中,除了写代码,你一定每天都和各种各样的数据库打过交道,Nosql我这里先不说,起码mysql、oracle、sqlserver这些常见的关系数据库你一定不陌生,那么用数据库有一个名词你是一定要了解的,那就是事务(分布式事务今天这里先不谈),啥是事务?
数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
并非任意的对数据库的操作序列都是数据库事务。数据库事务拥有以下四个特性,习惯上被称之为ACID特性。
以上是官方对于数据库事务的一个定义,我这里也不对这些东西做解释了,自行去了解一下这些概念
spring七个事物传播属性:
以上这些不是本章的重点,看一看了解一下先即可。
ok,经过上一节介绍应该对事务有了一个大致的了解了,那么回来我们说说NC,NC支持Oracle和Sqlserver
(这里多说一句,通过修改源码可以支持db2以及mysql,本人已亲证),其实这两个数据库默认的隔离级别都是读已提交(read commit),也就是说一个事务只能读取到另外一个事务commit了的数据,当然你可以根据你项目的需求进行调整,
上一章我强调过了,从源码层面分析了我们NC其实是只支持两种传播属性:Requires和equiresNew
,见下图:
不用多说这是本章的重点,在说本节内容之前,先提一个名词—>jdk动态代理,不知诸位对这个东东有没有了解过,没了解过的建议去百度一下,我这里直接上代码:
1、先有一个接口TargetItf:
1 | package jdkdtproxy; |
2、对该接口有一个实现类
1 | package jdkdtproxy; |
3、产生动态代理并通过动态代理调用方法
1 | package jdkdtproxy; |
执行结果:
1 | invoke before |
是不是觉得很神奇?竟然在你的目标方法内容前后都进行了操作!没错,这就是动态代理,它能够对你的目标对象进行拦截切面,而且我们NC的服务端容器就是完全依赖了这个东东,所有通过upm文件中写了cmt属性的接口在服务容器中都是一个动态代理对象而不是实现类本身,现在回应上一章的内容,你如果通过了NcLocator来获取到了一个对象,然后使用这个代理对象去调用对应的服务方法,然后的东西你明白了吗?来看看下面两张我精心挑选的图:
由于篇幅原因,Requires和RequiresNew具体区别我们下一张详细论述!!!,下一章我们通过实例来详细分析如何让你的代码能够使用到事务以及事务的传播属性。
Slogan:技术界一枚不起眼的迷途小书童
在平时的开发中,如果我们想要在客户端调用服务端部署好的服务,一般我们是这样在客户端通过以下方式:
1 | IxxxService service = NCLocator.getInstance().lookup(IxxxService.class); |
获取到service这样一个接口对象,然后通过这个service调用对应的method就能实现与服务端的通讯,但是诸位有没有想过为什么这样就可以进行client到server的网络IO通讯,其实这里就是通过了jdk的动态代理来实现的,jdk动态代理是javase高级知识点,没接触过的可以去看看相关知识点,在java高级知识介绍中我会用一篇日记来仔细讲解,这里就不做详细介绍。继续讲我们在客户端获取到的service对象就是一个IxxxService接口的动态代理对象,这里看一下动态代理是如何获取的,如下代码:
1 | Proxy.newProxyInstance(classloader, interfaces, InvocationHanddler); |
有没有发现上图中h=RemoteInvocationHandler很眼熟,这就是一个InvocationHanddler的实现方式
这里我通过下面一个通用接口来进行详细说明:
1 | IBillcodeManage lookup = NCLocator.getInstance().lookup(IBillcodeManage.class); |
从上图我们看到在客户端拿到的lookup对象确实就是一个动态代理类,并非对象本身那么简单,换句话说我们可以理解,
NCLocator.getInstance()其实就是获取到客户端jvm中的一个hashmap容器,
key是IxxxService.class,value就是这个接口类的一个动态代理实例,
这样说或许会比较好容易理解,但事实上也确实如此,只是具体实现上面会复杂很多,好了
接下来就去看看这个客户端获取到的动态代理是如何往服务端发送请求的
看到这里是不是有种拨开云雾的赶脚,没错,你没有眼花,我们的NC客户端采用的就是最原始最古老的BIO通讯模型
,不是说这个BIO模型不好,而是因为他存在有很大的局限性,比如同步、阻塞、无法处理高并发访问等,但是用在
erp系统中我觉得是够用的,这里我在整理总结一下当你使用客户端接口的动态代理调用方法时具体发生了什么:
这里再多解释一句,NC服务端启动的时候会有一个ServerSocket.accept()的方法专门用来处理客户端
发送来的连接请求,这也是BIO模型的精髓所在<同步与阻塞>。
这里还有非常一个值得一提的地方见下图,客户端并不是无限制的创建Socket,而是设计了一个Socket连接池来进行Socket复用,原理类似数据库连接池;
Socket s = (Socket)sq.poll();
这就是通过有界阻塞队列来实现Socket容器。
上一节我们讲到了客户端接口类的动态代理发送请求到服务端,那么我们NC的服务端又是如何处理请求,
又是如何将请求发送回客户端的了?我们慢慢来讲,跟第一章一样,我们先通过:
1 |
|
在服务端获取到lookup的动态代理对象,注意了这里我们是在服务端(private)获取了,不是在客户端(client)了哈,重要的事情说三遍:
见下图:
是不是发现了异样,同样的方法在客户端和服务端拿到的lookup对象是完全不一样的!因为服务端获取到的是具体实现类的动态代理,是要去实实在在做事情的了,这也就解释了NC是分服务端容器和客户端两大容器的!见下图:
有没有,看了图p2是不是就感觉发现了新大陆,这就是NC所谓的事务型组件的设计原理:根据接口设计中的方法名后缀来进行判断决定采用何种事务的传播属性,另外强调一下
NC的事务传播属性并没有很多种,从源码层面来看NC只支持最基本的Requires和equiresNew,并非像UAP红皮书中说的还支持mandatory、support以及never,至少我在源码层面是没有发现支持
与spring的7大事务传播属性相差甚远,至于这两种传播属性具体有什么区别,我会在我的第二篇UAP文章中进行剖析,好了这里我再总结一下服务端接收到客户端请求后都做了一些什么操作,见图p11、p12、p13
其实这是一个扩展思考的问题,当时也是因为这个事务问题笨人就多思考了一点,就是说你如果要保证事务有效,
前提条件你必须让你的一次请求过程中拿到的conn是同一个对象对吧,
这个问题我并不想描述的太多,因为这是一个很基础的并发编程问题–>如何让一个变量(conn)成为一个线程的独享变量,
从而达到解决线程安全的问题,这里的解决方案就是ThreadLocal;
我提供几个关键截图,朋友们可以自行去了解一下ThreadLocal的原理再回过头来就看这几行代码,
就能很好的理解其设计原理
上图中的connRef对象就是一个ThreadLocal变量。用于获取当前线程的conn,但是conn对象并非是存在这个变量中的,而是存储在每一个Thread的一个ThreadLocalMap的变量中的,这个ThreadLocalMap中key就是connRef的softreference形式,value就是conn对象,这里有点绕,所以我的建议是先了解原理再看代码;
前前后后写了三四个小时,终于写完了本人的第一篇博文,后续还会更新更多…
Slogan:技术界一枚不起眼的迷途小书童