RocketMQ学习(二):依赖关系和模块功能介绍

现在看的代码版本还是3.2.2 develop。先看张内部结构代码图:

rocketmq内部依赖图

从依赖层次再来看,越是被依赖的,越在底层:

层次结构

rocketmq包含9个子模块:

继续阅读

发表在 编程语言 | 标签为 , | Comments Off on RocketMQ学习(二):依赖关系和模块功能介绍

Netty5源码学习之buffer篇(一):PooledHeapByteBuf

PooledHeapByteBuf,带有池的堆内buffer,顾名思义,肯定比一般通过new出来的buffer性能好。把对象放入对象池缓存起来,一般都是因为创建该对象开销比较大,常见的有线程池(ThreadPool)、连接池(ConnectionPool)等。

PooledHeapByteBuf继承关系如下:
PooledHeapByteBuf –》 PooledByteBuf –》 AbstractReferenceCountedByteBuf –》 AbstractByteBuf –》 ByteBuf。
继承关系比较简单清晰。

先介绍几个相关的类:

PooledByteBufAllocator:buffer分配器,用来分配buffer(包括堆内和堆外)。

PoolArena:一块逻辑上的内存池,用来管理和组织buffer的,内部数据结构较复杂。

FastThreadLocal:较快的ThreadLocal(相对于jdk自带的),实现:线程T扩展于FastThreadLocalAccess,InternalThreadLocalMap是它的成员变量,set()时放入InternalThreadLocalMap的成员变量数组,下标是index,get()时从InternalThreadLocalMap的成员变量数组中下标是index处取。

继续阅读

发表在 编程语言 | 标签为 , , | Comments Off on Netty5源码学习之buffer篇(一):PooledHeapByteBuf

GraphicsMagick使用练习

GraphicsMagick官网地址:http://www.graphicsmagick.org/,介绍不多说网上都有,我这里只使用了它图片缩放功能,用java调用练习。

第一步:下载安装。

我下载的是:GraphicsMagick-1.3.20-Q8-win32-dll.exe,安装目录:C:\Program Files (x86)\GraphicsMagick-1.3.20-Q8。安装完毕后,安装目录自动配置到环境变量的Path中了,安装目录里有gm.exe。测试一下,gm -version,如果打印出GraphicsMagick相关信息则ok。这时就可以在命令行里使用gm命令了。

如果使用java调用报错:Caused by: java.io.IOException: CreateProcess error=2。则表示没有gm命令找不到,也就是说环境变量有可能更改了但是没有生效,我的做法是重启eclipse,运行同样程序就ok。如果还是报错,可能环境变量还是没有生效,重启电脑,又或者是安装目录压根就没有配置到环境变量Path中去,手动配置即可。

第二步:写代码。

继续阅读

发表在 编程语言 | 标签为 , , | Comments Off on GraphicsMagick使用练习

RocketMQ学习(一):简介和QuickStart

RocketMQ是什么?

引用官方描述:
RocketMQ是一款分布式、队列模型的消息中间件,具有以下特点:

支持严格的消息顺序
支持Topic与Queue两种模式
亿级消息堆积能力
比较友好的分布式特性
同时支持Push与Pull方式消费消息
历经多次天猫双十一海量消息考验

RocketMQ是纯java编写,基于通信框架Netty。

代码地址:https://github.com/alibaba/RocketMQ,目前分支是3.2.2 develop。

下载完代码后,将各个模块导入eclipse,本地尝试启动看看。

1.启动nameServer,运行rocketmq-namesrv的NamesrvStartup,运行之前需设置环境变量ROCKETMQ_HOME为RocketMQ项目的根目录,这样有一个作用是,指向logback的配置文件路径,保证在nameServer启动时,logback的正常初始化。我本机设置的是:ROCKETMQ_HOME=C:\Users\Administrator\git\RocketMQ。
The Name Server boot success. 表示启动成功。

2.启动brokerServer,运行rocketmq-broker的BrokerStartup,同样,运行之前需设置环境变量ROCKETMQ_HOME,然后启动参数需要带上【-n “192.168.0.109:9876″】,我本机的ip是192.168.0.109。如果不带-n的参数,那么broker会去访问http://jmenv.tbsite.net:8080/rocketmq/nsaddr获取nameServer的地址,这个地址不是我们自己的nameServer。
The broker[LENOVO-PC, 192.168.0.109:10911] boot success. and name server is 192.168.0.109:9876表示成功。

3.这个非必选项,不运行也可以。还可以启动rocketmq-srvutil的FiltersrvStartup,这是Consumer使用Java代码,在服务器做消息过滤。启动方式和broker一样,具体的过滤原理以后再详细的说。

到此就可以运行demo了。
继续阅读

