scala中sbt相应安装及配置信息

2015/08/23 22:09:00 No Comments

在使用scala进行开发时,特别是混合java进行开发时,都推荐使用sbt,而不是使用maven进行开发。因此,本篇描述了我搭建一个基本的sbt环境以及相应的配置信息,并且在idea中也能够识别相应的配置信息。
默认情况下,scala的配置信息使用默认值均会使用 ~/.ivy2以及~/.sbt,作为开发人员,肯定不会使用这些默认值,而是使用统一的配置目录及相关信息.

默认安装情况

默认情况下,将sbt文件从官方(http://www.scala-sbt.org/download.html)下载下来,并解压至指定的目录之后。配置好环境变量(主要是bin)之后,运行sbt,将使用默认的配置下载相应的组件信息。

  • ivy存储配置信息    默认存储在~/.ivy2目录下,主要包括在整个项目开发中所使用的jar缓存,类型maven中的repository
  • sbt启动信息    默认存储至~/.sbt 目录下,主要包括sbt启动时所依赖的组件,如scala信息以及sbt本身的各项jar文件.

自定义配置
其实这些配置信息都可以通过sbt自带的配置文件进行修改,网上在类似替换jar文件,或者在~/.sbt中增加配置项这些作法。但对于不想将配置信息放在~目录中来说,这些都不太方便。要修改这些信息,也很方便,在linux中,我们只需要修改文件sbtopts即可.此文件随sbt提供,在sbt目录下的conf目录中。具体配置如下所示:

read more… »

fastjson 反序列化源码解析

2015/08/16 13:02:18 No Comments

fastjson从0.X版本到最新版本,由于其特殊的编码(即特别编码优化),让人对其实现思路很难处理,加上没有注释,因此在学习了解时也很困难。因此,本篇即从基本概念入手,忽略其一些特殊处理点(对实际结果无意义),了解其反序列化实现思路。
本文基于fastjson版本 1.2.4

1 基本概念

  • token-词法标记      用于标识当前在解析过程中解析到的对象的一个标记,具体的值参考 JSONToken。比如 {,即表示当前正在解析的是一个类似map或对象的格式,而},则表示当前对象已经到底了。
  • ch-当前字符    用于表示当前已经读取到的字符是什么,如 abc,当位置为1时,则当前字符为 b
  • bp-解析字符位置    用于表示当前字符所位于原始字符串中的哪一个位置,与ch是相对应的,它始终表示最新的一个位置,如果需要记录一些历史位置。如字符串起始位置,数字起始位置等,则需要使用其它标记,如np。
  • sbuf-字符缓冲    在解析字符串时的特殊存储区域,主要是用于解析转义字符时的临时存储区。即如果原字符串为 a\\t,则实际解析的字符串应该为a\t,那么原字符串为3位长,解析之后为2位长。即需要另行存储。字符缓冲区如名所示,为一个字符数组,需要需要单独的定义来存储长度信息,如使用sp。
  • sp-字符缓冲区位置    这个用于表示在字符缓冲区之间记录当前字符串(或数字串)等的长度信息,同时也等同于当前的一个位置(如果坐标从0开始)。
  • np-数字解析位置    用于实际表示在解析到常量信息时起始点的标记位置。通过np + sp,即计算得出相应的区间值了。

read more… »

基于redis的分布式锁 RedissonLock实现分析

2015/07/05 21:34:01 No Comments

在分布式锁的实现当中,都是通过另一个中央服务来存储相应的状态,来达到一个应用分布处理的目的。这里分析了一种通过redis来进行锁实现的细节,以描述在整个实现细节中的处理点。

通常在锁实现当中, 都要实现获取锁,等待锁,释放锁这几种关键的业务场景。然后在这几种场景的基础之上,还需要实现更多的语义,比如过期时间,等待时间等。通过redis的setNx可以达到获取锁的语义,因此大多数的实现均是采用这种手法来进行锁判断和处理(类似的手法还包括concurrentHashMap的putIfAbsent)

本文基于redission版本1.2.0,类RedissionLock.

线程间协作

1. 获取锁

获取锁即通过redis的setNx命令来实现,此命令的意义即仅当相应的值不存在时,才能设置成功。如果设置成功的话,即认为当前能够获取到相应的锁了。相应的主要代码如下所示:

Boolean res = connection.setnx(getName(), currentLock);

其中name即可认为是lock的一个内部表示名字,其中多个线程共享同一个lock,即在操作命令时会使用同一个name值。

read more… »

java内部类final语义实现

2015/05/31 11:29:39 No Comments

本文描述在java内部类中,经常会引用外部类的变量信息。但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索。本文从字节码层描述在内部类中是如何实现这些语义的。

本地临时变量 基本类型

final int x = 10;

new Runnable() {
    @Override
    public void run() {
        System.out.println(x);
    }
}.run();

当输出内部类字节码(javap -p -s -c -v)时,如下所示:

         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: bipush        10
         5: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
         8: return

可以看出,此常量值直接被写在内部类的临时变量中,即相当于进行了一次变量copy。

read more… »

spring 多placeHolder问题的解决方案

2015/04/15 17:13:05 No Comments

当前的spring版本为: 4.0.6.RELEASE
问题官方地址:https://jira.spring.io/browse/SPR-9989

问题重现

@Component
public class Tb {
    @Value("${tb.username:abcd}")
    private String username;

    public String getUsername() {
        return username;
    }
}

以上为定义bean,其中属性表示需要去获取属性为tb.username的属性定义,默认值为abcd。然后在spring分别如下配置

<context:property-placeholder location="classpath:springa.properties" ignore-unresolvable="true" ignore-resource-not-found="true"/>
<context:property-placeholder location="classpath:springb.properties" ignore-unresolvable="true" ignore-resource-not-found="true"/>

配置文件的值如下所示:
配置文件一:tb.username1=spring1
配置文件二:tb.username=spring2

因为在配置文件2中,有相应的配置定义,因此我们期望其返回username的值为 spring2。但是在实际运行中,此值即是abcd,如下输出所示:

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Tb tb = context.getBean(Tb.class);
        System.out.println("->" + tb.getUsername());
    }

//输出值
->abcd

本文即通过更换相应的属性解析器,用于解决此问题,以让spring能够正常的解析并输出我们需要的值。

read more… »

redisson的理解和使用-调用流程

2015/03/29 21:11:39 No Comments

redisson是一个用于连接redis的java客户端工作,相对于jedis,是一个采用异步模型,大量使用netty promise编程的客户端框架。

0     代码示例

        //创建配置信息
        Config config = new Config();
        config.useSingleServer().setAddress("localhost:6379").setConnectionPoolSize(5);

        Redisson redisson = Redisson.create(config);

        //测试 list
        List<String> strList = redisson.getList("strList");
        strList.clear(); //清除所有数据
        strList.add("测试中文1");
        strList.add("test2");

        redisson.shutdown();

从代码上来看,其基本的使用非常简单,在最后的使用当中。除与redisson打交道之外(获取各种数据结构),完全感觉不到与redis的信息连接。甚至于返回于上层直接不需要考虑下层的实现,一切均由redisson进行了封装。

read more… »