Posted in Java, 技术

有趣的译文 《Java Pattern 那些小事》

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

一、现代的玩具 – Java 可以做很多事

一个 Q 与 A 的对话,展示了 Java 那些小事。

Q : 5 是整数吗?

A : 是。


Q : -23 是数吗?

A : 是,但负数使用场景很少。


Q : 5.32 是整数吗?

A : 不是,我们不用这种数值类型表示 5.32 。


Q : 5 属于什么数值类型?

A : int (整型)。
批注: int 是基本类型,int 代表整数。


Q : 快,想出另一个整数!

A : 19?


Q : 那 true 属于什么数值类型?

A : boolean (布尔型)。


Q : false 属于什么数值类型?

A : boolean。


Q : 想得出其他布尔值吗?

A : 没有,布尔值只有 true 和 false。


Q : int 是什么?

A : 一种类型。


Q : boolean 是什么?

A : 另一种类型。


Q : 什么是类型?

A : 类型是一个相关值集合的名称。


Q : 能举例解释下类型吗?

A : 使用类型就像使用一种集合一样。比如使用 boolean 可以表示逻辑值:是与非


Q : 能创建新的类型吗?

A : 我们还不知道怎么创建。


Q : 画出下面类的基本关系。

abstract class Seasoning {}

class Salt extends Seasoning {}

class Pepper extends Seasoning {}

A : 这样画?
图 1.1 Seasoning 类关系图

wechatimg4


Q : 是的。Seasoning 是数据类型,Salt 和 Pepper 是 Seasoning 的具体类型。

A : 好的。三个都是新类型吗?


Q : 是的。那么 new Salt() 是一个 Seasoning 吗?

A : 是的。 new Salt() new 关键字表示创建了 Salt 的一个实例,每个 Salt 的实例也是 Seasoning。


Q : new Pepper() 也是吗?

A : 是的。它也是一个 Seasoning。 new Pepper() new 关键字表示创建了 Pepper 的一个实例,每个 Pepper 的实例也是 Seasoning。


Q : 什么是 abstract , class 和 extends 关键字?

A : 简单地说:
abstract class 表示抽象数据类型
class 表示具体类型
extends 连接了具体类型到数据类型


Q : 还有其他的 Seasoning 具体类型吗?

A : 没有,因为只有 Salt 和 Pepper 继承 Seasoning。


Q : 正确。只有 Salt 和 Pepper 是 Seasoning 的具体类型。我们见过类似 Seasoning 数据类型吗?

A : 没有。但是 boolean 类型有两个值:true 和 false。
批注:值与具体类型是不同的。


Q : 再定义一个 Seasoning 具体类型:

class Thyme extends Seasoning {}

A : 再来一个:

class Sage extends Seasoning {}

Q : 4 个 Seasoning 具体类型了。

A : 是的。


Q : 什么是笛卡尔点?

A : 是一对数字。


Q : 曼哈顿地点位于哪里?

A : 两个城市街道的十字路口。


Q : 看代码,CartesianPt 类和 ManhattanPt 类有啥不同于 Salt 类和 Pepper 类

abstract class Point {}
class CartesianPt extends Point {
    int x;
    int y;
    CartesianPt(int _x, int _y){
        x = _x;
        y = _y;
    }
}
class ManhattanPt extends Point {
    int x;
    int y;
    ManhattanPt(int _x, int _y){
        x = _x;
        y = _y;
    }

}

A : 两个类中 {} 包含了三个元素。x 和 y 是表示点的坐标,但是构造函数里面包含什么呢?(批注:构造函数是同类名的函数)


Q : CartesianPt 和 ManhattanPt 各自的构造函数里面包含各自的字段值。

A : 那怎么使用构造函数呢?


Q : new 关键字作用于构造函数,会创建一个新的该类型实例。

A : 这样子呀。


Q : 比如下面的代码:

new CartesianPt(2,3);

使用 CartesianPt 的构造函数,创建一个 CartesianPt 实例。

A : 这样创建的 CartesianPt 实例 ,其字段 x 值为 2,y 值为 3。