发表在 编程语言 | 标签为 , | Comments Off on RocketMQ学习(一):简介和QuickStart

log4j几个tips

log4j是很常用的日志框架,这里总结几个小知识点:

1. logger是以名称为key,logger为value的形式存储在Hashtable里,所以,logger作为入参不需要传入引用,直接输入名称get即可。

LogFactoryImpl.java

/**
     * The {@link org.apache.commons.logging.Log} instances that have
     * already been created, keyed by logger name.
     */
    protected Hashtable instances = new Hashtable();

    public Log getInstance(String name) throws LogConfigurationException {

        Log instance = (Log) instances.get(name);
        if (instance == null) {
            instance = newInstance(name);
            instances.put(name, instance);
        }
        return (instance);

    }

2. logger的继承关系是根据名称的“.”分割来区分,表现为子logger打印日志时遍历父logger里的appender的进行日志打印。

Category.java

public
  void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
      // Protected against simultaneous call to addAppender, removeAppender,...
      synchronized(c) {
	if(c.aai != null) {
	  writes += c.aai.appendLoopOnAppenders(event);
	}
	if(!c.additive) {
	  break;
	}
      }
    }

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }

3.定义模块名为常量,按模块名称取logger,解决项目里包名类名相同日志无法区分问题。

贴代码:
示例一

package com.zoo;

import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;


/**
 * 
 * @author yankai913@gmail.com
 * @date 2014年12月22日
 */
public class LogTest {
    static final Log log = LogFactory.getLog(LogTest.class);


    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("log4j.rootLogger", "DEBUG,stdout");
        properties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");
        properties.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout");
        properties.setProperty("log4j.appender.stdout.layout.ConversionPattern",
            "%d [%t] %-5p %C{6} (%F:%L) - %m%n");
        // log4j的继承关系是"."
        // log --> com.zoo.LogTest
        // log2(父log) --> com.zoo
        // log3(父log2) --> com
        // 以此类推
        // 子logger的继承关系表现是,子logger打印日志时,遍历父logger里的appender
        // 进行日志打印,"com.zoo.LogTest"的父子logger分别是:
        // "com.zoo.LogTest"的logger -> "com.zoo"的logger -> "root"的logger。
        // 以下这句话定义了上述的log2(即父log),导致日志打印2次。
        properties.setProperty("log4j.logger.com.zoo", "INFO, stdout");
        // 以下这句话定义com.zoo包的logger(即log2)的appender不被继承,日志打印只有一条。
        properties.setProperty("log4j.additivity.com.zoo", "false");
        PropertyConfigurator.configure(properties);
        System.out.println(log);
        log.info("Hello World!");
        System.out.println("end");
    }
}

示例二

package com.zoo;

import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;


/**
 * 
 * @author yankai913@gmail.com
 * @date 2014年12月22日
 */
public class LogTest2 {
    // 定义公共的logerName,按module分
    static final String Module1_LogName = "Module1";
    static final String Module2_LogName = "Module2";


    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("log4j.rootLogger", "DEBUG,file");
        properties.setProperty("log4j.appender.file", "org.apache.log4j.FileAppender");
        properties.setProperty("log4j.appender.file.layout", "org.apache.log4j.PatternLayout");
        properties.setProperty("log4j.appender.file.layout.ConversionPattern",
            "%d [%t] %-5p %c{1} %C{6} (%F:%L) - %m%n");
        properties.setProperty("log4j.appender.file.append", "true");
        properties.setProperty("log4j.appender.file.file", "logtest2.log");
        PropertyConfigurator.configure(properties);
        // 比较同名称的log,结果为true,所以log作为入参不需要传入引用,直接get即可。
        System.out.println(Module1.log.equals(ServiceImpl_1.log));
        System.out.println(Module2.log.equals(ServiceImpl_2.log));
        // 按模块搜索查看日志,关键词就是模块名称,即上面的Module1,Module2。
        // 解决包名类名完全一样,但是在不同模块的日志查询。
        Module1.println();
        Module2.println();
        ServiceImpl_1.println();
        ServiceImpl_2.println();
        System.out.println("end");
    }

    public static class Module1 {
        public static Log log = LogFactory.getLog(Module1_LogName);


        public static void println() {
            log.info("this is module1");
        }
    }

    public static class Module2 {
        public static Log log = LogFactory.getLog(Module2_LogName);


        public static void println() {
            log.info("this is module2");
        }
    }

    public static class ServiceImpl_1 {
        public static Log log = LogFactory.getLog(Module1_LogName);


        public static void println() {
            log.info("this is service");
        }
    }

    public static class ServiceImpl_2 {
        public static Log log = LogFactory.getLog(Module2_LogName);


        public static void println() {
            log.info("this is service");
        }
    }
}

练习代码看这里

