将amr,caf转mp3

需求


公司原有文件存储现在要用java进行重构,其中涉及到Android和ios上的音频问题。

  1. Android录音是格式是amr,在电脑上一般是播放不出来的,必须要进行转码。

  2. iPhone录音传上来的是caf,在android上是不能进行播放的。

由于上面的问题,我们要进行文件的转换,另外还有一个需求就是,amr转wav ,这里我们将amr和caf统一转换为map3,另外提供一个接口进行amr2wav的转换。 在网上参考了许多,总结下来还都是调用ffmpeg 进行想着音频的转换。总也来说比较简单。这里时间的关系 ,也不可能去研究底层编解码的东西。


开工

安装ffmpeg

查看当前ffmpeg对mp3的编解码支持情况

    ffmpeg -codecs|grep mp3                                        

     D.A.L. mp3                  MP3 (MPEG audio layer 3) (decoders: mp3 mp3float )
     D.A.L. mp3adu               ADU (Application Data Unit) MP3 (MPEG audio layer 3) (decoders: mp3adu mp3adufloat )
     D.A.L. mp3on4               MP3onMP4 (decoders: mp3on4 mp3on4float )



     

问题

  • ffmpeg: error while loading shared libraries: libavdevice.so.53: cannot open shared object file: No such file or directory
      ffmpeg正常安装后执行ffmpeg时出现如下错误:

      解决办法:

      vi /etc/ld.so.conf

      加入:/usr/local/lib

      执行ldconfig
  • ffmpeg -i test.amr test.mp3
    ffmpeg: error while loading shared libraries: libavdevice.so.56: cannot open shared object file: No such file or directory

     <http://www.tjcarroll.org/?p=51>

git工作与学习

tag的作用与学习

  • git tag ‘name’ -m ‘desc’ 创建

  • git tag -d ‘name’ 删除

  • git tag -l 查看

  • git push –tags 提交

  • git push origin :refs/tags/tags_name

git 在使用项目中的实践模型

  1. master
  2. release-6.1
  3. develop
  4. hotfix-xxx
  5. release-release-6.1-xx

批量删除tag

git tag |grep -v ‘v7.2.25-log_report_v9-20200909’ | xargs -I {} git tag -d {}

redis致命错误的出现

#错误描述
我们将文件缓存到redis,但是在线上出现了一个问题,就是A企业群中发的文件,在B企业群中看文件时却看到了A企业群中的图片。

#经排查,结果如下:

##案例代码如下:

    import com.google.common.collect.Lists;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;

    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.*;

    /**
     * Created by Aaron on 15/11/12.
     */
    public class FileRedisFactory {
        private static Logger log = LoggerFactory.getLogger(FileRedisFactory.class);
        public ThreadPoolExecutor threadPoolExecutor;
        // 格式为 : 127.0.0.1:6379#0;127.0.0.2:6379#1    IP:PORT#index
        private String hosts;
        private String password;
        private int size;
        private List<JedisPool> pools=Lists.newArrayList();//连接池

        public FileRedisFactory(String hosts, String password) {
            this.hosts = hosts;
            this.password = password;
            this.init(hosts, password);
        }

        public FileRedisFactory(String hosts) {
            this.hosts = hosts;
            this.init(hosts, null);
        }


        private synchronized void init(String hosts, String password) {
            if (StringUtils.isNotEmpty(hosts)) {
                String[] hostsArray = hosts.split(";");
                List<String> hostList = Arrays.asList(hostsArray);
                Collections.sort(hostList);
                System.out.println(hostList);
                for (String host : hostList) {
                    try {
                        String[] uriDb=host.split("#");
                        String[] host_port = uriDb[0].split(":");
                        String ip = host_port[0];
                        String port = host_port[1];
                        int index=uriDb.length>0?Integer.valueOf(uriDb[1]):0;
                        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                        poolConfig.setMaxTotal(16);
                        poolConfig.setMaxIdle(16);
                        if (StringUtils.isNotEmpty(password)) {
                            pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, password, index));
                        } else {
                            pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, null, index));
                        }
                    } catch (Exception e) {
                        pools = Lists.newArrayList();
                        e.printStackTrace();
                        log.error("[ShardedRedisFactory] [initByShard] [error] [hosts:" + hosts + "] [password:" + password + "]", e);
                    }
                }
                size = pools.size();
            }
            this.threadPoolExecutor = new ThreadPoolExecutor(10,20,3, TimeUnit.MINUTES,new LinkedBlockingDeque<>(),new ThreadPoolExecutor.DiscardPolicy());

            // 构造池
            log.info("[ShardedRedisFactory] [initByShard] [success] [hosts:{}] [password:{}] [masterName:{}] [pool:{}]", hosts, password);
        }

        private JedisPool getJedisPool(int c) {
            int index = c % size;
            return pools.get(index);
        }

        private static int getIndexFromPath(String path) {
            String first=path.split("\\.")[0];
            return  first.charAt(first.length() - 1);
        }

        /**
         * @param filePath file path
         * @return
         */
        public byte[] get(String filePath) {
            if (cacheIsAvailable()) return null;
            JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                return jedis.get(filePath.getBytes());
            } catch (Exception e) {
                log.error(e.getMessage());
                return null;
            } finally {
                if (jedis != null)
                    jedisPool.returnResource(jedis);
            }
        }

        public void asynSet(String filePath, byte[] datas){
            if (cacheIsAvailable()) return;
            threadPoolExecutor.execute(()->{
                    JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
                    Jedis jedis = null;
                    try {
                        jedis = jedisPool.getResource();
                        jedis.set(filePath.getBytes(), datas);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    } finally {
                        if (jedis != null)
                            jedisPool.returnResource(jedis);
                    }
            });
        }
        private boolean cacheIsAvailable() {
            if(pools.size()==0){
                return true;
            }
            return false;
        }

    }