class CartesianPt extends Point {

还有 extends 关键字表示创建的 CartesianPt 也是 Point。


Q : 对。那么下面代码是创建一个 ManhattanPt 实例吗?

new ManhattanPt(2,3);

A : 是,它也有 x 值为 2,y 值为 3。


Q : 构造函数就这样?

A : 基本是了,但在没有定义过构造函数的代码里,以前用过构造函数。这是怎么实现的呢?


Q : 比如 Salt 和 Pepper 没有任何字段,但是它们有个默认构造函数。

A : 这是正确使用默认构造函数的方式吗?


Q : 是的。默认构造函数没有包含字段值。使用 new 关键字创建实例时,创建的实例没有字段值。

A : 好,下面这段代码呢?

new Point()

Q : Point 是一个抽象类,它是不完整的类,所以 new 关键字不能创建 Point 实例。

A : 这就说得通了,继续。


Q : 以下定义的类是另一种抽象数据类型和它的具体数据类型吗?

abstract class Num {}
class Zero extends Num {}
class OneMoreThan extends Num {
    Num predecessor;
    OneMoreThan (Num p) {
        predecessor = p;
    }
}

A : 是的。它们定义了一种抽象数据类型和两个具体数据类型。
图 1.2 Num 类关系图

wechatimg5


Q : new Zero() 是 Num 的实例吗?

A : 明显是的。就像 new Salt() 是 Salt 的一个实例。


Q : new OneMoreThan(new Zero()) 是 Num 的实例吗?

A : 是。OneMoreThan 继承了 Num,new OneMoreThan() 是一个 OneMoreThan 实例,本身也是一个 Num 实例,并包含了一个 Num 实例(这里是指new Zero())。


Q : 为什么 OneMoreThan 可以这样实现?

A : new Zero() 是一个 Num 实例,OneMoreThan 的实例创建时,包含了 Zero 的实例。


Q : 包含 Zero 实例?

A : OneMoreThan 的实例拥有一个值叫做 predecessor,即这个值可以是 new Zero()。


Q : predecessor 只能是 Zero 的实例?

A : 不是的。Num predecessor 说明了 predecessor 是一个 Num,所以具体表现为 OneMoreThan 或者 Zero 的实例。


Q : 那 new OneMoreThan(new OneMoreThan(new Zero()))呢?

A : 一个 Num 的实例,最外层的 new OneMoreThan 拥有了一个 Num 的实例:new OneMoreThan(new Zero())


Q : 那 new OneMoreThan(0)?

A : 胡说,0 不是一个 Num 。


Q : new Zero() 和 0 一样吗?

A : 不一样,虽然 new Zero() 和 0 概念相似,但不一样。


Q : new OneMoreThan(new Zero()) 和 1 概念相似?

A : 是的,但是他们是不一样的。


Q : new OneMoreThan( new OneMoreThan( new OneMoreThan(new Zero())))和哪个数概念相似?

A : 3


Q : Num 比 boolean 多吗?

A : 多很多。


Q : 比 int 多吗?

A : 不。


Q : 说下 new Zero() 和 0 的区别呢?

A : 我们得区别它们。new Zero() 是 Zero 的一个实例,意味着也是 Num 。0 是一个 int。


Q : 正确。不同数据类型的实例就是不同的。

A : 类型是一系列实例的统称。


Q : 基本类型(int 和 boolean)是不同的。

A : 那些不是基本类型呢?


Q : 类定义不引入基本类型,比如上面提到的 new Zero() 不单单是 Zero 的实例,也是 Num。任何继承 Num 的数据类型都是。

A : 然后呢?


Q : 就像每个数据类型继承 Object。

A : 就是说,所有类都是一个对象。


Q : 正确,下面有所体现。

A : 好的。


建议一:
自定义数据类型时,使用抽象类
自定义具体数据类型时,使用 extends 关键词继承抽象类


Q : 看看下面的定义?

abstract class Layer {}
class Base extends Layer {
    Object o;
    Base(Object o) {
        this.o = o;
    }
}
class Slice extends Layer {
    Layer l;
    Slice(Layer l) {
        this.l = l;
    }
}

A : 定义了 Layer 抽象数据类型和其两个具体数据类型 Base 和 Slice。其中 Base 包含一个值对象 Object。


Q : new Base(new Zero()) 是什么?

A : 一个 Base 的实例,即是 Layer 又是 Object 的实例。


Q : new Base(new Salt()) 是什么?

A : 一个 Base 的实例。但 new Base(new Salt())new Base(new Zero()) 是同一个数据类型吗?


Q : 是的。因为对象实例由 new 关键字创建,而它们都是 Base。

A : 因为 Base 包含的值对象是 Object。所以可以是 new Salt()new Zero()


Q : 任何都是个 Object 吗?

A : new 关键字创建的都是对象。自然 String 、Arrays 也是对象,这里我们不展开讲。


Q : 是的。下面的是 Layer 实例吗?

new Base(5)

A : 5 没有通过 new 创建,所以这个错误的语法。


Q : 下面的是 Layer 实例吗?

new Base(false)

A : false 没有通过 new 创建,所以这个错误的语法。


Q : 下面的是 Layer 实例吗?