发表在 编程语言 | 标签为 , | Comments Off on log4j几个tips

classloader隔离练习

平时,我们用maven来管理项目的依赖包,可是有时候还是会出现jar包多版本同时存在的问题,这时,我们可以利用classloader的隔离机制来解决。

1.我们自定义classloader,然后设置它为应用的contextClassLoader运行。

2.自定义classLoader加载特定目录的jar包,同时把加载过的Class缓存起来,这时classLoader就起到隔离作用,像一个容器,只装自己的jar包。

3.Class的查找机制,如果自定义classLoader里加载过,取出来直接返回,没有则用父classLoader查找加载。

4.自定义classLoader加载自己指定目录的jar包,父classLoader则加载classpath里的包或者类。

可能说的比较简洁,大家感兴趣还是直接看代码吧。
练习代码看这里

发表在 编程语言 | 标签为 | Comments Off on classloader隔离练习

go语言项目如何引用依赖Github上的开源项目

用go语言写项目时,难免会引用到一些Github上的开源项目,下面说说在开发时如何引用。

系统:windows
Go:1.3.1
开发工具:LiteIDE

比如:

import (
	"bytes"
	"fmt"
	"github.com/yankai913/go-tools/timetool"
	"net"
	"os"
)

当正确引用后,在写“timetool.”时,后面接着会有提示。

步骤:
前提是配好go的环境变量,包括GOROOT和GOPATH。LiteIDE分系统GOPATH和用户自定义GOPATH。

示例要引用的项目地址是:https://github.com/yankai913/go-tools

1. 打开cmd,执行go get github.com/yankai913/go-tools,会把项目源代码下载下来,同时控制台输出 package github.com/yankai913/go-tools等字样以及下载到本地的地址,我的本地地址是C:\Go\bin\src\github.com\yankai913\go-tools。

2. 进入go-tools的timetool包,即执行 cd C:\Go\bin\src\github.com\yankai913\go-tools\timetool,然后,编译,go build,安装,go install。完成后,记得刷新GOPATH,我用的LiteIDE,“package浏览”,“重新加载所有”就行了,此时在编辑器里输入“包名+点”,后面跟着提示信息。

另外,如果你需要go-tools里其他的package,那么你只需要进入相应的包里,执行编译,安装,即可。

发表在 编程语言 | 标签为 | Comments Off on go语言项目如何引用依赖Github上的开源项目

springext练习

最近新做的项目使用了webx,项目做完后,对webx还不是很有感觉,只知道webx是基于springext的,然后上网查了下springext,结果都是照搬webx官网文档里讲springext部分,没有自己的见解和代码,所以就打算自己写个demo练练手。

先贴代码,练习代码看这里

webx官方文档地址,http://www.openwebx.org/。

看图说话:

p1

1.看练习代码之前建议还是先看下webx官方文档里讲的springext部分,了解下概念和装插件。
2.文件《spring.configuration-points》是用来定义扩展点的。里面的内容定义是:“扩展点名称=uri命名空间; nsPrefix=前缀”。注意,扩展点名称推荐用“/”来区分,要唯一。
3.扩展点名称.bean-definition-parsers用来定义捐献文件,里面扩展点名称places/countries这里要转换成places-countries。
4.为捐献定义的schema的路径与扩展点的命名空间相匹配,扩展点是places,捐献是country,那么schema的路径就是“/META-INF/places/country.xsd”。
5.spring.schemas和META-INF/springext/springext-base.xsd可要可不要,因为webx框架已经包含定义。
6.springext和spring完全兼容。
7.schema的编写基础知识了解一点。

感觉大概就是这么多了,主要还是看代码,有兴趣的哥们可以上去看下。

发表在 编程语言 | 标签为 , | Comments Off on springext练习

学习ClassLoader和自定义ClassLoader的使用

这几天在看ClassLoader,推荐一篇讲ClassLoader的文章,地址:http://longdick.iteye.com/blog/442213,然后又看了下《深入java虚拟机》里的ClassLoader章节,下面就随便说点,主要还是以练习代码为主。

1.对于任意一个类,由加载它的ClassLoader和它本身决定了在java虚拟机中的唯一性。
也就是说比较2个类,只有它们都是由同一个ClassLoader加载,那么比较才有意义。否则,即使是同一个类文件,如果加载它们的ClassLoader不同,那么这2个类必定不相等。

2.类加载的双亲委派机制是可以破坏的,通过改变CallClassLoader和ContextClassLoader。
被当前类引用的类的加载也是由加载当前类的ClassLoader加载,子线程的ContextClassLoader是由父线程的ContextClassLoader派生出来。