##测试代码如下

        public static void main(String[] args) {
            FileRedisFactory fileRedisFactory = new FileRedisFactory("172.31.xxx.xxx:6379#0;172.31.xx.xxx:6379#1;172.31.xxx.xxx:6379#2;172.31.xxx.xxx:6379#3");
            System.out.println(fileRedisFactory);
            Map<String,String> map=new HashMap<>();

            for(int i=0;i<20;i++){
                map.put(""+i,""+i);
            }

            for (int j = 0; j <50 ; j++) {
                Thread thread=new Thread(){
                    @Override
                    public void run() {
                        while(true){
                            Set<String> s=map.keySet();

                            s.forEach(i->{
                                fileRedisFactory.set(i + "", (i + "").getBytes());
                            });
                        }
                    }
                };
                thread.start();
            }
            for (int k = 0; k <50 ; k++) {
                Thread thread=new Thread(){
                    @Override
                    public void run() {
                        while(true){
                            Set<String> s=map.keySet();
                            s.forEach(i->{
                                byte[] first=fileRedisFactory.get(i+"");
                                if(first==null){
                                    System.out.println(i+""+first);
                                    return;
                                }
                                try{
                                String temp=(new String(first));
                                if(!temp.equals(i+"")){
                                    System.out.println(i+"======"+temp);
                                    System.exit(-1);
                                }}catch(Exception e){
                                    e.printStackTrace();
                                }
                            });
                        }
                    }
                };
                thread.start();
            }
        }

若你和连接到redis服务器之间的网络不是很稳定
在运行时,我们会发现,有奇怪的现像出现:

    1======2
    3======8

这时,我们就在对redis操作时,异常的地方修改成如下代码:

    catch (Exception e) {
          log.error(e.getMessage());
          e.printStackTrace();
          return null;
    } 

就会看到报TimeOut的Exception

我们将:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.6.2</version>
        </dependency>

替换成:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.3</version>
        </dependency>

这时我们去Google上查询的同时也看了一下新的代码,
我们原来用的:

    jedisPool.returnResource(jedis);

 已经变成了:


   /**
    * @deprecated starting from Jedis 3.0 this method won't exist. Resouce cleanup should be done
    *             using @see {@link redis.clients.jedis.Jedis#close()}
    */
   @Deprecated
   public void returnResource(final Jedis resource) {
     if (resource != null) {
       try {
         resource.resetState();
         returnResourceObject(resource);
       } catch (Exception e) {
         returnBrokenResource(resource);
         throw new JedisException("Could not return the resource to the pool", e);
       }
     }
   }

同时我们也查到了一个文章JedisPool异常Jedis链接处理

#修改后的代码:

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;

/**
 * Created by Aaron on 15/11/12.
 */
public class FileRedisFactory {
    private static Logger log = LoggerFactory.getLogger(FileRedisFactory.class);
    public ThreadPoolExecutor threadPoolExecutor;
    // 格式为 : 127.0.0.1:6379#0;127.0.0.2:6379#1    IP:PORT#index
    private String hosts;
    private String password;
    private int size;
    private List<JedisPool> pools=Lists.newArrayList();//连接池

    public FileRedisFactory(String hosts, String password) {
        this.hosts = hosts;
        this.password = password;
        this.init(hosts, password);
    }

    public FileRedisFactory(String hosts) {
        this.hosts = hosts;
        this.init(hosts, null);
    }


