Java

apache curator

August 18, 2017
Zookeeper, Java, Distributed

“Guava is to java what Curator is to Zookeeper”. Start # Curator之前介绍过一些,是一个使用流式API方式实现的Zookeeper的Java客户端。 Get a connection # connection的实例(CuratorFramework)是用工厂模式分配的(CuratorFrameworkFactory),对于一个zk集群,你只需要一个连接的实例。 同时你可能会用到的是RetryPolicy 去设置失败重试的参数,一般你会这样使用: RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3) CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy); client.start(); 客户端需要显式的start并且在不用的时候显式的close. 在链接成功以后就可以直接操作对应的集群。并且,如果在执行操作的过程中出现了连接错误,curator的manage会自动重新尝试操作。 分布式锁 # 不可以对某个路径下的节点进行上锁: InterProcessMutex lock = new InterProcessMutex(client, lockPath); if ( lock.acquire(maxWait, waitUnit) ) { try { // do some work inside of the critical section here } finally { lock.release(); } }

synchronized 同步锁

August 18, 2017
Java

synchronized # 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象; 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象; 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象。 代码块加锁 # 一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。我们看下面一个例子: /** * 同步线程 */ class SyncThread implements Runnable { private static int count; public SyncThread() { count = 0; } public void run() { synchronized(this) { for (int i = 0; i < 5; i++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public int getCount() { return count; } } 调用的方式如下: ...

java wait一种线程通信方式

August 18, 2017
Java, 多线程, 线程通信

在一个异步改同步的工程中,有两种方式,一个是轮询,一个是中断。这里介绍一下中断的操作。 在看这一部分之前你可能先要看下一篇文章,关于synchronized同步锁的问题。下面会用到。 如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓冲区中有内容待消费(不为空)。相应的,消费者可以通知生产者可以开始生成更多的数据,因为当它消耗掉某些数据后缓冲区不再为满。 wait # Object类中相关的方法有两个notify方法和三个wait方法: 因为wait和notify方法定义在Object类中,因此会被所有的类所继承。 这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为。 wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。 线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。 要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。 与sleep不同的是sleep不会释放锁。 notify # notify()方法会唤醒一个等待当前对象的锁的线程。如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)。 被唤醒的县城也并不是直接就能执行,而是要进入到正常的线程竞争过程中。 同样的你notify方法也要放在synchronized方法或者synchronized块中执行。 正确的使用 # 除了要在同步的基础上使用以外,在书《Java并发实践》中,作者提出一定要在循环中使用wait。正确的代码应该是下面的样子: // The standard idiom for calling the wait method in Java synchronized (sharedObject) { while (condition) { sharedObject.wait(); // (Releases lock, and reacquires on wakeup) } // do action based upon condition e.g. take or put into queue } 在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。 这两个函数都是对于某个对象来说的,这个对象一定是一个多线程共享的对象。是同步,是利用锁的机制进行同步的。 在生产者消费者的概念中,就是对产品的队列进行共享,所以wait()和notify()都是queue的动作,同时锁也是对于queue来说的。

Java lamda 表达式

August 17, 2017
Java

本文大部分来自该博客,有些是自己的写代码的经验,觉得作者写的很清晰,非常棒。 1. 什么是λ表达式 # λ表达式本质上是一个匿名方法。让我们来看下面这个例子: public int add(int x, int y) { return x + y; } 转成λ表达式后是这个样子: (int x, int y) -> x + y; 参数类型也可以省略,Java编译器会根据上下文推断出来: (x, y) -> x + y; //返回两数之和 或者 (x, y) -> { return x + y; } //显式指明返回值 可见λ表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。 下面这个例子里的λ表达式没有参数,也没有返回值(相当于一个方法接受0个参数,返回void,其实就是Runnable里run方法的一个实现): () -> { System.out.println("Hello Lambda!"); } 如果只有一个参数且可以被Java推断出类型,那么参数列表的括号也可以省略: c -> { return c.size(); } 函数接口 # lamda表达式是什么?它不是一个object,而是一个函数接口。 在java8中引入的新特性,函数接口。定义如下:一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数接口。 也就是你生命一个接口,这个接口只有一个显示的抽象函数,那么这个函数其实就是lamda表达式本身。你可以写个类来实现它,然后在传入lamda表达式的位置传入这个类的实例,效果与lamda表达式是一样的。 这个接口可以使用一个注解来注解出来:@FunctionalInterface。 你可以用lamda表达式为一个函数接口赋值: Runnable r1 = () -> {System. ...