 new Base(new Integer(5))

A : 是的。 new Integer(5) 创建了一个 int 对象。


Q : 那么怎么创建一个 Layer 实例拥有 false?

A : 简单:

 new Base(new Boolean(false))

Q : int Integer / boolean Boolean 混乱了?

A : 以后会涉及到。


Q : 期待更多吧。

A : 迫不及待。

Posted in Working Skills, 技术

Java Web 工作技巧总结 16.10

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

在你成为领导者以前,成功只同自己的成长有关。
当你成为领导者以后,成功都同别人的成长有关。

1.聊聊并发插入&代码

场景:业务中有些ERP第三方调用该接口,导致多组同样的数据包会调用同一个插入接口。一般都是XXXParamList,一个批量插入的接口。

首先聊聊批量插入的代码,一般都会这样搞,伪代码

for(XXXParam xxx : XXXParamList)
validationXXXParam(xxx);
XXXDao.batchInsert(XXXParamList)

a.前端 – 灰色按钮
就是提交的时候控制,不能重复条form或者ajax。
b.后端 – 分布式锁
分布式锁的资料上次分享过:传送门 ->
http://www.cnblogs.com/PurpleDream/p/5559352.html
c.数据库 – UK
在数据库建表中设计时,设置 SQL UNIQUE 约束:传送门->
http://www.w3school.com.cn/sql/sql_unique.asp

2.继续说说数据库字段设计

技巧1 关系表 -> JSON Text字段
场景:比如商品详情页面,白色Apple,金色Apple…对应的图片显示。这样针对goods寸一条记录,记录着有个字段是 sku_image:
goodsid {[“白色”:“url”],[“金色”:“url”]}

而且Text字段是不对的。应该约定好大小,比如 VARCHAR(1000)
为啥呢?其实每次get都是流量,转换成流量方向想,那就是带宽,大字段如果在高流量高并发的情况下,容易造成查询量太大,会造成网关超过带宽。

有时候登录线上数据库PM后台,忘记了某表的字段,但只知道某表。我是这样干去取代 DESC table_name 或 SHOW CREATE TABLE table_name,SQL 很简单
SELECT * FROM XXX WHERE 1 LIMIT 1;
直接可以看到列名,修改下 WHERE 里面的条件就可以查询你想的查询的。

3.grep 命令

一般日志用过日志中心查询,但是更多情况下,单机下都会跑到服务器上直接找到自己想要的日志相关。
我是这样的,找到某异常XXXException
cat xxx.log grep ‘XXXException’
然后显示该行上下几行内容,使用 -C 参数输出匹配行的前后各4行
cat xxx.log grep ‘XXXException’ -C 4

grep 小命令 详解:传送门
https://linux.cn/article-5453-1.html

4.Maven 骨架工程

来到公司,发现小项目一个接一个地上。说罢就想起前东家的骨架工程。
很简单的就能生成 HelloWorld 项目,XXXarchetype 是我开发的估计工程依赖。生成骨架项目关键代码:
mvn archetype:generate -DgroupId=com.TT -DartifactId=helloworld -DarchetypeGroupId=com.TT -DarchetypeArtifactId=com.TT.XXXarchetype -DarchetypeVersion=0.0.1-SNAPSHOT -DinteractiveMode=false

详细教程,传送门->
http://www.voidcn.com/blog/aosica321/article/p-5764716.html

5.DO BO 互转工具

一般这种都是代码生成器,兼Java配置项。作用于两种业务model的互转:
mapstruct(效率最高)、orika(最快)、dozer(用的多)
详细教程,传送门
http://www.tianshouzhi.com/api/tutorials/mapstruct
http://blog.csdn.net/a258831020/article/details/48247187

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

Posted in Working Skills, 技术

Java Web 工作技巧总结 16.8

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

四时不谢之兰,百节长青之竹,万古不败之石,千秋不变之人。


1. AOP – LOG
项目中,一个请求过来,一个响应回去。

1_thumb3.png

经常我们需要记录请求过来的对应的 类,方法名,请求参数和IP等一些信息,还有响应出去的,如果是 JSON 结果集的话。比如现在一般暴露给前端(前后端分离),或者其他模块基本走 Restful 接口。那怎么优雅的去记录这些东西呢?

beta 1.0
@Path("user/get")
public ListResult<User> getUser(@BeanParam GetUserParam getUserParam){
    LOGGER.info(getUserParam.toString());
    ListResult<User> userList = userService.getUserList(getUserParam);
    LOGGER.info(userList.toString());

    return userList;
}
同样,硬编码加入了两句打印的代码,其实这个没这么简单。可能日志需要输出到日志平台,可能获取IP或者请求来源的一些信息。那怎么升级会优雅呢?Annotation + AOP可能不错哦!
realease 1.0
@Path("user/get")
@ApiAdvice
public ListResult<User> getUser(@BeanParam GetUserParam getUserParam){
 ListResult<User> userList = userService.getUserList(getUserParam);

 return userList;
}

ApiAvice 的实现原理是基于 Spring AOP 和 SPring 自定义注解完成。具体这篇文章写得差不多:http://www.xdemo.org/springmvc-aop-annotation/

 

2. 出、入参封装

上一点说到了,请求入参和响应出参。
入参提供一个 BaseParam,包含了 IP ,请求来源机器,机型等各种。PagerParam 继承 BaseParam 类,增加了分页相关的参数。比如,用户的参数 UserGetPagerParam..
出参提供一个 BaseResult,包含返回码,返回信息及请求 IP等。PlainResult 单个结果集,ListResult 列表结果集,MapResult… 
同样,两者需要实现序列化。序列化的可以看看这个文章 http://www.infoq.com/cn/articles/serialization-and-deserialization
 
3. LIMIT
在处理线上问题的时候,有时候会有脏数据要进行处理。自然 DDL 操作,需要通过审批什么的。这里就不说了。主要在 UPDATE 操作的时候,注意 SQL 的写法。防止一条 SQL 误操作了其他正确的数据,加个 LIMIT 限制语句。例如
UPDATE user SET name = "BYSocket" WHERE name = "Jeff" LIMIT 1.

http://database.51cto.com/art/201005/200401.htm


4.Guava EventBus
Guava EventBus 是基于事件处理机制,是设计模式中的生产消费模式的实现。使用的场景:多半在异步的场景上。但是基于 JVM 内存上实现的,通俗的说是单机模式。需要评估好,这个异步是否是非常快速可以处理完毕。具体使用见
http://www.cnblogs.com/peida/p/EventBus.html

5.GC常用分析命令
这个总结来自有次 FullGC 特别多,OOM 的场景。然后是这样操作分析的:
jps -lvm // 查看JVM进程中的状态,并得知 JVM 的具体配置
jstat -gcutil {pid} 1000 // 每秒钟打印 GC 信息,可以看下 full GC,各种区的 实时信息
jmap -F -heap {pid} // 查看内存对象信息
主要是
jmap -dump:format=b,file=dump.bin {pid} // 导出内存对象 dump 文件

然后分析工具很多,这里用IBM HeapAnalyzer 具体使用看: http://blog.csdn.net/alexbxp/article/details/6756411

JVM 相关也看看

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

Posted in Working Skills, 技术

Java Web dev搭建经验总结

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

回馈分析法使我看到,我对专业技术人员,不管是工程师、会计师还是市场研究人员,都容易从直觉上去理解他们。这令我大感意外。它还使我看到,我其实与那些涉猎广泛的通才没有什么共鸣。

总结下,新Mac电脑的环境搭建及推荐一些老司机的玩具(软件)

一、玩具篇(软件)

1. Google Chrome / Chrome 插件 -Draw.io Desktop 、Postman、FeHelper、Website IP、Isometric Contributions、Octotree、Momentum

Chrome 的 F12 ,调试神器。

Draw.io 我是用来画图的。Postman 测试 Rest API 接口 。FeHelper一个小工具集合体。三个是经常戳戳点击的。

还有 Website IP 显示 IP。Git Hub 两个小工具:Isometric Contributions 纯好看,Octotree 左侧出现代码目录。Momentum 在空的 Tab 加入了赏心悦目的图片。

2. Evernote/为知笔记

印象笔记我喜欢记录生活,记录IDEA,记录。。。。

为知笔记记录代码,记录技术,记录工作相关的。。。

3. Shadowsocks

代理。提供个代理服务器吧

 

server:45.78.48.253
port:4433

password:NWNmNzQ2ZT

4. SwitchHosts

Host修改。很多类似的。

5. IDEA

Java 吃饭的家伙,不多说。

二、环境

1/ zsh 安装

sh -c"$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

2/ JDK 8 安装

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html下载jdk-xxx.dmg。

然后设置 JAVA_HOME 环境变量,vim 文件’~/.zshrc’或’~/.bash_profile’,加入下面代码

 

export JAVA_HOME=`/usr/libexec/java_home -v 1.8`

export PATH=${JAVA_HOME}/bin:$PATH

java -version 验证下。

3/ Git 安装

https://sourceforge.net/projects/git-osx-installer/下载安装即可。

git –version验证下。

4/ Maven 安装

https://maven.apache.org/download.cgi下载 apache-maven-x.x.x-bin.zip。

设置 Maven 环境变量,和 JDK 环境一样,vim 文件’~/.zshrc’或’~/.bash_profile’,加入下面代码

export M2_HOME={Maven解压目录}/apache-maven-x.x.x

export PATH=$PATH:$M2_HOME/bin

mvn -version 验证下

项目一般都是 maven 项目,启动都基本用 maven 插件集成 jetty 启动。所以不涉及到 tomcat jetty这种安装。

5/ mysql 安装

下载 http://rj.baidu.com/soft/detail/25675.html?ald

# 移动解压后的二进制包到安装目录
sudo mv mysql-5.6.24-osx10.9-x86_64 /usr/local/mysql

# 更改 mysql 安装目录所属用户与用户组
cd /usr/local
sudo chown -R root:wheel mysql

sudo bin/mysqld --initialize --user=mysql

cd /usr/local/mysql

# 启动
sudo support-files/mysql.server start

# 重启
sudo support-files/mysql.server restart

# 停止
sudo support-files/mysql.server stop

# 检查 MySQL 运行状态
sudo support-files/mysql.server status

vim 文件’~/.zshrc’或’~/.bash_profile’,加入下面代码:

# MySQL
export PATH=${PATH}:/usr/local/mysql/bin

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

 

Posted in Java, 技术

Code片段 : .properties属性文件操作工具类 & JSON工具类

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!
“贵专” — 泥瓦匠

一、java.util.Properties API & 案例

java.util.Properties 是一个属性集合。常见的api有如下:

