
Java 世界里进行并发编程有 Future 和 ExecutorService(当成 ThreadPool 来对待),及至 Java 8 引入了更为趁手的 CompletableFuture。那么使用 Scala 该如何进行并发编程呢?Scala 能毫无障碍的使用 Java 类库,所以完全可以用 Java 的 API 来使用线程池,只是那不太 Scala 罢了。
既然是 Scala, 就尽量写成 Scala Style 吧,Scala 也有自己的 Future, 还有 Promise 呢? 至于 Promise 与 Future 多大区别,语义上似乎也差不多,只看到 Promise 中有一个 Future 的属性。如果想玩得高级一点的话就该把 Actor 弄起来,它算是所谓的纤程,多个 Actor 可跑在同一个线程中,当然启动要快,内存消耗少,还避免了上下文切换。
这里还是先体验 Scala Future 的用法。Future 本身只是描述了一个任务,及将要获得的结果(或执行的动作),因此那样一个任务也是要放到线程池中去执行。这和 Java 的 Future/ThreadPool 是一样的概念。稍有不同的是线程池的创建与使用,线程池的默认大小配置等。看个简单的应用示例,本次测试的 Scala 版本是 2.11.12,为了突出实际的线程池大小,我们把任务数设置为 20 个
Scala Future 并发编程体验
Read More- 标准 SQL 都提供了下面这种方式一条 INSERT INTO 语句插入多条记录
VALUES 之后用括号列出每一条记录。但是在 Java 中想把上面的语句转换成 PreparedStatement 来插入多条记录时就有些问题。要么写成INSERT INTO Customers(Id, Name, Age) VALUES (1, 'Name1', 21.5), (2, 'Name2', 32.3)
INSERT INTO Customers(Id, Name, Age) VALUES(?, ?, ?), (?, ?, ?), (?, ?, ?) ....
我们不知道 VALUES 后应该列多少个问号,而且 JDBC 对参数的个数是有限制的,最多 2000 个参数。如果根据字段个数来算一次添加多少条记录,那么这条 SQL 语句也是动态的,不能很好的作为 PreparedStatement 进行预编译。以一个表三个字段为例,2000 个参数下一次性最多能插入记录数 666 条,也可能由于输入是 666 条记录的任意数量,所以生成的语句非静态的。
这种方式与每次手动拼凑一个完全静态的 INSERT INTO 语句应该不会有太多的差别。
如果只是写成INSERT INTO Customers(Id, Name, Age) VALUES(?, ?, ?)
然后试图进行下面的操作 Read More 
上一次关注 Scala 新版本特性还是在将近五年前,针对的是 Scala 2.10. 后来也一直在使用 Scala,基本上是 Scala 2.11, 但对 Scala 2.11 所带来的新特性基本无知,大约有个 Macro 功能,没什么机会用上,应用 sbt 时稍有接触。还是老句老话, 了解新特性最可靠的文档是每个版本的的 Release Notes, 比如 Scala 2.12.0 Release Notes.
其中 Scala 2.12 带来的主要特性在于对 Java 8 的充分支持:
- Scala 可以有方法实现的 trait 直接编译为带默认方法的 Java 接口
- Lambda 表达式无需生成相应的类,而是用到
invokedynamic字节码指令(这个是 Java 7 加进来的新指令) - 最方便的功能莫过于终于支持 Java 8 风格的 Lambda,即功能性接口的 SAM(Single Abstract Method)
Scala 的 Lambda 内部实现
这儿主要是体验 Scala 2.12 如何使用 Java 8 风格的 Lambda. 在 Scala 2.12 之前,Scala 对 Lambda 的支持是为你准备了一大堆的 trait 类,有
- Function0, Function1, ...... Function22 (接收多个参数,返回一个值)
- Product1, Product2, ...... Product22 (函数返回多个值,即 TupleX 时用的)