ZooKeeper

August 17, 2017
Java, Distributed

暂且将恼人的Tomcat放在一边,来解决新的问题,并学习新的玩意儿。 Zookeeper 是啥 # 动物园管理员,分布式服务就像是一个动物园。 Zookeeper是一个开源的分布式应用程序协调程序,为分布式应用程序提供一致性服务。 在分布式计算的应用中,最令人头疼的就是分布式锁的问题。同时各种同步问题也很让人崩溃,Zookeeper就是封装可一些算法,保证了其分布式服务的一致性,作为很多分布式服务的基础服务程序。 ZooKeeper 的设计原理 # 官方称之为鸟瞰: 第一段在百度百科上。 在特性上面,zookeeper有这样几个特点。 使用文件系统的结构来存储数据。 数据在用户的角度来看,是以类似与unix文件系统的方式来组织的,所以其定位方式是使用路径来定位数据。但是与文件系统不同的是,每个结点都可以存储数据,没有文件夹和文件的区别概念。 高并发低延迟。 存储的数据在每一个zookeeper服务节点上都是一样的,所以读数据只要连接一个服务器直接读取就可以。数据的大小被限制在1M以内。 高可用,自动故障转移。 这个是其设计的精髓之一,下面重点会讲。 下面概要的讲一下运行的逻辑。 选举 第一个,非常重要的步骤就是选举,在集群上部署完zookeeper以后,他们便开始执行选举流程,使用选举算法Fast Paxos作为基础。选举会产生一个leader。 客户端与server 当有客户端与一个服务器建立连接的之后,他们之间会维持一个tcp连接,客户端会给服务器发送心跳请求,告诉服务器自己还在线。如果一个server监测到一个客户端断线了,就会在本地清除相关的数据。而客户端会重新去找一个server建立连接。 写请求 在客户端读取数据的时候只要在其对应的服务器上读取就可以了。当其要写数据的时候,server会将这个写请求转发给leader服务器,leader将这个写请求统一发给每一个server进行写数据操作,当确认有严格的大于一半的server都写入成功以后,就算是写请求成功,再返回给原server,由原server返回成功给客户端。 重新选举 leader会给server之间保持通信,通常就是所说的心跳。leader通过心跳来确认server是否存活,同时,server也可以确认leader是否存活,如果leader挂了,servers就会重新进行选举,然后再提供服务。 通知 watcher是zk比较特殊的设计,允许一个或多个客户端绑定多个节点数据。当zk上的数据发生变化的时候能够通知到相应的客户端。这个设计就可以用来做很多的应用啦。redis数据库同样也有提供这样的消息发布与订阅的功能,不过那个是特意实现的一个功能给应用使用的。 实现上的诸多细节 # 在听之前的老司机分享的时候,他们探讨了很多实现细节上的问题,感觉实现这样的一个分布式系统还是非常有挑战的。 比如,如果写请求进行中leader挂掉了怎么办,数据tcp丢包了怎么办。如何同步数据等等。有空很想看看其实现方式。 使用 # (这里补充一下服务器版的安装。与使用) 最主要的使用途径还是通过客户端程序来访问zk。客户端有Java、python、lua、Go等。 我用java,所以。。 maven # <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.3.5</version> </dependency> 不过,这个有一点低端,所以我使用另外一个客户端的实现:curator。也是一个开源的zk客户端的实现,封装层次更高,所以操作更简便。 Curator框架提供了一套高级的API, 简化了ZooKeeper的操作。 它增加了很多使用ZooKeeper开发的特性,可以处理ZooKeeper集群复杂的连接管理和重试机制。 这些特性包括: 自动化的连接管理: 重新建立到ZooKeeper的连接和重试机制存在一些潜在的错误case。 Curator帮助你处理这些事情,对你来说是透明的。 清理API: 简化了原生的ZooKeeper的方法,事件等 提供了一个现代的流式接口 (提供了Recipes实现: 如前面的文章介绍的那样,基于这些Recipes可以创建很多复杂的分布式应用.这部分不明白,待补充)。 Curator框架通过CuratorFrameworkFactory以工厂模式和builder模式创建CuratorFramework实 例。 CuratorFramework实例都是线程安全的,你应该在你的应用中共享同一个CuratorFramework实例. 工厂方法newClient()提供了一个简单方式创建实例。 而Builder提供了更多的参数控制。一旦你创建了一个CuratorFramework实例,你必须调用它的start()启动,在应用退出时调用close()方法关闭. <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.7.0</version> </dependency> 这个版本的API 是流式的API,也就是。。用的时候一句话里有一串的调用,不断的点操作符。 for 一个zample: client. ...