  • load(InputStream inStream)  从输入流中读取属性
  • getProperty(String key)  根据key,获取属性值
  • getOrDefault(Object key, V defaultValue) 根据key对象,获取属性值需要强转

首先在resources目录下增加/main/resources/fast.properties:

fast.framework.name=fast
fast.framework.author=bysocket
fast.framework.age=1

然后直接上代码PropertyUtil.java:

/**
 * .properties属性文件操作工具类
 *
 * Created by bysocket on 16/7/19.
 */
public class PropertyUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(PropertyUtil.class);

    /** .properties属性文件名后缀 */
    public static final String PROPERTY_FILE_SUFFIX	= ".properties";

    /**
     * 根据属性文件名,获取属性
     *
     * @param propsFileName
     * @return
     */
    public static Properties getProperties(String propsFileName) {
        if (StringUtils.isEmpty(propsFileName))
            throw new IllegalArgumentException();

        Properties  properties  = new Properties();
        InputStream inputStream = null;

        try {

            try {
                /** 加入文件名后缀 */
                if (propsFileName.lastIndexOf(PROPERTY_FILE_SUFFIX) == -1) {
                    propsFileName += PROPERTY_FILE_SUFFIX;
                }

                inputStream = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(propsFileName);
                if (null != inputStream)
                    properties.load(inputStream);
            } finally {
                if ( null != inputStream) {
                    inputStream.close();
                }
            }

        } catch (IOException e) {
            LOGGER.error("加载属性文件出错!",e);
            throw new RuntimeException(e);
        }

        return properties;
    }