    private synchronized void init(String hosts, String password) {
        if (StringUtils.isNotEmpty(hosts)) {
            String[] hostsArray = hosts.split(";");
            List<String> hostList = Arrays.asList(hostsArray);
            Collections.sort(hostList);
            System.out.println(hostList);
            for (String host : hostList) {
                try {
                    String[] uriDb=host.split("#");
                    String[] host_port = uriDb[0].split(":");
                    String ip = host_port[0];
                    String port = host_port[1];
                    int index=uriDb.length>0?Integer.valueOf(uriDb[1]):0;
                    GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                    poolConfig.setMaxTotal(16);
                    poolConfig.setMaxIdle(16);
                    if (StringUtils.isNotEmpty(password)) {
                        pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, password, index));
                    } else {
                        pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, null, index));
                    }
                } catch (Exception e) {
                    pools = Lists.newArrayList();
                    log.error("[ShardedRedisFactory] [initByShard] [error] [hosts:" + hosts + "] [password:" + password + "]", e);
                }
            }
            size = pools.size();
        }

        this.threadPoolExecutor = new ThreadPoolExecutor(10,20,3, TimeUnit.MINUTES,new LinkedBlockingDeque<>(50),new ThreadPoolExecutor.DiscardPolicy());

        // 构造池
        log.info("[ShardedRedisFactory] [initByShard] [success] [hosts:{}] [password:{}] [masterName:{}] [pool:{}]", hosts, password);
    }

    private JedisPool getJedisPool(int c) {
        int index = c % size;
        return pools.get(index);
    }

    private static int getIndexFromPath(String path) {
        String first=path.split("\\.")[0];
        return  first.charAt(first.length() - 1);
    }

    /**
     * @param filePath file path
     * @return
     */
    public byte[] get(String filePath) {
        if (cacheIsAvailable()) return null;
        JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.get(filePath.getBytes());
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (jedis != null)
                jedis.close();
        }
    }

    public String set(String filePath, byte[] datas) {
        if (cacheIsAvailable()) return null;
        JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.set(filePath.getBytes(), datas);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (jedis != null)
                jedis.close();
        }
    }

    public void asynSet(String filePath, byte[] datas,long expx){
        if (cacheIsAvailable()) return;
        threadPoolExecutor.execute(()->{
                JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
                Jedis jedis = null;
                try {
                    jedis = jedisPool.getResource();
                    jedis.set(filePath.getBytes(), datas,"NX".getBytes(),"EX".getBytes(),expx);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    if (jedis != null)
                        jedis.close();
                }
        });
    }
    private boolean cacheIsAvailable() {
        if(pools.size()==0){
            return true;
        }
        return false;
    }

}

#总结:

  1. 在使用做新功能时,方便时要添加开关或合理的回滚方案,方便快速的回滚减少事故的影响
  2. 排查错误,一查到底

JMeter

##JMeter是用来做什么的

是一个Apache的一个开源程序,一个100%的针对压力模块和功能压力测试纯Java应用,最初是专门为Web应用程序而设计 的,但是目前已经扩展到别的功能 测试。

  • 能做什么?

    用来测试动态 和 静态资源(Webservices(SOAP/REST),Web dynamic languages -PHP,JAva,ASP.NET,Files,etc.Jav)

##如何本地进行服务压力测试

  • 在lib下建一个文件夹,如tests,将所有自己用到的jar,放到这个文件夹中。

  • 将自己的测试jar放到 lib/ext下面

  • 将自己的程序依赖的jar文件夹,配置到配置文件
    user.classpath=../lib/tests

##如何分发到不同的机器进行压力测试

参考官方文档http://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf

##聚合分析

Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,这里显示的就是 Name 属性的值

#Samples:表示你这次测试中一共发出了多少个请求,如果模拟10个用户,每个用户迭代10次,那么这里显示100

Average:平均响应时间——默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以Transaction 为单位显示平均响应时间

Median:中位数,也就是 50% 用户的响应时间

90% Line:90% 用户的响应时间

Note:关于 50% 和 90% 并发用户数的含义,请参考下文

http://www.cnblogs.com/jackei/archive/2006/11/11/557972.html

Min:最小响应时间

Max:最大响应时间

Error%:本次测试中出现错误的请求的数量/请求的总数

Throughput:吞吐量——默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似 LoadRunner 的 Transaction per Second 数

KB/Sec:每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec

###问题

####Jmeter-server启动失败:Cannot start. Unable to get local host IP address. is a loopback address

    在Windows下启动Jmeter非常顺利,转到Linux下居然启动失败。
    想起之前 遇到“/etc/hosts文件设置不对导致Jboss启动失败”, 立马把焦点指向/etc/hosts。

    果然还是这个问题,贴/etc/hosts示例:

    127.0.0.1       localhost.localdomain localhost
    10.20.10.31   higkoo.rdev.company.net higkoo

    执行命令`hostname`查看当前机器名如果当前机器名与/etc/hosts不一致 ,可手动先执行成一次`hostname yourhostname`或直接加到jmeter-server文件中(注意机器名中不要含域信息,譬如:myname.rdev.company.com。这样设置仍然启动失败)。

    由/etc/hosts文件导致启动失败的错误有:
    1
    Created remote object: UnicastServerRef [liveRef: [endpoint:[10.20.10.31:62090](local),objID:[2c639f6d:12794fca52a:-7fff, 712947915258586677]]]
    Server failed to start: java.rmi.RemoteException: Cannot start. higkoo is a loopback address.
    2
    Created remote object: UnicastServerRef [liveRef: [endpoint:[10.20.10.31:38796](local),objID:[-b0d822e:12794fee8b1:-7fff, 8314597152635832475]]]
    Server failed to start: java.rmi.RemoteException: Cannot start. Unable to get local host IP address.