tomcat Server.xml及其启动顺序

August 16, 2017
Java, Web, Tomcat

欲仙又欲死。阿里巴巴真是一朵大奇葩。 一个写死的回调地址就能浪费我两天的时间去搞,还没有搞定。此坑绵绵无绝期。 一个sso的回调地址,写死的,要强行将应用部署到ROOT里中去。 在tomcat中有一个配置文件经常被用到,conf/server.xml。这个配置文件描述了如何启动tomcat server。 tomcat是servlet的容器,也就是能够运行servlet的一个程序。作为一个http服务的程序,可以监听端口,处理请求等。 配置文件结构 # <Server> <Listener /> <GlobaNamingResources> </GlobaNamingResources <Service> <Connector /> <Engine> <Logger /> <Realm /> <host> <Logger /> <Context /> </host> </Engine> </Service> </Server> 对我们来说,内层的Service才是有操作意义的部分。主要的部分简介如下: 元素 说明 service 提供服务的主体,默认的名字是Catalina Connector 客户端与服务端之间的连接,包括端口,协议版本,超时时间,等。 Engine 请求的处理机,接收和处理Connector的请求, 与host的联系比较大 Context 表示一个应用 host 表示一个虚拟主机 Tomcat Server处理一个http请求的过程 # 假设来自客户的请求为:http://localhost:8080/wsota/wsota_index.jsp 在这里有一幅图我觉得非常清晰的说明了这个过程,但是其本身跟这个毫无关系。 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得 Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应 Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机) localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为"“的Context去处理) path="/wsota"的Context获得请求/wsota_index.jsp,在它的mapping table中寻找对应的servlet Context匹配到URL PATTERN为.jsp的servlet,对应于JspServlet类 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法 Context把执行完了之后的HttpServletResponse对象返回给Host Host把HttpServletResponse对象返回给Engine Engine把HttpServletResponse对象返回给Connector Connector把HttpServletResponse对象返回给客户browser Context # 来看最重要的Context, 一般我们为每个应用做的定制化的东西都是依靠这个来做的,就比如我们要把war包部署成一个默认的应用。 ...

Java Json And Object

August 15, 2017
Java, Http

在写RESTFul风格的接口的时候最经常使用的就是Json和对象的互换。 今天记录一下阿里巴巴开源的FastJson的使用方式。 FastJson号称最快的Json解析工具包。有幸听了作者的分享会,并且在前几天的转正答辩的时候,他作为我的面试官之一。花名很奇特,叫高铁,可能这就是FastJson为什么这么快的原因吧。 在听分享会的时候,惊叹于其将一个小小的工具包中运用了如此多的优化方式。他曾是阿里安全团队的一元,对于Java底层非常了解,并且一些算法能力也很强,更是运用了产生式编程的神奇方式编写了这个工具包的某些部分。 package # 这是开源的工具,听闻,据说是阿里对Java社区做的最大贡献了。 import com.alibaba.fastjson.*; maven: # <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.36</version> </dependency> Example # 其对于json的操作都是在几个静态类中进行的。 举几个常用的例子来说名用法: 将Json文本数据信息转换为JsonObject对象,通过键值对获取值 # private static void json2JsonObject() { //一个JsonObject文本数据 String s = "{\"name\":\"xxx\"}"; //将JsonObject数据转换为Json JSONObject object = JSON.parseObject(s); //利用键值对的方式获取到值 System.out.println(object.get("name")); } 将Json文本数据转换为JavaBean # 需要注意的是,Json文本信息中的键的名称必须和JavaBean中的字段名称一致。 private static void json2BeanM2() { String s = "{\"id\":\"xx\",\"city\":\"xxx\"}"; //一个简单方便 的方法将Json文本信息转换为JsonObject对象的同时转换为JavaBean对象! Weibo weibo = JSON.parseObject(s, Weibo.class);//Weibo类在下边定义 System.out.println(weibo.getId()); System.out.println(weibo.getCity()); } Map类型的数据转换为JsonString # Map<Integer, Object> map = new HashMap<Integer,Object>(); map. ...