    /**
     * 根据key,获取属性值
     *
     * @param properties
     * @param key
     * @return
     */
    public static String getString(Properties properties, String key){
        return properties.getProperty(key);
    }

    /**
     * 根据key,获取属性值
     *
     * @param properties
     * @param key
     * @param defaultValue
     * @return
     */
    public static String getStringOrDefault(Properties properties, String key, String defaultValue){
        return properties.getProperty(key,defaultValue);
    }

    /**
     * 根据key,获取属性值
     *
     * @param properties
     * @param key
     * @param defaultValue
     * @param <V>
     * @return
     */
    public static <V> V getOrDefault(Properties properties, String key, V defaultValue){
        return (V) properties.getOrDefault(key,defaultValue);
    }
}

UT如下:

/**
 * {@link PropertyUtil} 测试用例
 * <p/>
 * Created by bysocket on 16/7/19.
 */
public class PropertyUtilTest {

    @Test
    public void testGetProperties() {
        Properties properties = PropertyUtil.getProperties("fast");
        String fastFrameworkName = properties.getProperty("fast.framework.name");
        String authorName        = properties.getProperty("fast.framework.author");
        Object age               = properties.getOrDefault("fast.framework.age",10);
        Object defaultVal        = properties.getOrDefault("fast.framework.null",10);
        System.out.println(fastFrameworkName);
        System.out.println(authorName);
        System.out.println(age.toString());
        System.out.println(defaultVal.toString());
    }