zookeeper学习及项目实践

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. 。

它设计一种新的数据结构——Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。

使用场景下会使用zookeeper

  1. 项目中在监控mongodb的oplog来进行同步数据库的变更给别的部门.若想做的多机互备,就需要使用到分布式锁,由一台机器进行对oplog的变化进行同步
  2. 项目在定时发送提醒,多台服务器进行周期扫库操作,也同样用到了1中的分布式锁
  3. 假设我们有20个搜索引擎的服务器(每个负责总索引中的一部分的搜索任务)和一个总服务器(负责向这20个搜索引擎的服务器发出搜索请求并合并结果集),一个备用的总服务器(负责当总服务器宕机时替换总服务器),一个web的cgi(向总服务器发出搜索请求)。搜索引擎的服务器中的15个服务器提供搜索服务,5个服务器正在生成索引。这20个搜索引擎的服务器经常要让正在提供搜索服务的服务器停止提供服务开始生成索引,或生成索引的服务器已经把索引生成完成可以提供搜索服务了。使用Zookeeper可以保证总服务器自动感知有多少提供搜索引擎的服务器并向这些服务器发出搜索请求,当总服务器宕机时自动启用备用的总服务器.—分布式系统协调 ZooKeeper

zookeeper来源是什么?

ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等。

协议

  1. 每个Server在内存中存储了一份数据;
  2. Zookeeper启动时,将从实例中选举一个leader(Leader选举算法采用了Paxos协议;Paxos核心思想:当多数Server写成功,则任务数据写成功。故 Server数目一般为奇数);
  3. Leader负责处理数据更新等操作(Zab协议);
  4. 一个更新操作成功,当且仅当大多数Server在内存中成功修改数据。

结构组成

  1. Leader 负责进行投票的发起和决议,更新系统状态
  2. Learner–>跟随者Follower 用于接收客户请求并向客户端返回结果,在选择中参与投票
  3. Learner–>观察者Observer 可以接收客户端连接,将写请求转发给Leader节点,但其不参悟投票过程,只同步Leader的状态.其目的是为了扩展系统,提高读取速度
  4. client 请求发起方

具体用在哪里

  1. 配置管理,一处修改,监听者进行更新
  2. 命名服务
  3. 分布式锁 即 Leader Election
  4. 集群管理
  5. 队列管理

Zookeeper文件系统

每个子目录项如 NameService 都被称作为znode,和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。
有四种类型的znode:

  1. PERSISTENT-持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在
  2. PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
  3. EPHEMERAL-临时目录节点:客户端与zookeeper断开连接后,该节点被删除
  4. EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

Zookeeper的特点

  1. 最终一致性:为客户端展示同一视图,这是zookeeper最重要的功能。
  2. 可靠性:如果消息被到一台服务器接受,那么它将被所有的服务器接受。
  3. 实时性:Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
  4. 等待无关(wait-free):慢的或者失效的client不干预快速的client的请求。
  5. 原子性:更新只能成功或者失败,没有中间状态。
  6. 顺序性:所有Server,同一消息发布顺序一致。

场景分析

  1. 分布式锁的场景使用
zkCli.sh -server x.x.x.x:4180

ls /key

>[data, leader]

[zk: x.x.x.x:4180(CONNECTED) 6] get /key/leader

cZxid = 0xc1098cd0b0
ctime = Sun Jul 16 13:10:01 CST 2017
mZxid = 0xc1098cd0b0
mtime = Sun Jul 16 13:10:01 CST 2017
pZxid = 0xc112aec1c0
cversion = 152
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2

[zk: x.x.x.x:4180(CONNECTED) 7] ls /key/leader
[_c_7ea9234d-3973-4e1d-8a6a-e2e30062cdc4-latch-0000000076, _c_5444e12a-c7ef-48bb-8ee6-271eea4a1c29-latch-0000000075]
[zk: x.x.x.x:4180(CONNECTED) 8] get /key/leader/_c_7ea9234d-3973-4e1d-8a6a-e2e30062cdc4-latch-0000000076
24
cZxid = 0xc112aec1c0
ctime = Fri Mar 30 16:58:50 CST 2018
mZxid = 0xc112aec1c0
mtime = Fri Mar 30 16:58:50 CST 2018
pZxid = 0xc112aec1c0
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0xd5848ddc5ec71f6
dataLength = 2
numChildren = 0

[zk: x.x.x.x:4180(CONNECTED) 9] get /key/leader/_c_5444e12a-c7ef-48bb-8ee6-271eea4a1c29-latch-0000000075
5
cZxid = 0xc1123e0f90
ctime = Tue Mar 27 10:55:03 CST 2018
mZxid = 0xc1123e0f90
mtime = Tue Mar 27 10:55:03 CST 2018
pZxid = 0xc1123e0f90
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x259977a5b1b3de0
dataLength = 1
numChildren = 0


经典文章链接

zookeeper系列
Leader选举
基本概念

Protobuf是什么