3.扩展ClassLoader一般应该建议重写findClass(String)方法。
原因是自定义的ClassLoader只专注于加载自己的Class,在加载自己的Class的过程中,又会先加载父类Object,Object类是由启动类加载器加载的,默认可以直接由loadClass(String)执行,这么做可以用ClassLoader来选择性加载某一些类做隔离。

贴代码

自定义ClassLoader,重写loadClass()。

@Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        try {
            String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
            InputStream is = getClass().getResourceAsStream(fileName);
            if (is == null) {
                return super.loadClass(name);
            }
            byte[] b = new byte[is.available()];
            is.read(b);
            return defineClass(name, b, 0, b.length);
        }
        catch (Exception e) {
            throw new ClassNotFoundException(name);
        }
    }

测试类



    public void say() {
        System.out.println("hello world");
    }


    public static void main(String[] args) throws Exception {
        // 打印java虚拟机的ClassLoader
        System.out.println(Thread.currentThread().getContextClassLoader());
        System.out.println(Thread.currentThread().getContextClassLoader().getParent());
        System.out.println(Thread.currentThread().getContextClassLoader().getParent().getParent());
        // 自定义ClassLoader
        ClassLoader myLoader = new MyClassLoader();
        Class<?> clazz = myLoader.loadClass("com.zoo.classloader.ClassLoaderTest");
        Object obj = clazz.newInstance();
        // 打印自定义ClassLoader加载的Class对象
        System.out.println(obj.getClass());
        // 打印被加载的Class对象是由哪个ClassLoader加载的
        System.out.println(obj.getClass().getClassLoader());
        /*
         * 对于任意一个类,由加载它的ClassLoader和它本身决定了在jvm虚拟机中的唯一性。
         * 也就是说比较2个类,只有它们都是由同一个ClassLoader加载,那么比较才有意义。
         * 否则,即使是同一个类文件,只要加载它们的ClassLoader不同,那么这2个类必定不相等。
         */
        System.out.println(obj instanceof com.zoo.classloader.ClassLoaderTest);
        // 由自定义ClassLoader加载后,在程序里运行。
        Method method = clazz.getDeclaredMethod("say", new Class<?>[] {});
        method.invoke(obj, new Object[] {});
        // 获取当前上下文的ClassLoader
        System.out.println(Thread.currentThread().getContextClassLoader());
        // 改变上下文的ClassLoader
        Thread.currentThread().setContextClassLoader(myLoader);
        // 获取当前上下文的ClassLoader
        System.out.println(Thread.currentThread().getContextClassLoader());
        // 改变当前上下文的ClassLoader可以改变在当前线程派生出的子线程的上下文ClassLoader
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t2 = Thread.currentThread();
                System.out.println(t2.getName() + ":" + t2.getContextClassLoader());
            }
        });
        t.start();
        Thread.sleep(3000);
        // 获取CallClassLoader
        Class<?> clz = Class.forName("com.zoo.classloader.ClassLoaderTest");
        System.out.println(clz);
        System.out.println(clz.getClassLoader());
        System.out.println(clz.getClass());
        System.out.println(clz.getClass().getClassLoader());
    }

执行结果:
sun.misc.Launcher$AppClassLoader@addbf1 ==> 当前上下文类加载器是应用类加载器
sun.misc.Launcher$ExtClassLoader@42e816 ==> 应用类加载器的父类加载器是扩展类加载器
null ==> 扩展类加载器的父类加载器是启动类加载器,因为启动类加载器是C++编写,java里获取不到
class com.zoo.classloader.ClassLoaderTest ==> 自定义类加载器加载进行加载
com.zoo.classloader.MyClassLoader@1fb8ee3 ==> 通过Class对象获取它的类加载器
false ==> 同一个Class,不同的类加载器加载,那么Class不相等
hello world ==> 被自定义类加载器加载的Class在程序中执行
sun.misc.Launcher$AppClassLoader@addbf1 ==> 获取当前上下文类加载器
com.zoo.classloader.MyClassLoader@1fb8ee3 ==> 设置上下文类加载器
Thread-0:com.zoo.classloader.MyClassLoader@1fb8ee3 ==> 派生出来的子线程的类加载器
class com.zoo.classloader.ClassLoaderTest ==> 默认加载类
sun.misc.Launcher$AppClassLoader@addbf1 ==> 默认加载用的是应用类加载器
class java.lang.Class ==> 获取Class
null ==> 获取类加载器,由于是启动类加载器,所以为null,java基础类是由启动类加载器加载。

练习代码看这里

发表在 编程语言 | 标签为 | Comments Off on 学习ClassLoader和自定义ClassLoader的使用

记博客重新搭建

近几天博客重新搭建完毕,在此做个时间戳,过程中,我只想说一句话,勤于备份真的是个好习惯。

发表在 生活笔记 | Comments Off on 记博客重新搭建