    @Test
    public void testGetString() {
        Properties properties = PropertyUtil.getProperties("fast");
        String fastFrameworkName = PropertyUtil.getString(properties,"fast.framework.name");
        String authorName        = PropertyUtil.getString(properties,"fast.framework.author");
        System.out.println(fastFrameworkName);
        System.out.println(authorName);
    }

    @Test
    public void testGetOrDefault() {
        Properties properties = PropertyUtil.getProperties("fast");
        Object age               = PropertyUtil.getOrDefault(properties,"fast.framework.age",10);
        Object defaultVal        = PropertyUtil.getOrDefault(properties,"fast.framework.null",10);
        System.out.println(age.toString());
        System.out.println(defaultVal.toString());
    }
}

Run Console:

1
10
fast
bysocket
1
10
fast
bysocket

相关对应代码分享在 Github 主页


二、JACKSON 案例

首先,加个Maven 依赖:

                


                <!-- Jackson -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.9.13</version>
		</dependency>
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-jaxrs</artifactId>
			<version>1.9.13</version>
		</dependency>

 

然后直接上代码JSONUtil:

/**
 * JSON 工具类
 * <p/>
 * Created by bysocket on 16/7/19.
 */
public class JSONUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(JSONUtil.class);

    /**
     * 默认JSON类
     **/
    private static final ObjectMapper mapper = new ObjectMapper();

    /**
     * 将 Java 对象转换为 JSON 字符串
     *
     * @param object
     * @param <T>
     * @return
     */
    public static <T> String toJSONString(T object) {
        String jsonStr;
        try {
            jsonStr = mapper.writeValueAsString(object);
        } catch (Exception e) {
            LOGGER.error("Java Object Can't covert to JSON String!");
            throw new RuntimeException(e);
        }
        return jsonStr;
    }


    /**
     * 将 JSON 字符串转化为 Java 对象
     *
     * @param json
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T toObject(String json, Class<T> clazz) {
        T object;
        try {
            object = mapper.readValue(json, clazz);
        } catch (Exception e) {
            LOGGER.error("JSON String Can't covert to Java Object!");
            throw new RuntimeException(e);
        }
        return object;
    }

}

UT如下:

/**
 * {@link JSONUtil} 测试用例
 * <p/>
 * Created by bysocket on 16/7/19.
 */