欢迎来到protocol buffer的开发者指南文档,一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据串行化方法。本文档面向希望使用protocol buffer的Java、C++或Python开发者。这个概览介绍了protocol buffer,并告诉你如何开始,你随后可以跟随编程指导深入了解protocol buffer编码方式API参考文档同样也是提供了这三种编程语言的版本,不够协议语言样式指导都是编写 .proto 文件。

什么是protocol buffer

ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。

他们如何工作

你首先需要在一个 .proto 文件中定义你需要做串行化的数据结构信息。每个ProtocolBuffer信息是一小段逻辑记录,包含一系列的键值对。这里有个非常简单的 .proto 文件定义了个人信息:


message Person {
required string name=1;
required int32 id=2;
optional string email=3;

enum PhoneType {
MOBILE=0;
HOME=1;
WORK=2;
}

message PhoneNumber {
required string number=1;
optional PhoneType type=2 [default=HOME];
}

repeated PhoneNumber phone=4;
}

有如你所见,消息格式很简单,每个消息类型拥有一个或多个特定的数字字段,每个字段拥有一个名字和一个值类型。值类型可以是数字(整数或浮点)、布尔型、字符串、原始字节或者其他ProtocolBuffer类型,还允许数据结构的分级。你可以指定可选字段,必选字段和重复字段。你可以在proto.html找到更多关于如何编写 .proto 文件的信息。

一旦你定义了自己的报文格式(message),你就可以运行ProtocolBuffer编译器,将你的 .proto 文件编译成特定语言的类。

为什么不用XML?

ProtocolBuffer拥有多项比XML更高级的串行化结构数据的特性,ProtocolBuffer:

    更简单
    小3-10倍
    快20-100倍
    更少的歧义
    可以方便的生成数据存取类 

例如,让我们看看如何在XML中建模Person的name和email字段:


<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>

对应的ProtocolBuffer报文则如下:

ProtocolBuffer的文本表示
这不是正常时使用的二进制数据

person {
name: "John Doe"
email: "jdoe@example.com"
}

当这个报文编码到ProtocolBuffer的二进制格式时(上面的文本仅用于调试和编辑),它只需要28字节和100-200ns的解析时间。而XML的版本需要69字节(除去空白)和 5000-10000ns的解析时间。

设计模式之创建型模式

##创建型模式
这六个模式都是与创建对象相关的

  • 简单工厂模式(Simple Factory);
  • 工厂方法模式(Factory Method);
  • 抽象工厂模式(Abstract Factory);
  • 创建者模式(Builder);
  • 原型模式(Prototype);
  • 单例模式(Singleton);

简单工厂模式(Simple Factory);

工厂方法模式(Factory Method);

建立一个工厂类,对实现同一接口的类进行实例化创建。