第一次用
spark-submit提交任务,是 Scala 的程序,命令格式是spark-submit --class <main-class> --master local[*] --name "My first Spark Job" spark-test-fat-1.0-SNAPSHOT.jar
结果报出错误
Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
at sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:330)
at sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:263)
at java.util.jar.JarVerifier.processEntry(JarVerifier.java:318)
......
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:119)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)Google 查了下,是需要把 jar 文件中的
META-INF/*.RSA META-INF/*.DSA META-INF/*.SF文件清理掉。我们可以执行如下命令从现有的 jar 中除去zip -d <jar file name>.jar META-INF/*.RSA META-INF/*.DSA META-INF/*.SF
是因为 jar 包中包含有这些文件才造成提交 Spark 时验证文件签名摘要时失败。 Read More
其实很多年前就做过如此的实验,一翻开自己的日志有关于 aspectj site:yanbin.blog, 可以找到 2008 年写的日志。真是流光容易把人抛,红了樱桃,绿了巴蕉。只是那时候 Spring 刚步入 2.0, 才翻开强大 AOP 的篇章,还记得彼时只要是直接使用 AspectJ 就要写 *.aj 文件。而如今 Spring 都到 5.0 了,也就是一年前才重拾起 Spring, 这期间 AspectJ 早就可以不用 *.aj 文件,只需普通 Java 文件,加上 @Aspect 和 @Pointcut 之类的注解就行。
本文内容与几年前写过的日志大体相差不大,再缀上一篇纯粹是个人笔记。这里不以 Spring 5.0 为例,仍然是最新的 4.3.11.RELEASE, 并且直接用 Spring, 而非选择 Spring Boot, 因为用了 Spring Boot 常常搞不清楚哪些是自动配置了的。原生的 Spring 可以使自己掌握一个 Spring AOP 的基本要素。
需求:@LogStartTime 注解的方法,在每次进入该方法时把当前时间写入 ThreadLocal 中去,被 @LogStartTime 注解的方法中随时可以获得进入方法的时间 Read More
昨日刚刚体验了 Terraform 是一个什么鬼东西 Terraform 使用 - 从最简单例子开始,今天再进一步。将来尝试的是使用 Terraform 来部署一个 Lambda 应用,并创建相关的资源。
本例中的 Lambda 要由 Kinesis 来触发,并写数据到 S3 Bucket 中去,所以需要做的事情大致如下:- 创建 IAM Role, 该 Role 要能访问 S3, Kinesis 和 CloudWatch
- 创建一个 Kinesis Stream (指定 Shard 数目)
- 创建一个 S3 Bucket
- 部署 Lambda (要指定能访问 S3 Bucket 的 Role, 并其他参数,如环境变量)
- 设置 Lambda 的 Kinesis 触发器 (指定源 Kinesis Stream 和 batchSize)
以下是 Lambda 的实现代码,从 Kinesis 读出字符串,逗号分割,第一部分作为 S3 Key, 第二部分作为文件内容写入到 S3 Bucket 中去。S3 Bucket 名称从环境变量中读取。 Read More
Terraform 是一个 IT 基础架构自动化编排工具,它的口号是 "Write, Plan, and create Infrastructure as Code", 基础架构即代码。具体的说就是可以用代码来管理维护 IT 资源,比如针对 AWS,我们可以用它创建,修改,删除 S3 Bucket, Lambda, EC2 实例,Kinesis, VPC 等各种资源。并且在真正运行之前可以看到执行计划(即干运行-dryrun)。由于状态保存到文件中,因此能够离线方式查看资源情况 -- 当然,前提是不要在 Terraform 之外对资源进行修改。
Terraform 配置的状态除了能够保存在本地文件中,也可以保存到 Consul, S3, azure, http, swift 等处。
Terraform 是一个高度可扩展的工具,通过 Provider 来支持新的基础架构,AWS 不过为目前官方内建 68 个 Providers 中的一个。其他能用 Terraform 的地方有 Alicloud(阿里云, 实名制备案才能用), Google Cloud, Heroku, Kubernetes, Microsoft Azure, MySQL, RabbitMQ, Docker 等等。愿意的话可以写自己的 Provider, 如搞个 Kafka 的话,用来管理 Topic 等的创建,维护工作。
Terraform 之前我们对 AWS 的操作用的是 awscli, 或 Serverless。awscli 什么都能做,但它是无状态的,必须明确用不同的命令来创建,修改和删除。Serverless 不是用来管理基础架构的,用它创建 Lambda 时创建资源都是很麻烦的事。AWS 提供的 CloudFormation 才是与 Terraform 较类似的工具,但是看到用法就头疼。 Read More两月前论及到 针对接口编程及敏捷编程,如今再一次老调重提。面向对象有一个很重要设计原则:
针对接口编程,而不是针对实现编程
这一原则关键在于理解什么是接口,请参照前文提到的上一篇。因为 Java 语言中有 interface 这个概念,于是 Java 的 interface 便躺枪了,好好的针对接口编程在 Java 中就机械式的变成了针对 interface 的编程。
以致于只要有实现的地方都可能变成像 UserDao.java(接口) 与 UserDaoImpl.java 成对出现,在以后的重构中基本上是为了实现而修改接口,这也进一步违背了针对接口编程的初衷,接口怎么一点也不稳固。
或许有人认为先声明一个 interface,然后我们可能会有多种实现(为将来考虑,不过多数时候只会是单一实现),这很像是 interface 存在的一个理由。可是当我们写下类似 UserDaoImpl 这个样的实现类名时直接宣告了该接口其实就只有一种实现,不然的话再加一个实现的话类名为哪般?UserDaoImpl2? 显然多种实现时 UserDaoImpl 需要重命名了。 Read More

Spring 定时任务实例
Spring 中使用定时任务很简单,只需要 @EnableScheudling 注解启用即可,并不要求是一个 Spring Mvc 的项目。对于一个 Spring Boot 项目,使用定时任务的简单方式如下:
pom.xml 中1<parent> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-parent</artifactId> 4 <version>1.5.3.RELEASE</version> 5</parent> 6<dependencies> 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter</artifactId> 10 </dependency> 11</dependencies>
Application.java Read More
Spring 项目中把大量的 SQL 分散在 Java 代码中,无 Here Doc 的情况下用加号来连接写着实在是不爽,于是之前思考这个 Spring 项目中把 SQL 语句写在 .sql 文件中 -- 把它们写在 *.sql 文件中,但是这个 *.sql 需要特定的格式来标识属性 Key--!select.user
而且还需要一个额外的类 SqlPropertySourceFactory 来解析上面的 *.sql 文件, 识别出 select.user 是 Key, 紧接着后面的块是相应的属性值,用注解引用它时还有点额外的 factory 属性来配置,如
select id, firstname, lastname, address --!update.user
update ........@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)
所以一直在思考是否能够再简单些,是否能用一个自定义的注解,如@SqlPropertySource("classpath:sql/queries.sql")
捉摸了很久,似乎有点难度,不过再不断发掘的过程中找到了这个类org.springframework.core.io.support.PropertiesLoaderUtils, 有下面的代码片断 Read More