public class JSONUtilTest {

    @Test
    public void testToJSONString() {
        JSONObject jsonObject = new JSONObject(1, "bysocket", 33);
        String jsonStr = JSONUtil.toJSONString(jsonObject);
        Assert.assertEquals("{\"age\":1,\"name\":\"bysocket\",\"id\":33}", jsonStr);
    }

    @Test(expected = RuntimeException.class)
    public void testToJSONStringError() {
        JSONUtil.toJSONString(System.out);
    }

    @Test
    public void testToObject() {
        JSONObject jsonObject = new JSONObject(1, "bysocket", 33);
        String jsonStr = JSONUtil.toJSONString(jsonObject);
        JSONObject resultObject = JSONUtil.toObject(jsonStr, JSONObject.class);
        Assert.assertEquals(jsonObject.toString(), resultObject.toString());
    }

    @Test(expected = RuntimeException.class)
    public void testToObjectError() {
        JSONUtil.toObject("{int:1}", JSONObject.class);
    }
}

class JSONObject {
    int age;
    String name;
    Integer id;

    public JSONObject() {
    }

    public JSONObject(int age, String name, Integer id) {
        this.age = age;
        this.name = name;
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "JSONObject{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}

Run Console(抛出了异常信息):

16/07/19 23:09:13 ERROR util.JSONUtil: JSON String Can't covert to Java Object!
16/07/19 23:09:13 ERROR util.JSONUtil: Java Object Can't covert to JSON String!

三、小结

相关对应代码分享在 Github 主页

请看到的Java小伙伴多交流多评论改进之。

参考 黄勇 smart

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

Posted in Java, 技术

图解微服务架构演进

图解服务化架构演进

许久没摘记了,继续告诫自己:

要静下心来,低调多做事

前言

来自dubbo的用户手册中的一句话:
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

常规的垂直应用架构就相当于传统的那种,现阶段传统垂直架构改造的核心就是对应用做服务化改造,服务话改造使用的核心技术架构就是分布式服务框架。

其实这篇是概念上的总结,技术概念软文,纪录此文让自己更明白什么是微服务化架构。

服务化架构演进

请看下图,也来自dubbo的用户手册,图中恰恰少了微服务架构的图。
image

那什么是微服务架构呢?
先从第一个图中第一个说起吧。

1.orm – 单一应用架构

我认为是一个高内聚版本,所有功能部署在一起。数据访问框架(orm)成为关键。这个架构很少被人使用,几乎接近灭绝了吧。

优点:成本低,适合功能少又简单 缺点:很多,比如无法适应高流量,二次开发难,部署成本高

2.mvc架构 - 垂直应用架构

当访问量渐渐增大,慢慢演化成用的很多的mvc架构。虽然还是所有的功能都是部署在同一个进程中,但是可以通过双机或者前置负载均衡来实现负载分流。这样应用也可以拆分成不同的几个应用,以提升性能和效率。

此时,mvc架构用于分离前后端逻辑。一方面,有一定的模块化。另一方面,加速和方便了开发。

3.rpc架构 - 分布式服务架构

当mvc垂直应用分成不同应用时,越来越多的情况下。不可避免的事应用a与应用b之间的交互。此时将核心和公共的 业务功能抽出来,作为单独的服务,并实现前后端逻辑分离。

此时则就需要提高业务的复用及整合的分布式rpc框架,例如dubbo等。

4.soa架构 - 流动计算架构

当rpc架构中的服务越来越多时,服务的生命周期的管控,容量的评估等各种问题会出现,使服务化成为瓶颈。需要增加一个调度中心来进行对服务管控,监督等。

然后,提到关键的 --

5.微服务架构

问:什么是微服务架构?

答:它就是将功能分散到各个离散的服务中然后实现对方案的解耦。服务更原子,自治更小,然后高密度部署服务。

下面是对微服务架构的图解:

image

小结

伴随敏捷开发,持续交付,DevOps,Docker等高速发展,微服务必然是未来演进方向。加油~ 多了解吧。

Posted in Java, 技术

google collection工具包的MapMaker使用

 

摘自网上描述语段:

Google Collections中的MapMaker融合了Weak Reference线程安全高并发性能异步超时清理自定义构建元素等强大功能于一身。

常阅读优秀源代码的童鞋都知道,一般叫Maker的对象都是Builder模式,而这个MapMaker就是来”Build“Map的.

一、google collection工具包的MapMaker使用:

public static void main(String[] args) {
        /**
         * expiration(3, TimeUnit.SECONDS)设置超时时间为3秒
         */
        ConcurrentMap<String , String> map = new MapMaker().concurrencyLevel(32).softKeys().weakValues()
                .expiration(3, TimeUnit.SECONDS).makeComputingMap(
                        /**
                         * 提供当Map里面不包含所get的项,可以自动加入到Map的功能
                         * 可以将这里的返回值放到对应的key的value中
                         */
                        new Function<String, String>() {
                            public String apply(String s) {
                                return "creating " + s + " -> Object";
                            }
                        }
                );

        map.put("a","testa");
        map.put("b","testb");

        System.out.println(map.get("a"));
        System.out.println(map.get("b"));
        System.out.println(map.get("c"));

        try {
            // 4秒后,大于超时时间,缓存失效。
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(map.get("a"));
        System.out.println(map.get("b"));
        System.out.println(map.get("c"));
    }

结果如下:

testa
testb
creating c -> Object
creating a -> Object
creating b -> Object
creating c -> Object

 

二、先看下其api的相关demo片段:

// 使用案例:存储验证码
    // <String, String> == <用户唯一,验证码>
    // expiration(15, TimeUnit.MINUTES) 有效期15分钟
    ConcurrentMap<String,String> capthcaMap = new MapMaker().expiration(15, TimeUnit.MINUTES).makeMap();

    // 设置ConcurrentMap的concurrencyLevel参数 ,例如ConcurrentHashMap是用来控制其Segment数组的大小
    ConcurrentMap<String,Object> map1 = new MapMaker().concurrencyLevel(8).makeMap();

    // 构造各种不同reference作为key和value的map
    ConcurrentMap<String,Object> map2 = new MapMaker().softKeys().weakValues().makeMap();

    // 提供当Map里面不包含所get的项,可以自动加入到Map的功能
    ConcurrentMap<String,Integer> map3 = new MapMaker()
            .makeComputingMap(
                    new Function<String, Integer>() {
                        public Integer apply(String key) {
                            return 1;
                        }
                    }
            );

可以看出过了4秒后,缓存失效,所以呈现如此结果。

Posted in Java, 技术

五、网站高可用架构

Writer      :BYSocket(泥沙砖瓦浆木匠)

2016年的书 — A Year Of Books


高可用架构

    主要手段:数据和服务的冗余备份及失效转移。

42b04b4f-0228-44e1-b0a0-9a6db3392de2

负载均衡通过心跳检测监控服务器不可用。

其机制,实现服务器可用实时监控,自动转移,心跳检测。利用负载均衡

906507aa-df96-4723-ba5c-fbbd7379d290

Session集群

1.Session复制

78d9fa72-eca3-4345-885e-e6560a254126

2. Session绑定

利用负载均衡的源地址Hash算法实现。

649f979a-b05e-45ee-a0cc-f546637ed0c7

3. 利用Cookie记录Session

3269f531-2bb7-4a15-bc9c-785683dff255

4.Session服务器

667425fb-2216-4704-9e23-39072659f52b