``
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public interface IParser {
String parse(Object obj);
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class JSONParser implements IParser{
@Override
public String parse(Object obj) {
//create json string
return "{class:"+obj.getClass()+"}";
}
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class XMLParser implements IParser{
@Override
public String parse(Object obj) {
//create xml string....
return "<object><class>"+obj.getClass()+"</class></object>";
}
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class ParserFactory {
public static final String TYPE_XML="xml";
public static final String TYPE_JSON="json";
public static IParser buildParser(String type){
switch (type){
case ParserFactory.TYPE_XML:return new XMLParser();
case ParserFactory.TYPE_JSON:return new JSONParser();
}
return null;
}

public static void main(String[] args){
IParser parser= ParserFactory.buildParser(ParserFactory.TYPE_JSON);
System.out.print(parser.parse(parser));
}
}

//output {class:JSONParser}

抽象工厂模式(Abstract Factory);

工厂方法,每创建一个新的类时,就要个性类工厂类,这样拓展性比较差,如何能通过不个性工厂类而进行扩展呢。这里就用到了抽象工厂模式,就是创建多个工厂,一旦要增加新的类型就增加一个新的工厂,不需要修改现有代码。

基于上面代码将ParserFactory工厂类用一个抽象工厂类和两个子工厂类进行代替
package design.pattern.abstractfactory;

import design.pattern.factory.*;

/**
* Created by Aaron on 15/9/13.
*/
public abstract class AbstractParserFactory {
abstract IParser create();
}

package design.pattern.abstractfactory;

/**
* Created by Aaron on 15/9/13.
*/
public class JSONParserFactory extends AbstractParserFactory {
@Override
IParser create() {
return new JSONParser();
}
}

package design.pattern.abstractfactory;

/**
* Created by Aaron on 15/9/13.
*/
public class XMLParserFactory extends AbstractParserFactory {
@Override
IParser create() {
return new XMLParser();
}
}

建造者模式(Builder);

GoF这样定义:

建造者模式:是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

咱们这里以创建应用为例,这里我们创建两个应用,考试系统和CRM系统,创建过程是,需求->原型图->开发计划->表设计->架构设计->功能实现->测试->交付 大概是这样一个简单的过程,这里就会看到同样的构建过程得到不同的表示。
package design.pattern.builder;

import java.util.Vector;

/**
* Created by Aaron on 15/9/13.
*/
public class Project {

private Vector<String> impleProcess=new Vector<String>();
public void process(String imple){
impleProcess.add(imple);
}
public Vector<String> getImpleProcess() {
return impleProcess;
}

}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public interface IProjectBuilder {
Project getProject();
void makeRequirement();

void makePrototype();

void makeScheduler();

void makeTables();

void makeAppFrameWork();

void programming();

void test();

void delivery();
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class ExamProjectBuilder implements IProjectBuilder {
private Project project;

public ExamProjectBuilder() {
this.project = new Project();
}

public Project getProject() {
return project;
}

@Override
public void makeRequirement() {
this.project.process("创建考试系统需求");

}

@Override
public void makePrototype() {
this.project.process("创建考试原型");
}

@Override
public void makeScheduler() {
this.project.process("创建考试计划");
}

@Override
public void makeTables() {
this.project.process("创建考试系统表");
}

@Override
public void makeAppFrameWork() {
this.project.process("创建考试应用架构");
}

@Override
public void programming() {
this.project.process("考试应用代码实现");
}

@Override
public void test() {
this.project.process("测试考试应用");
}

@Override
public void delivery() {
this.project.process("交付考试应用");
}
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class CRMProjectBuilder implements IProjectBuilder {
public CRMProjectBuilder() {
this.project = new Project();
}

public Project getProject() {
return project;
}

private Project project;

@Override
public void makeRequirement() {
this.project.process("创建CRM系统需求");
}

@Override
public void makePrototype() {
this.project.process("创建CRM原型");
}

@Override
public void makeScheduler() {
this.project.process("创建CRM计划");
}

@Override
public void makeTables() {
this.project.process("创建CRM系统表");
}

@Override
public void makeAppFrameWork() {
this.project.process("创建CRM应用架构");
}

@Override
public void programming() {
this.project.process("CRM应用代码实现");
}

@Override
public void test() {
this.project.process("测试CRM应用");
}

@Override
public void delivery() {
this.project.process("交付CRM应用");
}
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class Director {
private IProjectBuilder builder;
public Director(IProjectBuilder builder){
this.builder=builder;
}
public Project process(){
this.builder.makeRequirement();
this.builder.makePrototype();
this.builder.makeScheduler();
this.builder.makeAppFrameWork();
this.builder.makeTables();
this.builder.programming();
this.builder.test();
this.builder.delivery();
return builder.getProject();
}

public static void main(String[] args){
Director director = new Director(new CRMProjectBuilder());
Project project = director.process();
System.out.println(project.getImpleProcess());
}
}

//输出 [创建CRM系统需求, 创建CRM原型, 创建CRM计划, 创建CRM应用架构, 创建CRM系统表, CRM应用代码实现, 测试CRM应用, 交付CRM应用]

原型模式(Prototype);

GoF这样定义:

用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

package design.pattern.prototype;

import java.io.*;
import java.util.Vector;

/**
* Created by Aaron on 15/9/13.
*/
public class DeepClonePrototype implements Cloneable,Serializable {
public Vector<String> attrs=new Vector<String>();

public Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}

public static void main(String[] args) throws Exception{
Object pro=new DeepClonePrototype().deepClone();
System.out.println(pro.getClass());
}

}

单例模式(Singleton);

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

package design.pattern.singleton;

/**
* Created by Aaron on 15/9/11.
*/
public class Singleton {
private Singleton() {

}

private static Singleton instance = null;

private static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
return instance = new Singleton();
} else {
return instance;
}
}
} else {
return instance;
}
}

public String getName() {
return Singleton.class.getName();
}

public static void main(String args[]) {
Singleton instance = Singleton.getInstance();
System.out.print(instance.getName());
}

}

设计模式之结构型模式

##结构型模式

描述在面向对象设计中,类和对象的几种结构关系,设计好了会为后续代码的维护带来很大的方便。

  • 外观模式(Facade);
  • 适配器模式(Adapter);
  • 代理模式(Proxy);
  • 装饰模式(Decorator);
  • 桥模式(Bridge);
  • 组合模式(Composite);
  • 享元模式(Flyweight);

###外观模式(Facade)又称门面模式;
GoF这样定义:

为子系统中的一组接口提供一个一致的界面, Facade 模式定义了一个高层 接口,这个接口使得这一子系统更加容易使用。

外观模式,在我理解就是给一组对象提供一个对外统计的操作方式 ,让外部使用者不用操心内部工作。如一个汽车,一个电脑,你点开机,硬盘,CPU,内存,显卡就都开始工作了,关机时也一样。这里对我们操作者来说其实就是一个开关。

``
package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args)throws InterruptedException{
Computer computer=new Computer();
computer.startup();
System.out.println("--------shutdown-----------");
computer.shutdown();
}
}