Java HttpClient

August 15, 2017
Java, Http

来记录一下Java 发起Http请求的方法。 这里使用的是org.apache.http包中的一些封装工具。 首先实例化一个client: CloseableHttpClient httpclient = HttpClients.createDefault(); 然后来实例化一个URIBuild: URIBuilder builder = new URIBuilder(url); 如果Http请求带有参数,就设置在uri中: builder.setParameter(key, value); 实例化一个Httpget/Httppost: HttpGet httpget = new HttpGet(builder.build()); HttpPost httppost = new HttpPost(builder.build()); 你可以设置请求的Header: httpget.setHeader("Accept", "application/json"); // 接收json数据格式 发送请求: CloseableHttpResponse response = httpclient.execute(httpget); 查看请求结果: if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf-8"); } 更多设置可以直接补全出来看。

每天读点Spring(2)--Start

August 12, 2017
Java, Spring, Maven

在本章中,作者开篇就讲到,学习一个新的开发工具最难的就是不知道从哪里入手,尤其是Spring这样有很多选择的框架。但是幸好在这本书中是简单的,下面介绍一些必要的基本知识。 这就是很人性的化的写技术书籍的方式,透露出考虑之周到。 我觉得很多时候,国内的教育体制总是要用比人家多的时间去学会一个东西。很多人看到老外中学成绩都很差,到了大学才开始学习。但是仔细想一下就会发现不太对劲,为什么人家学习的深度比我们还深呢?明明没有我们的基础好,也没有我们花费的时间多啊。 我觉得很大一部分原因是国内的教材有问题。很多教材都是非常的笼统的介绍一个东西是什么,然后就搬上一大堆理论出来证明。但是让人看了很费劲,因为我不一定就具备了看懂这个知识的基础能力,可能我要先去了解一下什么东西再来看这个会效果更好。在我看的很多国外工程师写的文档或者是书中,都有这样的设定,要么会给出在你继续往下看之前你需要去了解的知识清单,要么就直接把需要的知识写在正式内容之前。这是一个非常负责的行为,在人家眼里是很正常的事情,在我们这里可能就是不在我的工作范围中。就像初中上高中的时候,初中老师说这个你们在以后上高中就知道了,高中老师说,你们应该在初中就学过了。有些老师会讲,这些老师的学生就会很轻松的就掌握这部分东西。 不要觉得什么都要别人告诉你很low,学习就是一个这样的过程,你需要别人不断的告诉你一些东西,那些已经被解决的问题不是你主要要解决的问题,而是你要快速掌握的理论。你在学车的时候如果碰到一个什么都不教,直接让你把车开起来上路的师傅,你就会说:“如果我什么都知道还要来学嘛?”,就是这个道理。 国内很多作者纯粹就是急于求成,这些看似不是自己的责任的事情就不做,默认你会。然后把那些确实是核心的问题官方的表述一下,就算是写完了一本技术著作。很不厚道,我作为学生非常鄙视这样的人。 需要具备的知识 # 也不能算是知识,是关于Spring的一些更细节的信息,和设计。 理解Spring的包 # 这部分介绍了Spring是由哪些模块构成,你可以按照自己的需求选择使用那些模块,并介绍了每个模块的基本功能。 在Spring4.0.2发行版中一共有20个包。每个模块的包名格式如下,以aop为例:spring-aop-4.0.2.RELEASE.jar Jar File Description aop 如果你要用到AOP功能,或是你用到的Spring的其他模块用到了这个功能,你就需要把这个包添加进你的项目中 aspects 如果你用到了AspectJ AOP的功能就要包含这个包(Aspectj是Eclipse出的一个AOP的编程框架,Spring 兼容了它) bean 包含了所有用来实现Spring控制bean的类,其中很多类也都支持Spring的bean工程模式,例如解析xml和注解的类 context 这个包给Spring core提供了很多扩展能力,Spring的很多功能都依赖于此,并且实现交互的脚本语言也是集成在其中的 context-support 这个包有扩展了context的功能,例如邮件支持、模板引擎例如Velocity、FreeMaker,此外还有很多作业的执行和调度,例如CommonJ(计时器)和Quartz(作业调度)都打包在这里。 core 这是你必须包含的包,其中的类被用在很多其他的包中,并且有一些全局工具你也可以用在自己的代码中 expression 这个包是支持Spring Expression Language的,是一种强大而简洁的装配Bean的方式 instrument 这个模块包括Java虚拟机的引导(翻译有待确认)?当你在使用AspectJ时需要使用这个包 instrument-tomcat JVM Bootstrapping in the tomcat-server jdbc 数据库链接操作相关 messaging 是基于消息的应用相关的,以及支持STOMP消息文本协议 orm 扩展了JDBC,支持ORM框架,诸如Hibernate、JDO、JPA oxm 支持Object/XML Mapping (OXM) test 提供了强大的单元测试的功能,紧密集成了JUnit tx 支持分布式事物操作 web web功能的核心,支持了文件上传,参数解析等 web-mvc 支持MVC模式的web web-portlet 门户网站服务器部署支持(Not know) websocket 支持Java API for WebSocket(Not know) 随后讲了你可以用maven获取这些,就像你不知道maven一样 ...