package design.pattern.facade;
/**
* Created by Aaron on 15/9/14.
*/
public class Computer {
private CPU cpu;
private Memory memory;
private GraphicsCard graphicsCard;
private Disk disk;

public Computer() {
this.cpu = new CPU();
this.memory = new Memory();
this.graphicsCard = new GraphicsCard();
this.disk = new Disk();
}

public void startup(){
this.cpu.startup();
this.memory.startup();
this.disk.startup();
this.graphicsCard.startup();
}
public void shutdown(){
this.graphicsCard.shutdown();
this.disk.shutdown();
this.memory.shutdown();
this.cpu.shutdown();
}



}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class CPU {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class Disk {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class GraphicsCard {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class Memory {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

输出结果:

CPU启动
Memory启动
Disk启动
GraphicsCard启动
--------shutdown-----------
GraphicsCard关闭
Disk关闭
Memory关闭
CPU关闭

###适配器模式(Adapter);
GoF这样定义:

将一个类的接口转换成客户希望的另外一个接口。 Adapter 模式使得原本 由于接口不兼容而不能一起工作的那些类可以一起工作。

我的事例理解:如咱们家中常用的洗衣机,当我们要与我们的水龙头进行对接时,中间要借助一个中间者“转换头”,它在这里就起到了适配作用。

``
package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public class WashingMachine {
public void connectPort(IWashFaucetAdapter washportadapter){
System.out.print(washportadapter.outToWashingPort()+" success!");
}
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public interface IWashFaucetAdapter {
String outToWashingPort();
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public class WashingFaucetAdapter extends Faucet implements IWashFaucetAdapter{

public String outToWashingPort(){
return "transform"+this.port()+" to washing port!";
}
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
* 水龙头
*/

public class Faucet {
public String port(){
System.out.print("facucet port .....");
return "facucet port";
}
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
// 创建水龙头、洗衣机、镶接头
WashingMachine washingMachine=new WashingMachine();
WashingFaucetAdapter washingFaucetAdapter= new WashingFaucetAdapter();
// 进行适配
washingMachine.connectPort(washingFaucetAdapter);

}
}

输出结果:

facucet port .....transformfacucet port to washing port! success!

###代理模式(Proxy);
GoF这样定义:

为其他对象提供一个代理以控制对这个对象的访问。

这里就以找工作为例吧,现在我们找工作都会通过找工作平台来进行找工作,因为他们有资源,他们比较专业。我们告诉他们要找什么样的工作他们就会给我们推荐什么样的工作,在这个环节中,类似51job,100offer这样的平台就是所谓的招聘代理。
他代理公司进行招人。同时也方便了我们去找工作。

下面是代码实现:

package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public interface IRecruitment {
void recruitment(String user);
}

package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public class FounderWork implements IRecruitment{
public void recruitment(String user){
System.out.println(this.getClass().getSimpleName()+"招聘员工"+user+"成功!");
}
}

package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public class WorkProxy implements IRecruitment {
private IRecruitment recruitment;

public WorkProxy() {
this.recruitment = new FounderWork();
}

@Override
public void recruitment(String user) {
before();
this.recruitment.recruitment(user);
after();
}

public void before() {
System.out.println(this.getClass().getSimpleName() + "进行招聘前工作准备!");
}

public void after() {
System.out.println(this.getClass().getSimpleName() + "进行招聘完成后工作收尾!");
}

}


package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
new WorkProxy().recruitment("Aaron");
}
}

输出:

WorkProxy进行招聘前工作准备!
FounderWork招聘员工Aaron成功!
WorkProxy进行招聘完成后工作收尾!

###装饰模式(Decorator);
GoF这样定义:

动态地给一个对象添加一些额外的职责。就扩展功能而言, Decorator 模 式比生成子类方式更为灵活。

我们可以拿我们的扩音器为例,假如一个mp3的有声音,那么它的声音不是很大,稍微远一点我们就不能听到了,这里就会用一个扩音器,放在mp3旁边,离稍微远点也能享受音乐的快乐了。

这里,扩音器就是装饰器,他使mp3的声音变大。有时扩音器也可以改变声音的音质,变的更好听。

下面是代码实现:

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public interface ISoundable {
void sound();
}

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public class MP3 implements ISoundable{
public void sound(){
System.out.println("small sound from mp3!");
}
}

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public class SoundDecorator implements ISoundable {
private ISoundable soundable;

public SoundDecorator(ISoundable soundable) {
this.soundable = soundable;
}

public void sound(){
this.soundable.sound();
System.out.println("make sound beautiful");
System.out.println("make sound aloud ");
}
}

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
new SoundDecorator(new MP3()).sound();
}
}

输出:

small sound from mp3!
make sound beautiful
make sound aloud 

###桥接模式(Bridge);
GoF这样定义:

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

这里还举一个生活中常用到的例子,洗衣机有多种,但我们当我们没有接到水龙头上的管子时,我们可以去商店里买,这里可能会有大小长短各不相同的管子,但都可以与我们的洗衣机相连接进行使用。

这里我们变化的是多种洗衣机和多种管子,我们为洗衣机做一个抽像类。可以设置不同的管子。

``
package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public interface IPip {
String color();
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
* 水龙头
*/

public class RedPip implements IPip{
public String color(){
return "Red";
}
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
* 水龙头
*/

public class BluePip implements IPip{
public String color(){
return "blue pip";
}
}


package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public abstract class AbstractWashingMachine {
private IPip pip;

public IPip getPip() {
return pip;
}

public void setPip(IPip pip) {
this.pip = pip;
System.out.println(this.getClass().getSimpleName()+" set "+pip.color()+" "+pip.getClass().getSimpleName());
}
}


package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public class ChinaWashingMachine extends AbstractWashingMachine {
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public class HaierWashingMachine extends AbstractWashingMachine {
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
new HaierWashingMachine().setPip(new BluePip());
new HaierWashingMachine().setPip(new RedPip());
new ChinaWashingMachine().setPip(new BluePip());
}
}

输出:

HaierWashingMachine set blue pip BluePip
HaierWashingMachine set Red RedPip
ChinaWashingMachine set blue pip BluePip

###组合模式(Composite);
GoF这样定义:

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使 得客户对单个对象和复合对象的使用具有一致性。

这里我们最常见的就是公司与部门的关系,其实就是整体与部分的关系。

代码

package design.pattern.composite;

import java.util.Vector;

/**
* Created by Aaron on 15/9/14.
*/
public abstract class AbstractCompany {
private String name;
private Vector<AbstractCompany> companys=new Vector<AbstractCompany>();
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
public void display(int deep) {
StringBuilder sb=new StringBuilder();
for(int i=0;i<deep;i++){
sb.append("\t");
}
sb.append(this.getName());
System.out.println(sb.toString());
int l = this.getCompanys().size();
if (l > 0) {
for (int i = 0; i < l; i++) {
this.getCompanys().get(i).display(deep+2);
}
}
}
public Vector<AbstractCompany> getCompanys() {
return companys;
}
public void removeCompany(AbstractCompany company){
this.companys.remove(company);
}
public void addCompany(AbstractCompany company) {
this.companys.add(company);
}
}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class Company extends AbstractCompany {
public Company(String name) {
this.setName(name);
}

}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class TechDepartment extends AbstractCompany {
public TechDepartment() {
}
public TechDepartment(String name) {
this.setName(name);
}
}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class UIDepartment extends AbstractCompany {
public UIDepartment(String name) {
this.setName(name);
}

public UIDepartment() {
}
}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class CEO {
public static void main(String[] args) {
AbstractCompany company = new Company("总公司");
AbstractCompany abc = new TechDepartment("技术一部");
company.addCompany(abc);
abc = new TechDepartment("技术二部");
company.addCompany(abc);
abc = new TechDepartment("技术三部");
company.addCompany(abc);
abc = new UIDepartment("UI一部");
company.addCompany(abc);
abc = new UIDepartment("UI二部");
company.addCompany(abc);
abc = new UIDepartment("UI三部");
company.addCompany(abc);
AbstractCompany abc1 = new UIDepartment("UI一组");
abc.addCompany(abc1);
abc1 = new UIDepartment("UI二组");
abc.addCompany(abc1);
abc1 = new UIDepartment("UI三组");
abc.addCompany(abc1);
company.display(0);
}
}


输出:

总公司
        技术一部
        技术二部
        技术三部
        UI一部
        UI二部
        UI三部
                UI一组
                UI二组
                UI三组

###享元模式(Flyweight)
GoF这样定义:

运用共享技术有效地支持大量细粒度的对象。

咱们这里会想到数据库连接池,对,就是它,咱们先看一下类图。

`示例代码如下:`
package design.pattern.flayweight;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

/**
* Created by Aaron on 15/9/14.
*/
public class ConnectionPool {
private Vector<Connection> pool;
private static ConnectionPool instance;
private int poolSize=10;
private String url = "jdbc:mysql://127.0.0.1:3306/mysql";
private String username = "root";
private String password = "root";
private String driverClassName = "com.mysql.jdbc.Driver";
private ConnectionPool(){
this.pool=new Vector<Connection>();

for (int i = 0; i < poolSize; i++) {
try {
Class.forName(driverClassName);
pool.add(DriverManager.getConnection(url, username, password));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

public static synchronized ConnectionPool getInstance(){
if(instance==null){
return instance=new ConnectionPool();
}
return instance;
}

public synchronized Connection getConnection(){
Connection connection=null;
if(pool.size()>0){
connection=pool.get(0);
pool.remove(connection);
}
return connection;
}

public synchronized void release(Connection conn){
pool.add(0,conn);
}

}

package design.pattern.flayweight;

import java.sql.Connection;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String args[]){
ConnectionPool pool=ConnectionPool.getInstance();
Connection connection=pool.getConnection();
System.out.println(connection);
connection=pool.getConnection();
System.out.println(connection);
pool.release(connection);
connection=pool.getConnection();
System.out.println(connection);
}
}


输出:

com.mysql.jdbc.JDBC4Connection@2d8e6db6
com.mysql.jdbc.JDBC4Connection@23ab930d
com.mysql.jdbc.JDBC4Connection@23ab930d