每天读点Spring(1)--Introduction

August 11, 2017
Java, Spring

Java如果没有Spring,绝不会这么流行。 Spring将很多Java的设计模式框架化,使得Java的开发效率得到很大的增长。 想系统的学习一下Java,但是又要与工作接轨,所以就选择了Spring这个中间的角色来开始学习。我学习的教材主要是英文版的《Pro Spring 4》,这本书在CSDN上有pdf版本,不是影印版,非常优质。 为什么不用中文的呢,一个是因为中文的书中在Introduction上就写得不好,无法从宏观上去解释这个框架的精髓,这个很致命,想比较外文版的读物,虽然偏长了一些,但是很对概念能够很清晰的表述,对于我这样的技术新人来说很重要。另一个原因是,本身的英语能力没有场景去使用,看看英文的技术专业书籍,有利于英语能力也更有利于以后看英文的代码注释。 每天坚持看一点,是个很难的工作。 What is Spring. # 在第一章中对Spring这个项目本身做了一些介绍。包括这个项目是在Java一片火热的情况下诞生的,并且诞生至今非常的优秀等等。 我觉得最重要的是,作者解释了什么是轻量级这个问题。 所谓轻量级并不是代码量很少也不是代码的框架设计很简单,而是一种传达除了Spring这个框架自己的思考哲学,就是让Java项目变得轻量化起来。 随后介绍了Spring项目的两个最重要的技术基础,IOC(控制反转)或者在文中着重讲述的DI(依赖注入)的说法。在前面的文章中我已经介绍过这个概念,在设计模式上属于工厂模式的一种实现。还有一个就是AOP(面向切面编程),也有人理解为面向方便编程。 除了这两个重要的技术基础以外,介绍了Spring框架本身有非常多的方便的设计,兼容非常多的东西,在数据交互、xml、交互式脚本语言等方面都做了很多的工作,并且引起Java标准基金会的注意,影响了基金会的很多标准的制定等。 介绍就是要这样,从宏观上去提纲挈领的介绍一个事物。